mirror of https://github.com/arendst/Tasmota.git
IRremoteESP8266 library from v2.7.20 to v2.8.0
This commit is contained in:
parent
97ba91ca58
commit
0cbd6cff4a
|
@ -0,0 +1,3 @@
|
|||
# Directories & files to ignore from release archives
|
||||
docs export-ignore
|
||||
assets export-ignore
|
|
@ -71,7 +71,7 @@ Include details about your configuration, circuit and environment:
|
|||
* Avoid platform-dependent code.
|
||||
* Use c98 types where possible for better portablity.
|
||||
* In almost all cases, code & documentation should be peer-reviewed by at least one other contributor.
|
||||
* The code should pass all the existing testing infrastructure in Travis. e.g. Unit tests, cpplint, and basic compilation.
|
||||
* The code should pass all the existing testing infrastructure in GitHub Actions. e.g. Unit tests, cpplint, and basic compilation etc.
|
||||
* State if you have tested this under real conditions if you have, and what other tests you may have carried out.
|
||||
|
||||
### Git Commit Messages
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
- [Mark Kuchel](https://github.com/kuchel77)
|
||||
- [Christian Nilsson](https://github.com/NiKiZe)
|
||||
- [Zhongxian Li](https://github.com/siriuslzx)
|
||||
- [Davide Depau](https://github.com/Depau)
|
||||
|
||||
All contributors can be found on the [contributors site](https://github.com/crankyoldgit/IRremoteESP8266/graphs/contributors).
|
||||
|
||||
|
|
57
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/ISSUE_TEMPLATE/problem-report.md
vendored
Normal file
57
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/ISSUE_TEMPLATE/problem-report.md
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
---
|
||||
name: Problem report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Version/revision of the library used
|
||||
_Typically located in the `library.json` & `src/IRremoteESP8266.h` files in the root directory of the library.
|
||||
e.g. v2.0.0, or 'master' as at 1st of June, 2017. etc._
|
||||
|
||||
### Describe the bug
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
#### To Reproduce
|
||||
_What steps did you do, and what did or didn't actually happen? How can we reproduce the issue?_
|
||||
|
||||
_e.g._
|
||||
_1. Initialise the IRsend class._
|
||||
_2. `IRsend.sendFoobar(0xdeadbeef);`_
|
||||
_3. Foobar BBQ went into Cow(er)-saving mode and fried me a couple of eggs instead._
|
||||
|
||||
#### Example code used
|
||||
_Include all relevant code snippets or links to the actual code files. Tip: [How to quote your code so it is still readable in the report](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)._
|
||||
|
||||
#### Expected behaviour
|
||||
_What steps did you do and what should it have done? A clear and concise description of what you expected to happen._
|
||||
|
||||
_e.g._
|
||||
_1. Initialise the IRsend class._
|
||||
_2. `IRsend.sendFoobar(0xdeadbeef);`_
|
||||
_3. Foobar branded BBQ turns on and cooks me some ribs._
|
||||
|
||||
#### Output of raw data from [IRrecvDumpV2.ino](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/IRrecvDumpV2/IRrecvDumpV2.ino) or [V3](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/IRrecvDumpV3/) (if applicable)
|
||||
_Include some serial text of the raw dumps of what the device saw._
|
||||
|
||||
_**Note**: Output from Tasmota is not acceptable. We can't easily use their raw format._
|
||||
|
||||
|
||||
### What brand/model IR demodulator are you using?
|
||||
_Brand/Model code_ or _None_
|
||||
|
||||
_If VS1838b: That is likely your problem. Please buy a better one & try again. Reporting a capture or decode issue when you use one of these is effectively wasting our & your time. See the [FAQ](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions#Help_Im_getting_very_inconsistent_results_when_capturing_an_IR_message_using_a_VS1838b_IR_demodulator)_
|
||||
|
||||
### Circuit diagram and hardware used (if applicable)
|
||||
_Link to an image of the circuit diagram used. Part number of the IR receiver module etc. ESP8266 or ESP32 board type._
|
||||
|
||||
### I have followed the steps in the [Troubleshooting Guide](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Troubleshooting-Guide) & read the [FAQ](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions)
|
||||
_Yes/No._
|
||||
|
||||
### Has this library/code previously worked as expected for you?
|
||||
_Yes/No. If "Yes", which version last worked for you?_
|
||||
|
||||
### Other useful information
|
||||
_More information is always welcome. Be verbose._
|
|
@ -1,47 +0,0 @@
|
|||
_(Please use this template for reporting issues. You can delete what ever is not relevant. Giving us this information will help us help you faster. Please also read the [FAQ](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions) & [Troubleshooting Guide](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Troubleshooting-Guide). Your problem may already have an answer there.)_
|
||||
|
||||
### Version/revision of the library used
|
||||
_Typically located in the `library.json` & `src/IRremoteESP8266.h` files in the root directory of the library.
|
||||
e.g. v2.0.0, or 'master' as at 1st of June, 2017. etc._
|
||||
|
||||
### Expected behavior
|
||||
_What steps did you do and what should it have done?_
|
||||
|
||||
e.g.
|
||||
1. Initialise the IRsend class.
|
||||
2. IRsend.sendFoobar(0xdeadbeef);
|
||||
3. Foobar branded BBQ turns on and cooks me some ribs.
|
||||
|
||||
### Actual behavior
|
||||
_What steps did you do, and what did or didn't actually happen?_
|
||||
|
||||
e.g.
|
||||
1. Initialise the IRsend class.
|
||||
2. IRsend.sendFoobar(0xdeadbeef);
|
||||
3. Foobar BBQ went into Cow(er)-saving mode and fried me a couple of eggs instead.
|
||||
|
||||
#### Output of raw data from IRrecvDumpV2.ino (if applicable)
|
||||
_Include some raw dumps of what the device saw._
|
||||
|
||||
### What brand/model IR demodulator are you using?
|
||||
_Brand/Model code_ or _None_
|
||||
|
||||
_If VS1838b: That is likely your problem. Please buy a better one & try again. Reporting a capture or decode issue when you use one of these is effectively wasting our & your time. See the [FAQ](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions#Help_Im_getting_very_inconsistent_results_when_capturing_an_IR_message_using_a_VS1838b_IR_demodulator)_
|
||||
|
||||
### Steps to reproduce the behavior
|
||||
_What can we do to (pref. reliably) repeat what is happening?_
|
||||
|
||||
#### Example code used
|
||||
_Include all relevant code snippets or links to the actual code files. Tip: [How to quote your code so it is still readable](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code)._
|
||||
|
||||
#### Circuit diagram and hardware used (if applicable)
|
||||
_Link to an image of the circuit diagram used. Part number of the IR receiver module etc. ESP8266 or ESP32 board type._
|
||||
|
||||
### I have followed the steps in the [Troubleshooting Guide](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Troubleshooting-Guide) & read the [FAQ](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions)
|
||||
_Yes/No._
|
||||
|
||||
### Has this library/code previously worked as expected for you?
|
||||
_Yes/No. If "Yes", which version last worked for you?_
|
||||
|
||||
### Other useful information
|
||||
_More information is always welcome. Be verbose._
|
|
@ -0,0 +1,37 @@
|
|||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
Build_Examples:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
- name: Cache PlatformIO
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.platformio
|
||||
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
- 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
|
||||
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
|
15
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Documentation.yml
vendored
Normal file
15
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/Documentation.yml
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
# This is a basic workflow that is triggered on push/PRs to the master branch.
|
||||
|
||||
name: Documentation
|
||||
|
||||
# Controls when the action will run. Workflow runs when manually triggered using the UI
|
||||
# or API.
|
||||
on: [push, pull_request]
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
Doxygen:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: mattnotmitt/doxygen-action@v1
|
|
@ -0,0 +1,28 @@
|
|||
name: Code Lint
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
Linters:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pylint
|
||||
pip install cpplint
|
||||
- name: Analysing the code with pylint
|
||||
run: |
|
||||
shopt -s nullglob
|
||||
pylint -d F0001 {src,test,tools}/*.py
|
||||
- name: Analysing the code with cpplint
|
||||
run: |
|
||||
shopt -s nullglob
|
||||
cpplint --extensions=c,cc,cpp,ino --headers=h,hpp {src,src/locale,test,tools}/*.{h,c,cc,cpp,hpp,ino} examples/*/*.{h,c,cc,cpp,hpp,ino}
|
54
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/MetaChecks.yml
vendored
Normal file
54
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/MetaChecks.yml
vendored
Normal file
|
@ -0,0 +1,54 @@
|
|||
# This is a basic workflow that is triggered on push/PRs to the master branch.
|
||||
|
||||
name: Library Linter
|
||||
|
||||
# Controls when the action will run. Workflow runs when manually triggered using the UI
|
||||
# or API.
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
arduino-library-manager-lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: arduino/arduino-lint-action@v1
|
||||
with:
|
||||
library-manager: update
|
||||
compliance: strict
|
||||
# Detect case-insensitive file duplication in the same directory.
|
||||
# This can cause a problem for the Arduino IDE on Windows & Macs.
|
||||
# See:
|
||||
# - https://github.com/arduino/Arduino/issues/11441
|
||||
# - https://github.com/crankyoldgit/IRremoteESP8266/issues/1451
|
||||
detect-duplicate-files:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Look for case-insensitive filename collisions.
|
||||
run: DUPS=$(find . -path '*/.pio' -prune -o -print | sort | uniq -D -i); if [[ -n "${DUPS}" ]]; then echo -e "Duplicates found:\n${DUPS}"; false; fi
|
||||
version-number-consitent:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- 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)
|
||||
test ${LIB_VERSION} == "$(jq -r .version library.json)"
|
||||
grep -q "^version=${LIB_VERSION}$" library.properties
|
||||
examples-have-platformio_ini:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check that every example directory has a platformio.ini file.
|
||||
run: (status=0; for dir in examples/*; do if [[ ! -f "${dir}/platformio.ini" ]]; then echo "${dir} has no 'platform.ini' file!"; status=1; fi; done; exit ${status})
|
||||
supported-devices-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check that all files have supported sections.
|
||||
run: (SUPPORTED_OUTPUT=$(python3 tools/scrape_supported_devices.py --noout --alert 2>&1); if [[ $? -ne 0 || -n "${SUPPORTED_OUTPUT}" ]]; then echo "${SUPPORTED_OUTPUT}"; exit 1; fi)
|
23
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/UnitTests.yml
vendored
Normal file
23
lib/lib_basic/IRremoteESP8266/IRremoteESP8266/.github/workflows/UnitTests.yml
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
Unit_Tests:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
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"
|
||||
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)
|
|
@ -22,7 +22,7 @@ examples/**/lib
|
|||
examples/**/.travis.yml
|
||||
examples/**/.gitignore
|
||||
lib/readme.txt
|
||||
lib/googletest/**/*
|
||||
lib/googletest/
|
||||
|
||||
# GCC pre-compiled headers.
|
||||
**/*.gch
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[submodule "lib/googletest"]
|
||||
path = lib/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
branch = v1.8.x
|
|
@ -1,69 +0,0 @@
|
|||
language: c
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- jq
|
||||
- doxygen
|
||||
- graphviz
|
||||
- python3
|
||||
- python3-pip
|
||||
- pylint3
|
||||
- python3-setuptools
|
||||
env:
|
||||
- PLATFORMIO_BUILD_CACHE_DIR="../../.pio/buildcache"
|
||||
IRRECVDUMP_RE=".*IRrecvDumpV.*"
|
||||
IRMQTTSERVER_RE=".*IRMQTTServer.*"
|
||||
MAKEFLAGS="-j 2"
|
||||
cache:
|
||||
directories:
|
||||
- "~/.platformio"
|
||||
before_install:
|
||||
- wget https://raw.githubusercontent.com/google/styleguide/gh-pages/cpplint/cpplint.py
|
||||
- python --version && pip --version
|
||||
- python3 --version && pip3 --version
|
||||
- sudo pip3 install -U platformio
|
||||
- pio update
|
||||
script: echo Running checks
|
||||
notifications:
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: change
|
||||
jobs:
|
||||
include:
|
||||
- name: "Compile the trivial examples"
|
||||
script:
|
||||
# Check that everything compiles but some heavy tasks e.g. IRMQTTServer & IRrecvDumpV2+
|
||||
# i.e. We are splitting the work load in to parallel tasks.
|
||||
- find . -regextype egrep -name platformio.ini -type f \! -regex "${IRRECVDUMP_RE}|${IRMQTTSERVER_RE}" | sed 's,/platformio.ini$,,' | xargs --verbose -n 1 pio run --jobs 2 --project-dir
|
||||
- name: "Compile the IRrecvDumpV2+ examples"
|
||||
script:
|
||||
# Check that IRrecvDumpV2+ compiles.
|
||||
# i.e. We are splitting the work load in to parallel tasks.
|
||||
- find . -regextype egrep -name platformio.ini -type f -regex "${IRRECVDUMP_RE}" | sed 's,/platformio.ini$,,' | xargs --verbose -n 1 pio run --jobs 2 --project-dir
|
||||
- name: "Unit tests, Linter, Doc checks, & Compile IRMQTTServer"
|
||||
script:
|
||||
# Run all the Tests & check the code linters have no issues, and that
|
||||
# IRMQTTServer compiles.
|
||||
# i.e. We are splitting the work load in to parallel tasks.
|
||||
# Check the version numbers match.
|
||||
- LIB_VERSION=$(egrep "^#define\s+_IRREMOTEESP8266_VERSION_\s+" src/IRremoteESP8266.h | cut -d\" -f2)
|
||||
- test ${LIB_VERSION} == "$(jq -r .version library.json)"
|
||||
- grep -q "^version=${LIB_VERSION}$" library.properties
|
||||
# Check the tools programs compile.
|
||||
- (cd tools; make all)
|
||||
# Check for lint issues.
|
||||
- shopt -s nullglob
|
||||
- python cpplint.py --extensions=c,cc,cpp,ino --headers=h,hpp {src,src/locale,test,tools}/*.{h,c,cc,cpp,hpp,ino} examples/*/*.{h,c,cc,cpp,hpp,ino}
|
||||
- pylint3 -d F0001 {src,test,tools}/*.py
|
||||
- shopt -u nullglob
|
||||
# Build and run the unit tests.
|
||||
- (cd test; make run)
|
||||
- (cd tools; make run_tests)
|
||||
# Check that every example directory has a platformio.ini file.
|
||||
- (status=0; for dir in examples/*; do if [[ ! -f "${dir}/platformio.ini" ]]; then echo "${dir} has no 'platform.ini' file!"; status=1; fi; done; exit ${status})
|
||||
# Check that doxygen completes without errors or warnings.
|
||||
- (DOXYGEN_OUTPUT=$(doxygen 2>&1); if [[ $? -ne 0 || -n "${DOXYGEN_OUTPUT}" ]]; then echo "${DOXYGEN_OUTPUT}"; exit 1; fi)
|
||||
# Check that all files has supported sections.
|
||||
- (SUPPORTED_OUTPUT=$(python3 tools/scrape_supported_devices.py --noout --alert 2>&1); if [[ $? -ne 0 || -n "${SUPPORTED_OUTPUT}" ]]; then echo "${SUPPORTED_OUTPUT}"; exit 1; fi)
|
||||
# Check that IRMQTTServer compiles.
|
||||
- find . -regextype egrep -name platformio.ini -type f -regex "${IRMQTTSERVER_RE}" | sed 's,/platformio.ini$,,' | xargs --verbose -n 1 pio run --jobs 2 --project-dir
|
|
@ -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.7.20 Now Available
|
||||
Version 2.7.20 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.0 Now Available
|
||||
Version 2.8.0 of the library is now [available](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes.
|
||||
|
||||
#### 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.
|
||||
|
|
|
@ -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.7.20 jetzt verfügbar
|
||||
Version 2.7.20 der Bibliothek ist nun [verfügbar](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Die [Versionshinweise](ReleaseNotes.md) enthalten alle wichtigen Neuerungen.
|
||||
## v2.8.0 jetzt verfügbar
|
||||
Version 2.8.0 der Bibliothek ist nun [verfügbar](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Die [Versionshinweise](ReleaseNotes.md) enthalten alle wichtigen Neuerungen.
|
||||
|
||||
#### 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.
|
||||
|
|
|
@ -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.7.20 disponible
|
||||
Version 2.7.20 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.0 disponible
|
||||
Version 2.8.0 de la libraire est maintenant [disponible](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Vous pouvez voir le [Release Notes](ReleaseNotes.md) pour tous les changements importants.
|
||||
|
||||
#### 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.
|
||||
|
|
|
@ -1,5 +1,73 @@
|
|||
# Release Notes
|
||||
|
||||
## _v2.8.0 (20211119)_
|
||||
|
||||
**[Bug Fixes]**
|
||||
- Fix compilation issue when using old 8266 Arduino Frameworks. (#1639 #1640)
|
||||
- Fix potential security issue with `scrape_supported_devices.py` (#1616 #1619)
|
||||
|
||||
**[Features]**
|
||||
- SAMSUNG_AC
|
||||
- Change `clean` setting to a toggle. (#1676 #1677)
|
||||
- Highest fan speed is available without Powerful setting. (#1675 #1678)
|
||||
- Change `beep` setting to a toggle. (#1669 #1671)
|
||||
- Fix Beep for AR12TXEAAWKNEU (#1668 #1669)
|
||||
- Add support for Horizontal Swing & Econo (#1277 #1667)
|
||||
- Add support for On, Off, & Sleep Timers (#1277 #1662)
|
||||
- Fix power control. Clean-up code & bitmaps from Checksum changes. (#1277 #1648 #1650)
|
||||
- HAIER_AC176/HAIER_AC_YRW02
|
||||
- Add support A/B unit setting (#1672)
|
||||
- Add support degree Fahrenheit (#1659)
|
||||
- Add support `Lock` function (#1652)
|
||||
- Implement horizontal swing feature (#1641)
|
||||
- Implement Quiet setting. (#1634 #1635)
|
||||
- Basic support for Airton Protocol (#1670 #1681)
|
||||
- HAIER_AC176: Add Turbo and Quiet settings (#1634)
|
||||
- Gree: Add `SwingH` & `Econo` control. (#1587 #1653)
|
||||
- MIRAGE
|
||||
- Add experimental detailed support. (#1573 #1615)
|
||||
- Experimental detailed support for KKG29A-C1 remote. (#1573 #1660)
|
||||
- ELECTRA_AC: Add support for "IFeel" & Sensor settings. (#1644 #1645)
|
||||
- Add Russian translation (#1649)
|
||||
- Add Swedish translation (#1627)
|
||||
- Reduce flash space used. (#1633)
|
||||
- Strings finally in Flash! (#1493 #1614 #1623)
|
||||
- Add support for Rhoss Idrowall MPCV 20-30-35-40 A/C protocol (#1630)
|
||||
- Make `IRAc::opmodeToString()` output nicer for humans. (#1613)
|
||||
- TCL112AC/TEKNOPOINT: Add support for `GZ055BE1` model (#1486 #1602)
|
||||
- Support for Arris protocol. (#1598)
|
||||
- SharpAc: Allow position control of SwingV (#1590 #1594)
|
||||
|
||||
**[Misc]**
|
||||
- HAIER_AC176/HAIER_AC_YRW02
|
||||
- Replace some magic numbers with constants (#1679)
|
||||
- Small fix `Quiet` and `Turbo` test (#1674)
|
||||
- Fix `IRHaierAC176::getTemp()` return value description (#1663)
|
||||
- Security Policy creation and changes. (#1616 #1617 #1618 #1621 #1680)
|
||||
- IRrecvDumpV2/3: Update PlatformIO envs for missing languages (#1661)
|
||||
- IRMQTTServer
|
||||
- Use the correct string for Fan mode in Home Assistant. (#1610 #1657)
|
||||
- Move a lot of the strings/text to flash. (#1638)
|
||||
- Minor code style improvements. (#1656)
|
||||
- Update Supported Devices
|
||||
- HAIER_AC176 (#1673)
|
||||
- LG A/C (#1651 #1655)
|
||||
- Symphony (#1603 #1605)
|
||||
- Epson (#1574 #1601)
|
||||
- GREE (#1587 #1588)
|
||||
- SharpAc (#1590 #1591)
|
||||
- Add extra tests for LG2 protocol (#1654)
|
||||
- Fix parameter expansion in several macros.
|
||||
- Move some strings to `IRtext.cpp` & `locale/default.h` (#1637)
|
||||
- RHOSS: Move include and defines to their correct places (#1636)
|
||||
- Make makefile only build required files when running `run-%` target (#1632)
|
||||
- Update Portuguese translation (#1628)
|
||||
- Add possibility to run specific test case (#1625)
|
||||
- Change `googletest` library ignore (#1626)
|
||||
- Re-work "Fan Only" strings & matching. (#1610)
|
||||
- Address `C0209` pylint warnings. (#1608)
|
||||
|
||||
|
||||
## _v2.7.20 (20210828)_
|
||||
|
||||
**[Bug Fixes]**
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Security Policy
|
||||
|
||||
You can find this library's <a href="https://crankyoldgit.github.io/IRremoteESP8266/SECURITY">Security Policy</a> and contact procedure at https://crankyoldgit.github.io/IRremoteESP8266/SECURITY
|
|
@ -1,14 +1,16 @@
|
|||
<!--- WARNING: Do NOT edit this file directly.
|
||||
It is generated by './tools/scrape_supported_devices.py'.
|
||||
Last generated: Sat 28 Aug 2021 07:53:10 +0000 --->
|
||||
Last generated: Fri 19 Nov 2021 00:35:37 +0000 --->
|
||||
# IR Protocols supported by this library
|
||||
|
||||
| Protocol | Brand | Model | A/C Model | Detailed A/C Support |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| [Airton](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Airton.cpp) | **Airton** | RD1A1 remote<BR>SMVH09B-2A2A3NH ref. 409730 A/C | | - |
|
||||
| [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 |
|
||||
| [Arris](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Arris.cpp) | **Arris** | 120A V1.0 A18 remote<BR>VIP1113M Set-top box | | - |
|
||||
| [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/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 |
|
||||
| [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 |
|
||||
|
@ -26,11 +28,13 @@
|
|||
| [Doshisha](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Doshisha.cpp) | **Doshisha** | CZ-S32D LED Light<BR>CZ-S38D LED Light<BR>CZ-S50D LED Light<BR>RCZ01 remote | | - |
|
||||
| [Ecoclim](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Ecoclim.cpp) | **[EcoClim](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Ecoclim.h)** | HYSFR-P348 remote<BR>ZC200DPO A/C | | Yes |
|
||||
| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[AUX](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | KFR-35GW/BpNFW=3 A/C<BR>YKR-T/011 remote | | Yes |
|
||||
| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[Centek](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | SCT-65Q09 A/C<BR>YKR-P/002E remote | | Yes |
|
||||
| [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[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) | **[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 | | - |
|
||||
| [EliteScreens](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_EliteScreens.cpp) | **Lumene Screens** | Embassy | | - |
|
||||
| [Epson](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Epson.cpp) | **Epson** | EN-TW9100W Projector | | - |
|
||||
| [Epson](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Epson.cpp) | **Epson** | EN-TW9100W Projector<BR>EX3220 Projector<BR>EX5220 Projector<BR>EX5230 Projector<BR>EX6220 Projector<BR>EX7220 Projector<BR>VS230 Projector<BR>VS330 Projector | | - |
|
||||
| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AGTV14LAC A/C (ARRAH2E)<BR>AR-DB1 remote (ARDB1)<BR>AR-DL10 remote (ARDB1)<BR>AR-RAC1E remote (ARRAH2E)<BR>AR-RAE1E remote (ARRAH2E)<BR>AR-RAH1U remote (ARREB1E)<BR>AR-RAH2E remote (ARRAH2E)<BR>AR-REB1E remote (ARREB1E)<BR>AR-REW4E remote (ARREW4E)<BR>AR-RY4 remote (ARRY4)<BR>AST9RSGCW A/C (ARDB1)<BR>ASTB09LBC A/C (ARRY4)<BR>ASU12RLF A/C (ARREB1E)<BR>ASU30C1 A/C (ARDB1)<BR>ASYG09KETA-B A/C (ARREW4E)<BR>ASYG30LFCA A/C (ARRAH2E)<BR>ASYG7LMCA A/C (ARREB1E) | ARDB1<BR>ARJW2<BR>ARRAH2E<BR>ARREB1E<BR>ARREW4E<BR>ARRY4 | Yes |
|
||||
| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu General](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AOHG09LLC A/C (ARRAH2E)<BR>AR-JW2 remote (ARJW2)<BR>AR-RCE1E remote (ARRAH2E)<BR>ASHG09LLCA A/C (ARRAH2E) | ARDB1<BR>ARJW2<BR>ARRAH2E<BR>ARREB1E<BR>ARREW4E<BR>ARRY4 | Yes |
|
||||
| [GICable](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GICable.cpp) | **G.I. Cable** | XRC-200 remote | | - |
|
||||
|
@ -39,11 +43,13 @@
|
|||
| [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 | 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 | 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 | Yes |
|
||||
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YAA1FBF remote<BR>YB1F2F remote | YAW1F<BR>YBOFB | Yes |
|
||||
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | VIR09HP115V1AH A/C<BR>VIR12HP230V1AH A/C<BR>YAA1FBF remote<BR>YAN1F1 remote<BR>YB1F2F remote | YAW1F<BR>YBOFB | Yes |
|
||||
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YBOFB remote<BR>YBOFB2 remote | YAW1F<BR>YBOFB | Yes |
|
||||
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[RusClimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | EACS/I-09HAR_X/N3 A/C<BR>YAW1F remote | YAW1F<BR>YBOFB | Yes |
|
||||
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Ultimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | Heat Pump | YAW1F<BR>YBOFB | Yes |
|
||||
| [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | HSU-09HMC203 A/C (HAIER_AC_YRW02)<BR>HSU07-HEA03 remote (HAIER_AC)<BR>YR-W02 remote (HAIER_AC_YRW02) | | Yes |
|
||||
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Vailland](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | VAI5-035WNI A/C<BR>YACIFB remote | YAW1F<BR>YBOFB | Yes |
|
||||
| [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Daichi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | D-H A/C (HAIER_AC176) | | Yes |
|
||||
| [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | HSU-09HMC203 A/C (HAIER_AC_YRW02)<BR>HSU07-HEA03 remote (HAIER_AC)<BR>V9014557 M47 8D remote (HAIER_AC176)<BR>YR-W02 remote (HAIER_AC_YRW02) | | Yes |
|
||||
| [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Mabe](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | MMI18HDBWCA6MI8 A/C (HAIER_AC176)<BR>V12843 HJ200223 remote (HAIER_AC176) | | Yes |
|
||||
| [Hitachi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.cpp) | **[Hitachi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.h)** | KAZE-312KSDP A/C (HITACHI_AC1)<BR>LT0541-HTA remote (HITACHI_AC1)<BR>PC-LH3B (HITACHI_AC3)<BR>R-LT0541-HTA/Y.K.1.1-1 V2.3 remote (HITACHI_AC1)<BR>RAR-8P2 remote (HITACHI_AC424)<BR>RAS-22NK A/C (HITACHI_AC344)<BR>RAS-35THA6 remote<BR>RAS-AJ25H A/C (HITACHI_AC424)<BR>RF11T1 remote (HITACHI_AC344)<BR>Series VI A/C (Circa 2007) (HITACHI_AC1) | | Yes |
|
||||
| [Inax](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Inax.cpp) | **Lixil** | Inax DT-BA283 Toilet | | - |
|
||||
|
@ -53,7 +59,7 @@
|
|||
| [Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.h)** | KSV26CRC A/C<BR>KSV26HRC A/C<BR>KSV35CRC A/C<BR>KSV35HRC A/C<BR>KSV53HRC A/C<BR>KSV62HRC A/C<BR>KSV70CRC A/C<BR>KSV70HRC A/C<BR>KSV80HRC A/C<BR>YALIF Remote | | Yes |
|
||||
| [Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.h)** | A5VEY A/C<BR>YB1FA remote | | Yes |
|
||||
| [LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[General Electric](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711AR2853M A/C Remote (LG)<BR>AG1BH09AW101 Split A/C (LG) | | Yes |
|
||||
| [LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711A20083V remote (LG)<BR>A4UW30GFA2 A/C (LG2 - AKB74955603 & AKB73757604)<BR>AKB73757604 remote (LG2 - AKB73757604)<BR>AKB74395308 remote (LG2)<BR>AKB74955603 remote (LG2 - AKB74955603)<BR>AKB75215403 remote (LG2)<BR>AMNW09GSJA0 A/C (LG2 - AKB74955603)<BR>AMNW24GTPA1 A/C (LG2 - AKB73757604)<BR>S4-W12JA3AA A/C (LG2) | | Yes |
|
||||
| [LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711A20083V remote (LG)<BR>A4UW30GFA2 A/C (LG2 - AKB74955603 & AKB73757604)<BR>AKB73315611 remote (LG2 - AKB74955603)<BR>AKB73757604 remote (LG2 - AKB73757604)<BR>AKB74395308 remote (LG2)<BR>AKB74955603 remote (LG2 - AKB74955603)<BR>AKB75215403 remote (LG2)<BR>AMNW09GSJA0 A/C (LG2 - AKB74955603)<BR>AMNW24GTPA1 A/C (LG2 - AKB73757604)<BR>MS05SQ NW0 A/C (LG2 - AKB74955603)<BR>S4-W12JA3AA A/C (LG2) | | Yes |
|
||||
| [Lasertag](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Lasertag.cpp) | **Lasertag** | Phaser emitters | | - |
|
||||
| [Lego](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Lego.cpp) | **LEGO Power Functions** | IR Receiver | | - |
|
||||
| [Lutron](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Lutron.cpp) | **Lutron** | MIR-ITFS remote<BR>MIR-ITFS-F remote<BR>MIR-ITFS-LF remote<BR>SP-HT remote | | - |
|
||||
|
@ -69,7 +75,9 @@
|
|||
| [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Pioneer System](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG66B6(B)/BGEFU1 remote (MIDEA)<BR>RUBO18GMFILCAD A/C (18K BTU) (MIDEA)<BR>RYBO12GMFILCAD A/C (12K BTU) (MIDEA)<BR>UB018GMFILCFHD A/C (12K BTU) (MIDEA)<BR>WS012GMFI22HLD A/C (12K BTU) (MIDEA)<BR>WS018GMFI22HLD A/C (12K BTU) (MIDEA) | | Yes |
|
||||
| [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Trotec](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG57H(B)/BGE remote (MIDEA)<BR>TROTEC PAC 3900 X (MIDEA) | | Yes |
|
||||
| [MilesTag2](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MilesTag2.cpp) | **Milestag2** | Various | | - |
|
||||
| [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **Mirage** | VLU series A/C | | - |
|
||||
| [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **[Maxell](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.h)** | KKG9A-C1 remote<BR>MX-CH18CF A/C | KKG29AC1<BR>KKG9AC1 | Yes |
|
||||
| [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **[Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.h)** | VLU series A/C | KKG29AC1<BR>KKG9AC1 | Yes |
|
||||
| [Mirage](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.cpp) | **[Tronitechnik](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mirage.h)** | KKG29A-C1 remote<BR>Reykir 9000 A/C | KKG29AC1<BR>KKG9AC1 | Yes |
|
||||
| [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-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/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 |
|
||||
|
@ -87,18 +95,21 @@
|
|||
| [Pronto](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Pronto.cpp) | **Pronto** | Pronto Hex | | - |
|
||||
| [RC5_RC6](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_RC5_RC6.cpp) | **Philips** | RC-5X (RC5X)<BR>Standard RC-5 (RC5)<BR>Standard RC-6 (RC6) | | - |
|
||||
| [RCMM](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_RCMM.cpp) | **Microsoft** | XBOX 360 | | - |
|
||||
| [Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.cpp) | **[Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.h)** | AH59-02692E Soundbar remote (SAMSUNG36)<BR>AK59-00167A Bluray remote (SAMSUNG36)<BR>AR09FSSDAWKNFA A/C (SAMSUNG_AC)<BR>AR09HSFSBWKN A/C (SAMSUNG_AC)<BR>AR12HSSDBWKNEU A/C (SAMSUNG_AC)<BR>AR12KSFPEWQNET A/C (SAMSUNG_AC)<BR>AR12NXCXAWKXEU A/C (SAMSUNG_AC)<BR>BN59-01178B TV remote (SAMSUNG)<BR>DB63-03556X003 remote<BR>DB93-14195A remote (SAMSUNG_AC)<BR>DB93-16761C remote<BR>HW-J551 Soundbar (SAMSUNG36)<BR>IEC-R03 remote<BR>UA55H6300 TV (SAMSUNG) | | Yes |
|
||||
| [Rhoss](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Rhoss.cpp) | **[Rhoss](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Rhoss.h)** | Idrowall MPCV 20-30-35-40 | | Yes |
|
||||
| [Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.cpp) | **[Samsung](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.h)** | AH59-02692E Soundbar remote (SAMSUNG36)<BR>AK59-00167A Bluray remote (SAMSUNG36)<BR>AR09FSSDAWKNFA A/C (SAMSUNG_AC)<BR>AR09HSFSBWKN A/C (SAMSUNG_AC)<BR>AR12HSSDBWKNEU A/C (SAMSUNG_AC)<BR>AR12KSFPEWQNET A/C (SAMSUNG_AC)<BR>AR12NXCXAWKXEU A/C (SAMSUNG_AC)<BR>AR12TXEAAWKNEU A/C (SAMSUNG_AC)<BR>BN59-01178B TV remote (SAMSUNG)<BR>DB63-03556X003 remote<BR>DB93-14195A remote (SAMSUNG_AC)<BR>DB93-16761C remote<BR>DB96-24901C remote (SAMSUNG_AC)<BR>HW-J551 Soundbar (SAMSUNG36)<BR>IEC-R03 remote<BR>UA55H6300 TV (SAMSUNG) | | Yes |
|
||||
| [Sanyo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sanyo.cpp) | **[Sanyo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sanyo.h)** | LC7461 transmitter IC (SANYO_LC7461)<BR>RCS-2HS4E remote (SANYO_AC)<BR>RCS-2S4E remote (SANYO_AC)<BR>SA 8650B - disabled<BR>SAP-K121AHA A/C (SANYO_AC)<BR>SAP-K242AH A/C (SANYO_AC) | | Yes |
|
||||
| [Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.cpp) | **[Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.h)** | AH-A12REVP-1 A/C (A903)<BR>AH-AxSAY A/C (A907)<BR>AH-PR13-GL A/C (A903)<BR>AH-XP10NRY A/C (A903)<BR>AY-ZP40KR A/C (A907)<BR>CRMC-820 JBEZ remote (A903)<BR>CRMC-A705 JBEZ remote (A705)<BR>CRMC-A863 JBEZ remote (A903)<BR>CRMC-A903JBEZ remote (A903)<BR>CRMC-A907 JBEZ remote (A907)<BR>LC-52D62U TV | A705<BR>A903<BR>A907 | Yes |
|
||||
| [Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.cpp) | **[Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.h)** | AH-A12REVP-1 A/C (A903)<BR>AH-AxSAY A/C (A907)<BR>AH-PR13-GL A/C (A903)<BR>AH-XP10NRY A/C (A903)<BR>AY-ZP40KR A/C (A907)<BR>CRMC-820 JBEZ remote (A903)<BR>CRMC-A705 JBEZ remote (A705)<BR>CRMC-A863 JBEZ remote (A903)<BR>CRMC-A903JBEZ remote (A903)<BR>CRMC-A907 JBEZ remote (A907)<BR>CRMC-A950 JBEZ (A907)<BR>LC-52D62U TV | A705<BR>A903<BR>A907 | Yes |
|
||||
| [Sherwood](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sherwood.cpp) | **Sherwood** | RC-138 remote<BR>RD6505(B) Receiver | | - |
|
||||
| [Sony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sony.cpp) | **Sony** | HT-CT380 Soundbar (Uses 38kHz & 3 repeats) | | - |
|
||||
| [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Blyss** | Owen-SW-5 3 Fan<BR>WP-YK8 090218 remote | | - |
|
||||
| [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **SamHop** | SM3015 Fan Remote Control<BR>SM5021 Encoder chip<BR>SM5032 Decoder chip | | - |
|
||||
| [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Satellite Electronic** | ID6 Remote<BR>JY199I Fan driver<BR>JY199I-L Fan driver | | - |
|
||||
| [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **SilverCrest** | SSVS 85 A1 Fan | | - |
|
||||
| [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Symphony** | Air Cooler 3Di | | - |
|
||||
| [Symphony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Symphony.cpp) | **Westinghouse** | 78095 Remote<BR>Ceiling fan | | - |
|
||||
| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[Leberg](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | LBS-TOR07 A/C | | Yes |
|
||||
| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[TCL](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | TAC-09CHSD/XA31I A/C | | Yes |
|
||||
| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[Leberg](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | LBS-TOR07 A/C (TAC09CHSD) | GZ055BE1<BR>TAC09CHSD | Yes |
|
||||
| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[TCL](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | TAC-09CHSD/XA31I A/C (TAC09CHSD) | GZ055BE1<BR>TAC09CHSD | Yes |
|
||||
| [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[Teknopoint](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | Allegro SSA-09H A/C (GZ055BE1)<BR>GZ-055B-E1 remote (GZ055BE1) | GZ055BE1<BR>TAC09CHSD | Yes |
|
||||
| [Technibel](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Technibel.cpp) | **[Technibel](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Technibel.h)** | IRO PLUS | | Yes |
|
||||
| [Teco](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Teco.cpp) | **[Alaska](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Teco.h)** | SAC9010QC A/C<BR>SAC9010QC remote | | Yes |
|
||||
| [Teknopoint](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Teknopoint.cpp) | **Teknopoint** | Allegro SSA-09H A/C<BR>GZ-055B-E1 remote | | - |
|
||||
|
@ -127,10 +138,12 @@
|
|||
|
||||
## Send & decodable protocols:
|
||||
|
||||
- AIRTON
|
||||
- AIRWELL
|
||||
- AIWA_RC_T501
|
||||
- AMCOR
|
||||
- ARGO
|
||||
- ARRIS
|
||||
- BOSE
|
||||
- CARRIER_AC
|
||||
- CARRIER_AC40
|
||||
|
@ -202,6 +215,7 @@
|
|||
- RC5X
|
||||
- RC6
|
||||
- RCMM
|
||||
- RHOSS
|
||||
- SAMSUNG
|
||||
- SAMSUNG36
|
||||
- SAMSUNG_AC
|
||||
|
|
|
@ -261,8 +261,8 @@ const uint16_t kMinUnknownSize = 2 * 10;
|
|||
#define KEY_RX_GPIO "rx"
|
||||
|
||||
// Text for Last Will & Testament status messages.
|
||||
const char* kLwtOnline = "Online";
|
||||
const char* kLwtOffline = "Offline";
|
||||
const char* const kLwtOnline = "Online";
|
||||
const char* const kLwtOffline = "Offline";
|
||||
|
||||
const uint8_t kHostnameLength = 30;
|
||||
const uint8_t kPortLength = 5; // Largest value of uint16_t is "65535".
|
||||
|
@ -285,7 +285,7 @@ const uint16_t kJsonAcStateMaxSize = 1024; // Bytes
|
|||
// ----------------- End of User Configuration Section -------------------------
|
||||
|
||||
// Constants
|
||||
#define _MY_VERSION_ "v1.5.2"
|
||||
#define _MY_VERSION_ "v1.6.0"
|
||||
|
||||
const uint8_t kRebootTime = 15; // Seconds
|
||||
const uint8_t kQuickDisplayTime = 2; // Seconds
|
||||
|
@ -310,29 +310,29 @@ const int8_t kRxGpios[] = {
|
|||
|
||||
// JSON stuff
|
||||
// Name of the json config file in SPIFFS.
|
||||
const char* kConfigFile = "/config.json";
|
||||
const char* kMqttServerKey = "mqtt_server";
|
||||
const char* kMqttPortKey = "mqtt_port";
|
||||
const char* kMqttUserKey = "mqtt_user";
|
||||
const char* kMqttPassKey = "mqtt_pass";
|
||||
const char* kMqttPrefixKey = "mqtt_prefix";
|
||||
const char* kHostnameKey = "hostname";
|
||||
const char* kHttpUserKey = "http_user";
|
||||
const char* kHttpPassKey = "http_pass";
|
||||
const char* kCommandDelimiter = ",";
|
||||
const char* const kConfigFile = "/config.json";
|
||||
const char* const kMqttServerKey = "mqtt_server";
|
||||
const char* const kMqttPortKey = "mqtt_port";
|
||||
const char* const kMqttUserKey = "mqtt_user";
|
||||
const char* const kMqttPassKey = "mqtt_pass";
|
||||
const char* const kMqttPrefixKey = "mqtt_prefix";
|
||||
const char* const kHostnameKey = "hostname";
|
||||
const char* const kHttpUserKey = "http_user";
|
||||
const char* const kHttpPassKey = "http_pass";
|
||||
const char* const kCommandDelimiter = ",";
|
||||
|
||||
// URLs
|
||||
const char* kUrlRoot = "/";
|
||||
const char* kUrlAdmin = "/admin";
|
||||
const char* kUrlAircon = "/aircon";
|
||||
const char* kUrlSendDiscovery = "/send_discovery";
|
||||
const char* kUrlExamples = "/examples";
|
||||
const char* kUrlGpio = "/gpio";
|
||||
const char* kUrlGpioSet = "/gpio/set";
|
||||
const char* kUrlInfo = "/info";
|
||||
const char* kUrlReboot = "/quitquitquit";
|
||||
const char* kUrlWipe = "/reset";
|
||||
const char* kUrlClearMqtt = "/clear_retained";
|
||||
const char* const kUrlRoot = "/";
|
||||
const char* const kUrlAdmin = "/admin";
|
||||
const char* const kUrlAircon = "/aircon";
|
||||
const char* const kUrlSendDiscovery = "/send_discovery";
|
||||
const char* const kUrlExamples = "/examples";
|
||||
const char* const kUrlGpio = "/gpio";
|
||||
const char* const kUrlGpioSet = "/gpio/set";
|
||||
const char* const kUrlInfo = "/info";
|
||||
const char* const kUrlReboot = "/quitquitquit";
|
||||
const char* const kUrlWipe = "/reset";
|
||||
const char* const kUrlClearMqtt = "/clear_retained";
|
||||
|
||||
#if MQTT_ENABLE
|
||||
const uint32_t kBroadcastPeriodMs = MQTTbroadcastInterval * 1000; // mSeconds.
|
||||
|
@ -340,7 +340,7 @@ const uint32_t kBroadcastPeriodMs = MQTTbroadcastInterval * 1000; // mSeconds.
|
|||
// Default is 5 seconds per IR TX GPIOs (channels) used.
|
||||
const uint32_t kStatListenPeriodMs = 5 * 1000 * kNrOfIrTxGpios; // mSeconds
|
||||
const int32_t kMaxPauseMs = 10000; // 10 Seconds.
|
||||
const char* kSequenceDelimiter = ";";
|
||||
const char* const kSequenceDelimiter = ";";
|
||||
const char kPauseChar = 'P';
|
||||
#if defined(ESP8266)
|
||||
const uint32_t kChipId = ESP.getChipId();
|
||||
|
@ -349,7 +349,7 @@ const uint32_t kChipId = ESP.getChipId();
|
|||
const uint32_t kChipId = ESP.getEfuseMac(); // Discard the top 16 bits.
|
||||
#endif // ESP32
|
||||
|
||||
const char* kClimateTopics =
|
||||
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 "|"
|
||||
|
@ -358,7 +358,7 @@ const char* kClimateTopics =
|
|||
"|" KEY_JSON
|
||||
#endif // MQTT_CLIMATE_JSON
|
||||
")<br>";
|
||||
const char* kMqttTopics[] = {
|
||||
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,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Send & receive arbitrary IR codes via a web server or MQTT.
|
||||
* Copyright David Conran 2016, 2017, 2018, 2019, 2020
|
||||
* Copyright David Conran 2016-2021
|
||||
*
|
||||
* Copyright:
|
||||
* Code for this has been borrowed from lots of other OpenSource projects &
|
||||
|
@ -252,7 +252,8 @@
|
|||
* - "Middle"
|
||||
* - "Low"
|
||||
* - "Lowest"
|
||||
* power_command_topic: "ir_server/ac/cmnd/power"
|
||||
* # `power_command_topic` is probably not needed for most HA configurations
|
||||
* # 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"
|
||||
|
@ -360,6 +361,12 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#ifdef ESP32
|
||||
#ifdef F
|
||||
#undef F
|
||||
#endif // F
|
||||
#define F(string) string
|
||||
#endif // ESP32
|
||||
using irutils::msToString;
|
||||
|
||||
#if REPORT_VCC
|
||||
|
@ -380,7 +387,7 @@ MDNSResponder mdns;
|
|||
WiFiClient espClient;
|
||||
WiFiManager wifiManager;
|
||||
bool flagSaveWifiConfig = false;
|
||||
char HttpUsername[kUsernameLength + 1] = "admin"; // Default HTT username.
|
||||
char HttpUsername[kUsernameLength + 1] = "admin"; // Default HTTP username.
|
||||
char HttpPassword[kPasswordLength + 1] = ""; // No HTTP password by default.
|
||||
char Hostname[kHostnameLength + 1] = "ir_server"; // Default hostname.
|
||||
uint16_t *codeArray;
|
||||
|
@ -398,14 +405,14 @@ String lastClimateSource;
|
|||
IRrecv *irrecv = NULL;
|
||||
decode_results capture; // Somewhere to store inbound IR messages.
|
||||
int8_t rx_gpio = kDefaultIrRx;
|
||||
String lastIrReceived = "None";
|
||||
String lastIrReceived = FPSTR("None");
|
||||
uint32_t lastIrReceivedTime = 0;
|
||||
uint32_t irRecvCounter = 0;
|
||||
#endif // IR_RX
|
||||
|
||||
// Climate stuff
|
||||
IRac *climate[kNrOfIrTxGpios];
|
||||
String channel_re = "("; // Will be built later.
|
||||
String channel_re = FPSTR("("); // Will be built later.
|
||||
uint16_t chan = 0; // The channel to use for the aircon HTML page.
|
||||
|
||||
TimerMs lastClimateIr = TimerMs(); // When we last sent the IR Climate mesg.
|
||||
|
@ -416,8 +423,8 @@ bool hasClimateBeenSent = false; // Has the Climate ever been sent?
|
|||
|
||||
#if MQTT_ENABLE
|
||||
PubSubClient mqtt_client(espClient);
|
||||
String lastMqttCmd = "None";
|
||||
String lastMqttCmdTopic = "None";
|
||||
String lastMqttCmd = FPSTR("None");
|
||||
String lastMqttCmdTopic = FPSTR("None");
|
||||
uint32_t lastMqttCmdTime = 0;
|
||||
uint32_t lastConnectedTime = 0;
|
||||
uint32_t lastDisconnectedTime = 0;
|
||||
|
@ -654,7 +661,7 @@ String listOfTxGpios(void) {
|
|||
if (i) result += ", ";
|
||||
result += gpioToString(txGpioTable[i]);
|
||||
if (!found && txGpioTable[i] == getDefaultTxGpio()) {
|
||||
result += " (default)";
|
||||
result += F(" (default)");
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
@ -894,7 +901,7 @@ void handleExamples(void) {
|
|||
#endif // EXAMPLES_ENABLE
|
||||
|
||||
String htmlSelectBool(const String name, const bool def) {
|
||||
String html = "<select name='" + name + "'>";
|
||||
String html = F("<select name='") + name + F("'>");
|
||||
for (uint16_t i = 0; i < 2; i++)
|
||||
html += htmlOptionItem(IRac::boolToString(i), IRac::boolToString(i),
|
||||
i == def);
|
||||
|
@ -903,7 +910,7 @@ String htmlSelectBool(const String name, const bool def) {
|
|||
}
|
||||
|
||||
String htmlSelectClimateProtocol(const String name, const decode_type_t def) {
|
||||
String html = "<select name='" + name + "'>";
|
||||
String html = 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),
|
||||
|
@ -915,14 +922,14 @@ String htmlSelectClimateProtocol(const String name, const decode_type_t def) {
|
|||
}
|
||||
|
||||
String htmlSelectModel(const String name, const int16_t def) {
|
||||
String html = "<select name='" + name + "'>";
|
||||
String html = F("<select name='") + name + F("'>");
|
||||
for (int16_t i = -1; i <= 6; i++) {
|
||||
String num = String(i);
|
||||
String text;
|
||||
if (i == -1)
|
||||
text = F("Default");
|
||||
else if (i == 0)
|
||||
text = F("Unknown");
|
||||
text = kUnknownStr;
|
||||
else
|
||||
text = num;
|
||||
html += htmlOptionItem(num, text, i == def);
|
||||
|
@ -933,7 +940,7 @@ String htmlSelectModel(const String name, const int16_t def) {
|
|||
|
||||
String htmlSelectUint(const String name, const uint16_t max,
|
||||
const uint16_t def) {
|
||||
String html = "<select name='" + name + "'>";
|
||||
String html = F("<select name='") + name + F("'>");
|
||||
for (uint16_t i = 0; i < max; i++) {
|
||||
String num = String(i);
|
||||
html += htmlOptionItem(num, num, i == def);
|
||||
|
@ -944,7 +951,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 = ": <select name='" + name + "'>";
|
||||
String html = 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,
|
||||
|
@ -956,7 +963,7 @@ String htmlSelectGpio(const String name, const int16_t def,
|
|||
}
|
||||
|
||||
String htmlSelectMode(const String name, const stdAc::opmode_t def) {
|
||||
String html = "<select name='" + name + "'>";
|
||||
String html = 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);
|
||||
|
@ -966,7 +973,7 @@ String htmlSelectMode(const String name, const stdAc::opmode_t def) {
|
|||
}
|
||||
|
||||
String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def) {
|
||||
String html = "<select name='" + name + "'>";
|
||||
String html = 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);
|
||||
|
@ -976,7 +983,7 @@ String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def) {
|
|||
}
|
||||
|
||||
String htmlSelectSwingv(const String name, const stdAc::swingv_t def) {
|
||||
String html = "<select name='" + name + "'>";
|
||||
String html = 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);
|
||||
|
@ -986,7 +993,7 @@ String htmlSelectSwingv(const String name, const stdAc::swingv_t def) {
|
|||
}
|
||||
|
||||
String htmlSelectSwingh(const String name, const stdAc::swingh_t def) {
|
||||
String html = "<select name='" + name + "'>";
|
||||
String html = 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);
|
||||
|
@ -1030,84 +1037,85 @@ void handleAirCon(void) {
|
|||
String html = htmlHeader(F("Air Conditioner Control"));
|
||||
html += htmlMenu();
|
||||
if (kNrOfIrTxGpios > 1) {
|
||||
html += "<form method='POST' action='/aircon/set'"
|
||||
html += 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) +
|
||||
"<input type='submit' value='Change'>"
|
||||
F("<input type='submit' value='Change'>"
|
||||
"</td></tr>"
|
||||
"</table>"
|
||||
"</form>"
|
||||
"<hr>";
|
||||
"<hr>");
|
||||
}
|
||||
if (climate[chan] != NULL) {
|
||||
html += "<h3>Current Settings</h3>"
|
||||
html += F("<h3>Current Settings</h3>"
|
||||
"<form method='POST' action='/aircon/set'"
|
||||
" enctype='multipart/form-data'>"
|
||||
"<input type='hidden' name='" KEY_CHANNEL "' value='" + String(chan) +
|
||||
"'>" +
|
||||
"<table style='width:33%'>"
|
||||
"<tr><td>" D_STR_PROTOCOL "</td><td>" +
|
||||
"<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,
|
||||
climate[chan]->next.protocol) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_MODEL "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_MODEL "</td><td>") +
|
||||
htmlSelectModel(KEY_MODEL, climate[chan]->next.model) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_POWER "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_POWER "</td><td>") +
|
||||
htmlSelectBool(KEY_POWER, climate[chan]->next.power) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_MODE "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_MODE "</td><td>") +
|
||||
htmlSelectMode(KEY_MODE, climate[chan]->next.mode) +
|
||||
"</td></tr>"
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_TEMP "</td><td>"
|
||||
"<input type='number' name='" KEY_TEMP "' min='16' max='90' "
|
||||
"step='0.5' value='" + String(climate[chan]->next.degrees, 1) + "'>"
|
||||
"step='0.5' value='") + String(climate[chan]->next.degrees, 1) +
|
||||
F("'>"
|
||||
"<select name='" KEY_CELSIUS "'>"
|
||||
"<option value='on'" +
|
||||
"<option value='on'") +
|
||||
(climate[chan]->next.celsius ? " selected='selected'" : "") +
|
||||
">C</option>"
|
||||
"<option value='off'" +
|
||||
(!climate[chan]->next.celsius ? " selected='selected'" : "") +
|
||||
">F</option>"
|
||||
F(">F</option>"
|
||||
"</select></td></tr>"
|
||||
"<tr><td>" D_STR_FAN "</td><td>" +
|
||||
"<tr><td>" D_STR_FAN "</td><td>") +
|
||||
htmlSelectFanspeed(KEY_FANSPEED, climate[chan]->next.fanspeed) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_SWINGV "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_SWINGV "</td><td>") +
|
||||
htmlSelectSwingv(KEY_SWINGV, climate[chan]->next.swingv) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_SWINGH "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_SWINGH "</td><td>") +
|
||||
htmlSelectSwingh(KEY_SWINGH, climate[chan]->next.swingh) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_QUIET "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_QUIET "</td><td>") +
|
||||
htmlSelectBool(KEY_QUIET, climate[chan]->next.quiet) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_TURBO "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_TURBO "</td><td>") +
|
||||
htmlSelectBool(KEY_TURBO, climate[chan]->next.turbo) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_ECONO "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_ECONO "</td><td>") +
|
||||
htmlSelectBool(KEY_ECONO, climate[chan]->next.econo) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_LIGHT "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_LIGHT "</td><td>") +
|
||||
htmlSelectBool(KEY_LIGHT, climate[chan]->next.light) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_FILTER "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_FILTER "</td><td>") +
|
||||
htmlSelectBool(KEY_FILTER, climate[chan]->next.filter) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_CLEAN "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_CLEAN "</td><td>") +
|
||||
htmlSelectBool(KEY_CLEAN, climate[chan]->next.clean) +
|
||||
"</td></tr>"
|
||||
"<tr><td>" D_STR_BEEP "</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>" D_STR_BEEP "</td><td>") +
|
||||
htmlSelectBool(KEY_BEEP, climate[chan]->next.beep) +
|
||||
"</td></tr>"
|
||||
"<tr><td>Force resend</td><td>" +
|
||||
F("</td></tr>"
|
||||
"<tr><td>Force resend</td><td>") +
|
||||
htmlSelectBool(KEY_RESEND, false) +
|
||||
"</td></tr>"
|
||||
F("</td></tr>"
|
||||
"</table>"
|
||||
"<input type='submit' value='Update & Send'>"
|
||||
"</form>";
|
||||
"</form>");
|
||||
}
|
||||
html += htmlEnd();
|
||||
server.send(200, "text/html", html);
|
||||
|
@ -1232,124 +1240,127 @@ void handleInfo(void) {
|
|||
String html = htmlHeader(F("IR MQTT server info"));
|
||||
html += htmlMenu();
|
||||
html +=
|
||||
"<h3>General</h3>"
|
||||
"<p>Hostname: " + String(Hostname) + "<br>"
|
||||
"IP address: " + WiFi.localIP().toString() + "<br>"
|
||||
"MAC address: " + WiFi.macAddress() + "<br>"
|
||||
"Booted: " + timeSince(1) + "<br>" +
|
||||
"Version: " _MY_VERSION_ "<br>"
|
||||
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>") +
|
||||
F("Version: " _MY_VERSION_ "<br>"
|
||||
"Built: " __DATE__
|
||||
" " __TIME__ "<br>"
|
||||
"Period Offset: " + String(offset) + "us<br>"
|
||||
"Period Offset: ") + String(offset) + F("us<br>"
|
||||
"IR Lib Version: " _IRREMOTEESP8266_VERSION_ "<br>"
|
||||
#if defined(ESP8266)
|
||||
"ESP8266 Core Version: " + ESP.getCoreVersion() + "<br>"
|
||||
"Free Sketch Space: " + String(maxSketchSpace() >> 10) + "k<br>"
|
||||
"ESP8266 Core Version: ") + ESP.getCoreVersion() + F("<br>"
|
||||
"Free Sketch Space: ") + String(maxSketchSpace() >> 10) + F("k<br>"
|
||||
#endif // ESP8266
|
||||
#if defined(ESP32)
|
||||
"ESP32 SDK Version: " + ESP.getSdkVersion() + "<br>"
|
||||
"ESP32 SDK Version: ") + ESP.getSdkVersion() + F("<br>"
|
||||
#endif // ESP32
|
||||
"Cpu Freq: " + String(ESP.getCpuFreqMHz()) + "MHz<br>"
|
||||
"Sanity Check: " + String((_sanity == 0) ? "Ok" : "FAILED") + "<br>"
|
||||
"IR Send GPIO(s): " + listOfTxGpios() + "<br>"
|
||||
"Cpu Freq: ") + String(ESP.getCpuFreqMHz()) + F("MHz<br>"
|
||||
"Sanity Check: ") + String((_sanity == 0) ? F("Ok") : F("FAILED")) +
|
||||
F("<br>"
|
||||
"IR Send GPIO(s): ") + listOfTxGpios() + F("<br>")
|
||||
+ irutils::addBoolToString(kInvertTxOutput,
|
||||
"Inverting GPIO output", false) + "<br>"
|
||||
"Total send requests: " + String(sendReqCounter) + "<br>"
|
||||
"Last message sent: " + String(lastSendSucceeded ? "Ok" : "FAILED") +
|
||||
" <i>(" + timeSince(lastSendTime) + ")</i><br>"
|
||||
F("Inverting GPIO output"), false) + F("<br>"
|
||||
"Total send requests: ") + String(sendReqCounter) + F("<br>"
|
||||
"Last message sent: ") + String(lastSendSucceeded ? F("Ok") : F("FAILED")) +
|
||||
F(" <i>(") + timeSince(lastSendTime) + F(")</i><br>"
|
||||
#if IR_RX
|
||||
"IR Recv GPIO: " + gpioToString(rx_gpio) +
|
||||
"IR Recv GPIO: ") + gpioToString(rx_gpio) + F(
|
||||
#if IR_RX_PULLUP
|
||||
" (pullup)"
|
||||
#endif // IR_RX_PULLUP
|
||||
"<br>"
|
||||
"Total IR Received: " + String(irRecvCounter) + "<br>"
|
||||
"Last IR Received: " + lastIrReceived +
|
||||
" <i>(" + timeSince(lastIrReceivedTime) + ")</i><br>"
|
||||
"Total IR Received: ") + String(irRecvCounter) + F("<br>"
|
||||
"Last IR Received: ") + lastIrReceived +
|
||||
F(" <i>(") + timeSince(lastIrReceivedTime) + F(")</i><br>"
|
||||
#endif // IR_RX
|
||||
"Duplicate " D_STR_WIFI " networks: " +
|
||||
String(HIDE_DUPLICATE_NETWORKS ? "Hide" : "Show") + "<br>"
|
||||
"Duplicate " D_STR_WIFI " networks: ") +
|
||||
String(HIDE_DUPLICATE_NETWORKS ? F("Hide") : F("Show")) + F("<br>"
|
||||
"Min " D_STR_WIFI " signal required: "
|
||||
#ifdef MIN_SIGNAL_STRENGTH
|
||||
+ String(static_cast<int>(MIN_SIGNAL_STRENGTH)) +
|
||||
) + // NOLINT(whitespace/parens)
|
||||
String(static_cast<int>(MIN_SIGNAL_STRENGTH)) + F(
|
||||
#else // MIN_SIGNAL_STRENGTH
|
||||
"8"
|
||||
#endif // MIN_SIGNAL_STRENGTH
|
||||
"%<br>"
|
||||
"Serial debugging: "
|
||||
#if DEBUG
|
||||
+ String(isSerialGpioUsedByIr() ? D_STR_OFF : D_STR_ON) +
|
||||
) + // NOLINT(whitespace/parens)
|
||||
String(isSerialGpioUsedByIr() ? D_STR_OFF : D_STR_ON) + F(
|
||||
#else // DEBUG
|
||||
D_STR_OFF
|
||||
#endif // DEBUG
|
||||
"<br>"
|
||||
#if REPORT_VCC
|
||||
"Vcc: ";
|
||||
"Vcc: ");
|
||||
html += vccToString();
|
||||
html += "V<br>"
|
||||
html += F("V<br>"
|
||||
#endif // REPORT_VCC
|
||||
"</p>"
|
||||
#if MQTT_ENABLE
|
||||
"<h4>MQTT Information</h4>"
|
||||
"<p>Server: " + String(MqttServer) + ":" + String(MqttPort) + " <i>(" +
|
||||
"<p>Server: ") + String(MqttServer) + ":" + String(MqttPort) + F(" <i>(") +
|
||||
(mqtt_client.connected() ? "Connected " + timeSince(lastDisconnectedTime)
|
||||
: "Disconnected " + timeSince(lastConnectedTime)) +
|
||||
")</i><br>"
|
||||
"Disconnections: " + String(mqttDisconnectCounter - 1) + "<br>"
|
||||
"Buffer Size: " + String(mqtt_client.getBufferSize()) + " bytes<br>"
|
||||
"Client id: " + MqttClientId + "<br>"
|
||||
"Command topic(s): " + listOfCommandTopics() + "<br>"
|
||||
"Acknowledgements topic: " + MqttAck + "<br>"
|
||||
F(")</i><br>"
|
||||
"Disconnections: ") + String(mqttDisconnectCounter - 1) + F("<br>"
|
||||
"Buffer Size: ") + String(mqtt_client.getBufferSize()) + F(" bytes<br>"
|
||||
"Client id: ") + MqttClientId + F("<br>"
|
||||
"Command topic(s): ") + listOfCommandTopics() + F("<br>"
|
||||
"Acknowledgements topic: ") + MqttAck + F("<br>"
|
||||
#if IR_RX
|
||||
"IR Received topic: " + MqttRecv + "<br>"
|
||||
"IR Received topic: ") + MqttRecv + F("<br>"
|
||||
#endif // IR_RX
|
||||
"Log topic: " + MqttLog + "<br>"
|
||||
"LWT topic: " + MqttLwt + "<br>"
|
||||
"QoS: " + String(QOS) + "<br>"
|
||||
"Log topic: ") + MqttLog + F("<br>"
|
||||
"LWT topic: ") + MqttLwt + F("<br>"
|
||||
"QoS: ") + String(QOS) + F("<br>"
|
||||
// lastMqttCmd* is unescaped untrusted input.
|
||||
// Avoid any possible HTML/XSS when displaying it.
|
||||
"Last MQTT command seen: (topic) '" +
|
||||
"Last MQTT command seen: (topic) '") +
|
||||
irutils::htmlEscape(lastMqttCmdTopic) +
|
||||
"' (payload) '" + irutils::htmlEscape(lastMqttCmd) + "' <i>(" +
|
||||
timeSince(lastMqttCmdTime) + ")</i><br>"
|
||||
"Total published: " + String(mqttSentCounter) + "<br>"
|
||||
"Total received: " + String(mqttRecvCounter) + "<br>"
|
||||
F("' (payload) '") + irutils::htmlEscape(lastMqttCmd) + F("' <i>(") +
|
||||
timeSince(lastMqttCmdTime) + F(")</i><br>"
|
||||
"Total published: ") + String(mqttSentCounter) + F("<br>"
|
||||
"Total received: ") + String(mqttRecvCounter) + F("<br>"
|
||||
"</p>"
|
||||
#endif // MQTT_ENABLE
|
||||
"<h4>Climate Information</h4>"
|
||||
"<p>"
|
||||
"IR Send GPIO: " + String(txGpioTable[0]) + "<br>"
|
||||
"Last update source: " + lastClimateSource + "<br>"
|
||||
"Total sent: " + String(irClimateCounter) + "<br>"
|
||||
"Last send: " + String(hasClimateBeenSent ?
|
||||
"IR Send GPIO: ") + String(txGpioTable[0]) + F("<br>"
|
||||
"Last update source: ") + lastClimateSource + F("<br>"
|
||||
"Total sent: ") + String(irClimateCounter) + F("<br>"
|
||||
"Last send: ") + String(hasClimateBeenSent ?
|
||||
(String(lastClimateSucceeded ? "Ok" : "FAILED") +
|
||||
" <i>(" + timeElapsed(lastClimateIr.elapsed()) + ")</i>") :
|
||||
"<i>Never</i>") + "<br>"
|
||||
"<i>Never</i>") + F("<br>"
|
||||
#if MQTT_ENABLE
|
||||
"State listen period: " + msToString(kStatListenPeriodMs) + "<br>"
|
||||
"State broadcast period: " + msToString(kBroadcastPeriodMs) + "<br>"
|
||||
"Last state broadcast: " + (hasBroadcastBeenSent ?
|
||||
"State listen period: ") + msToString(kStatListenPeriodMs) + F("<br>"
|
||||
"State broadcast period: ") + msToString(kBroadcastPeriodMs) + F("<br>"
|
||||
"Last state broadcast: ") + (hasBroadcastBeenSent ?
|
||||
timeElapsed(lastBroadcast.elapsed()) :
|
||||
String("<i>Never</i>")) + "<br>"
|
||||
String(F("<i>Never</i>"))) + F("<br>"
|
||||
#if MQTT_DISCOVERY_ENABLE
|
||||
"Last discovery sent: " + (lockMqttBroadcast ?
|
||||
String("<b>Locked</b>") :
|
||||
"Last discovery sent: ") + (lockMqttBroadcast ?
|
||||
String(F("<b>Locked</b>")) :
|
||||
(hasDiscoveryBeenSent ?
|
||||
timeElapsed(lastDiscovery.elapsed()) :
|
||||
String("<i>Never</i>"))) +
|
||||
"<br>"
|
||||
"Discovery topic: " + MqttDiscovery + "<br>" +
|
||||
String(F("<i>Never</i>")))) +
|
||||
F("<br>"
|
||||
"Discovery topic: ") + MqttDiscovery + F("<br>") + F(
|
||||
#endif // MQTT_DISCOVERY_ENABLE
|
||||
"Command topics: " + MqttClimate + channel_re + '/' + MQTT_CLIMATE_CMND +
|
||||
'/' + kClimateTopics +
|
||||
"State topics: " + MqttClimate + channel_re + '/' + MQTT_CLIMATE_STAT +
|
||||
'/' + kClimateTopics +
|
||||
"Command topics: ") + MqttClimate + channel_re +
|
||||
F("/" MQTT_CLIMATE_CMND "/") + FPSTR(kClimateTopics) +
|
||||
F("State topics: ") + MqttClimate + channel_re +
|
||||
F("/" MQTT_CLIMATE_STAT "/") + FPSTR(kClimateTopics) + F(
|
||||
#endif // MQTT_ENABLE
|
||||
"</p>"
|
||||
// Page footer
|
||||
"<hr><p><small><center>"
|
||||
"<i>(Note: Page will refresh every 60 " D_STR_SECONDS ".)</i>"
|
||||
"<centre></small></p>";
|
||||
"<centre></small></p>");
|
||||
html += addJsReloadUrl(kUrlInfo, 60, false);
|
||||
html += htmlEnd();
|
||||
server.send(200, "text/html", html);
|
||||
|
@ -1384,14 +1395,14 @@ bool clearMqttSavedStates(const String topic_base) {
|
|||
for (size_t i = 0; i < sizeof(kMqttTopics) / sizeof(char*); i++) {
|
||||
// Sending a retained "" message to the topic should clear previous values
|
||||
// in theory.
|
||||
String topic = topic_base + channelStr + '/' + F(MQTT_CLIMATE_STAT) +
|
||||
'/' + String(kMqttTopics[i]);
|
||||
String topic = topic_base + channelStr + F("/" MQTT_CLIMATE_STAT "/") +
|
||||
String(kMqttTopics[i]);
|
||||
success &= mqtt_client.publish(topic.c_str(), "", true);
|
||||
}
|
||||
channelStr = '_' + String(channel);
|
||||
}
|
||||
String logmesg = "Removing all possible settings saved in MQTT for '" +
|
||||
topic_base + "' ";
|
||||
String logmesg = F("Removing all possible settings saved in MQTT for '") +
|
||||
topic_base + F("' ");
|
||||
logmesg += success ? F("succeeded") : F("failed");
|
||||
mqttLog(logmesg.c_str());
|
||||
return success;
|
||||
|
@ -1410,13 +1421,13 @@ void handleClearMqtt(void) {
|
|||
htmlHeader(F("Clearing saved info from MQTT"),
|
||||
F("Removing all saved settings for this device from "
|
||||
"MQTT.")) +
|
||||
"<p>Device restarting. Try connecting in a few " D_STR_SECONDS ".</p>" +
|
||||
F("<p>Device restarting. Try connecting in a few " D_STR_SECONDS ".</p>") +
|
||||
addJsReloadUrl(kUrlRoot, 10, true) +
|
||||
htmlEnd());
|
||||
// Do the clearing.
|
||||
mqttLog("Clearing all saved settings from MQTT.");
|
||||
mqttLog(PSTR("Clearing all saved settings from MQTT."));
|
||||
clearMqttSavedStates(MqttClimate);
|
||||
doRestart("Rebooting...");
|
||||
doRestart(PSTR("Rebooting..."));
|
||||
}
|
||||
#endif // MQTT_ENABLE && MQTT_CLEAR_ENABLE
|
||||
|
||||
|
@ -1438,10 +1449,10 @@ void handleReset(void) {
|
|||
// Do the reset.
|
||||
#if MQTT_ENABLE
|
||||
#if MQTT_CLEAR_ENABLE
|
||||
mqttLog("Clearing all saved climate settings from MQTT.");
|
||||
mqttLog(PSTR("Clearing all saved climate settings from MQTT."));
|
||||
clearMqttSavedStates(MqttClimate);
|
||||
#endif // MQTT_CLEAR_ENABLE
|
||||
mqttLog("Wiping all saved config settings.");
|
||||
mqttLog(PSTR("Wiping all saved config settings."));
|
||||
#endif // MQTT_ENABLE
|
||||
if (mountSpiffs()) {
|
||||
debug("Removing JSON config file");
|
||||
|
@ -1451,7 +1462,7 @@ void handleReset(void) {
|
|||
delay(1000);
|
||||
debug("Reseting wifiManager's settings.");
|
||||
wifiManager.resetSettings();
|
||||
doRestart("Rebooting...");
|
||||
doRestart(PSTR("Rebooting..."));
|
||||
}
|
||||
|
||||
// Reboot web page
|
||||
|
@ -1465,7 +1476,7 @@ void handleReboot() {
|
|||
#endif
|
||||
server.send(200, "text/html",
|
||||
htmlHeader(F("Device restarting.")) +
|
||||
"<p>Try connecting in a few " D_STR_SECONDS ".</p>" +
|
||||
F("<p>Try connecting in a few " D_STR_SECONDS ".</p>") +
|
||||
addJsReloadUrl(kUrlRoot, kRebootTime, true) +
|
||||
htmlEnd());
|
||||
doRestart("Reboot requested");
|
||||
|
@ -1484,7 +1495,7 @@ bool parseStringAndSendAirCon(IRsend *irsend, const decode_type_t irType,
|
|||
uint8_t state[kStateSizeMax] = {0}; // All array elements are set to 0.
|
||||
uint16_t stateSize = 0;
|
||||
|
||||
if (str.startsWith("0x") || str.startsWith("0X"))
|
||||
if (str.startsWith(PSTR("0x")) || str.startsWith(PSTR("0X")))
|
||||
strOffset = 2;
|
||||
// Calculate how many hexadecimal characters there are.
|
||||
uint16_t inputLength = str.length() - strOffset;
|
||||
|
@ -1643,8 +1654,9 @@ uint16_t * newCodeArray(const uint16_t size) {
|
|||
// Check we malloc'ed successfully.
|
||||
if (result == NULL) // malloc failed, so give up.
|
||||
doRestart(
|
||||
"FATAL: Can't allocate memory for an array for a new message! "
|
||||
"Forcing a reboot!", true); // Send to serial only as we are in low mem
|
||||
PSTR("FATAL: Can't allocate memory for an array for a new message! "
|
||||
"Forcing a reboot!"),
|
||||
true); // Send to serial only as we are in low mem
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1666,7 +1678,7 @@ bool parseStringAndSendGC(IRsend *irsend, const String str) {
|
|||
String tmp_str;
|
||||
|
||||
// Remove the leading "1:1,1," if present.
|
||||
if (str.startsWith("1:1,1,"))
|
||||
if (str.startsWith(PSTR("1:1,1,")))
|
||||
tmp_str = str.substring(6);
|
||||
else
|
||||
tmp_str = str;
|
||||
|
@ -2097,7 +2109,7 @@ void setup(void) {
|
|||
if (isSerialGpioUsedByIr()) Serial.end();
|
||||
#endif // DEBUG
|
||||
|
||||
channel_re.reserve(kNrOfIrTxGpios * 3);
|
||||
channel_re.reserve(kNrOfIrTxGpios * 3 + 3 + 1);
|
||||
// Initialise all the IR transmitters.
|
||||
for (uint8_t i = 0; i < kNrOfIrTxGpios; i++) {
|
||||
if (txGpioTable[i] == kGpioUnused) {
|
||||
|
@ -2195,7 +2207,7 @@ void setup(void) {
|
|||
if (strlen(HttpPassword)) { // Allow if password is set.
|
||||
server.on("/update", HTTP_POST, [](){
|
||||
#if MQTT_ENABLE
|
||||
mqttLog("Attempting firmware update & reboot");
|
||||
mqttLog(PSTR("Attempting firmware update & reboot"));
|
||||
delay(1000);
|
||||
#endif // MQTT_ENABLE
|
||||
server.send(200, "text/html",
|
||||
|
@ -2287,7 +2299,7 @@ void unsubscribing(const String topic_name) {
|
|||
|
||||
void mqttLog(const char* str) {
|
||||
debug(str);
|
||||
mqtt_client.publish(MqttLog.c_str(), str);
|
||||
mqtt_client.publish(MqttLog.c_str(), String(str).c_str());
|
||||
mqttSentCounter++;
|
||||
}
|
||||
|
||||
|
@ -2313,7 +2325,7 @@ bool reconnect(void) {
|
|||
}
|
||||
if (connected) {
|
||||
// Once connected, publish an announcement...
|
||||
mqttLog("(Re)Connected.");
|
||||
mqttLog(PSTR("(Re)Connected."));
|
||||
|
||||
// Update Last Will & Testament to say we are back online.
|
||||
mqtt_client.publish(MqttLwt.c_str(), kLwtOnline, true);
|
||||
|
@ -2364,12 +2376,13 @@ void handleSendMqttDiscovery(void) {
|
|||
server.send(200, "text/html",
|
||||
htmlHeader(F("Sending MQTT Discovery message")) +
|
||||
htmlMenu() +
|
||||
"<p>The Home Assistant MQTT Discovery message is being sent to topic: " +
|
||||
MqttDiscovery + ". It will show up in Home Assistant in a few seconds."
|
||||
F("<p>The Home Assistant MQTT Discovery message is being sent to topic: ")
|
||||
+ MqttDiscovery +
|
||||
F(". It will show up in Home Assistant in a few seconds."
|
||||
"</p>"
|
||||
"<h3>Warning!</h3>"
|
||||
"<p>Home Assistant's config for this device is reset each time this is "
|
||||
" is sent.</p>" +
|
||||
" is sent.</p>") +
|
||||
addJsReloadUrl(kUrlRoot, kRebootTime, true) +
|
||||
htmlEnd());
|
||||
sendMQTTDiscovery(MqttDiscovery.c_str());
|
||||
|
@ -2416,8 +2429,8 @@ void receivingMQTT(String const topic_name, String const callback_str) {
|
|||
// Or is for a specific ac/climate channel. e.g. "*/ac_[1-9]"
|
||||
debug(("Checking for channel number in " + topic_name).c_str());
|
||||
for (uint16_t i = 0; i < kNrOfIrTxGpios; i++) {
|
||||
if (topic_name.endsWith("_" + String(i)) ||
|
||||
(i > 0 && topic_name.startsWith(MqttClimate + "_" + String(i)))) {
|
||||
if (topic_name.endsWith('_' + String(i)) ||
|
||||
(i > 0 && topic_name.startsWith(MqttClimate + '_' + String(i)))) {
|
||||
channel = i;
|
||||
break;
|
||||
}
|
||||
|
@ -2425,8 +2438,8 @@ void receivingMQTT(String const topic_name, String const callback_str) {
|
|||
debug(("Channel = " + String(channel)).c_str());
|
||||
// Is it a climate topic?
|
||||
if (topic_name.startsWith(MqttClimate)) {
|
||||
String alt_cmnd_topic = MqttClimate + "_" + String(channel) + '/' +
|
||||
MQTT_CLIMATE_CMND + '/';
|
||||
String alt_cmnd_topic = MqttClimate + '_' + String(channel) +
|
||||
F("/" MQTT_CLIMATE_CMND "/");
|
||||
// Also accept climate commands on the '*_0' channel.
|
||||
String cmnd_topic = topic_name.startsWith(alt_cmnd_topic) ? alt_cmnd_topic
|
||||
: MqttClimateCmnd;
|
||||
|
@ -2440,7 +2453,7 @@ void receivingMQTT(String const topic_name, String const callback_str) {
|
|||
if (topic_name.equals(cmnd_topic + KEY_RESEND) &&
|
||||
callback_str.equalsIgnoreCase(KEY_RESEND)) {
|
||||
force_resend = true;
|
||||
mqttLog("Climate resend requested.");
|
||||
mqttLog(PSTR("Climate resend requested."));
|
||||
}
|
||||
if (sendClimate(stat_topic, true, false, force_resend, true,
|
||||
climate[channel]) && !force_resend)
|
||||
|
@ -2548,10 +2561,15 @@ void mqttCallback(char* topic, byte* payload, unsigned int length) {
|
|||
void sendMQTTDiscovery(const char *topic) {
|
||||
if (mqtt_client.publish(
|
||||
topic, String(
|
||||
"{"
|
||||
"\"~\":\"" + MqttClimate + "\","
|
||||
"\"name\":\"" + MqttHAName + "\","
|
||||
F("{"
|
||||
"\"~\":\"") + MqttClimate + F("\","
|
||||
"\"name\":\"") + MqttHAName + 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
|
||||
// if both are used.
|
||||
"\"pow_cmd_t\":\"~/" MQTT_CLIMATE_CMND "/" KEY_POWER "\","
|
||||
#endif // !MQTT_CLIMATE_HA_MODE
|
||||
"\"mode_cmd_t\":\"~/" MQTT_CLIMATE_CMND "/" KEY_MODE "\","
|
||||
"\"mode_stat_t\":\"~/" MQTT_CLIMATE_STAT "/" KEY_MODE "\","
|
||||
// I don't know why, but the modes need to be lower case to work with
|
||||
|
@ -2571,22 +2589,22 @@ 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 + "\","
|
||||
"\"uniq_id\":\"") + MqttUniqueId + F("\","
|
||||
"\"device\":{"
|
||||
"\"identifiers\":[\"" + MqttUniqueId + "\"],"
|
||||
"\"connections\":[[\"mac\",\"" + WiFi.macAddress() + "\"]],"
|
||||
"\"identifiers\":[\"") + MqttUniqueId + F("\"],"
|
||||
"\"connections\":[[\"mac\",\"") + WiFi.macAddress() + F("\"]],"
|
||||
"\"manufacturer\":\"IRremoteESP8266\","
|
||||
"\"model\":\"IRMQTTServer\","
|
||||
"\"name\":\"" + Hostname + "\","
|
||||
"\"name\":\"") + Hostname + F("\","
|
||||
"\"sw_version\":\"" _MY_VERSION_ "\""
|
||||
"}"
|
||||
"}").c_str(), true)) {
|
||||
mqttLog("MQTT climate discovery successful sent.");
|
||||
"}")).c_str(), true)) {
|
||||
mqttLog(PSTR("MQTT climate discovery successful sent."));
|
||||
hasDiscoveryBeenSent = true;
|
||||
lastDiscovery.reset();
|
||||
mqttSentCounter++;
|
||||
} else {
|
||||
mqttLog("MQTT climate discovery FAILED to send.");
|
||||
mqttLog(PSTR("MQTT climate discovery FAILED to send."));
|
||||
}
|
||||
}
|
||||
#endif // MQTT_DISCOVERY_ENABLE
|
||||
|
@ -2616,11 +2634,12 @@ void loop(void) {
|
|||
lastReconnectAttempt = 0;
|
||||
wasConnected = true;
|
||||
if (boot) {
|
||||
mqttLog("IRMQTTServer " _MY_VERSION_ " just booted");
|
||||
mqttLog(PSTR("IRMQTTServer " _MY_VERSION_ " just booted"));
|
||||
boot = false;
|
||||
} else {
|
||||
mqttLog(String(
|
||||
"IRMQTTServer just (re)connected to MQTT. Lost connection about "
|
||||
F("IRMQTTServer just (re)connected to MQTT. "
|
||||
"Lost connection about ")
|
||||
+ timeSince(lastConnectedTime)).c_str());
|
||||
}
|
||||
lastConnectedTime = now;
|
||||
|
@ -2628,7 +2647,7 @@ void loop(void) {
|
|||
if (lockMqttBroadcast) {
|
||||
// Attempt to fetch back any Climate state stored in MQTT retained
|
||||
// messages on the MQTT broker.
|
||||
mqttLog("Started listening for previous state.");
|
||||
mqttLog(PSTR("Started listening for previous state."));
|
||||
for (uint16_t i = 0; i < kNrOfIrTxGpios; i++)
|
||||
subscribing(genStatTopic(i) + '+');
|
||||
statListenTime.reset();
|
||||
|
@ -2648,10 +2667,10 @@ void loop(void) {
|
|||
sendClimate(stat_topic, true, false, false,
|
||||
MQTT_CLIMATE_IR_SEND_ON_RESTART, climate[i]);
|
||||
lastClimateSource = F("MQTT (via retain)");
|
||||
mqttLog("The state was recovered from MQTT broker.");
|
||||
mqttLog(PSTR("The state was recovered from MQTT broker."));
|
||||
}
|
||||
}
|
||||
mqttLog("Finished listening for previous state.");
|
||||
mqttLog(PSTR("Finished listening for previous state."));
|
||||
lockMqttBroadcast = false; // Release the lock so we can broadcast again.
|
||||
}
|
||||
// Periodically send all of the climate state via MQTT.
|
||||
|
@ -2671,17 +2690,17 @@ void loop(void) {
|
|||
resultToHexidecimal(&capture);
|
||||
#if REPORT_RAW_UNKNOWNS
|
||||
if (capture.decode_type == UNKNOWN) {
|
||||
lastIrReceived += ";";
|
||||
lastIrReceived += ';';
|
||||
for (uint16_t i = 1; i < capture.rawlen; i++) {
|
||||
uint32_t usecs;
|
||||
for (usecs = capture.rawbuf[i] * kRawTick; usecs > UINT16_MAX;
|
||||
usecs -= UINT16_MAX) {
|
||||
lastIrReceived += uint64ToString(UINT16_MAX);
|
||||
lastIrReceived += ",0,";
|
||||
lastIrReceived += F(",0,");
|
||||
}
|
||||
lastIrReceived += uint64ToString(usecs, 10);
|
||||
if (i < capture.rawlen - 1)
|
||||
lastIrReceived += ",";
|
||||
lastIrReceived += ',';
|
||||
}
|
||||
}
|
||||
#endif // REPORT_RAW_UNKNOWNS
|
||||
|
@ -2875,10 +2894,10 @@ void sendJsonState(const stdAc::state_t state, const String topic,
|
|||
json[KEY_PROTOCOL] = typeToString(state.protocol);
|
||||
json[KEY_MODEL] = state.model;
|
||||
json[KEY_POWER] = IRac::boolToString(state.power);
|
||||
json[KEY_MODE] = IRac::opmodeToString(state.mode);
|
||||
json[KEY_MODE] = IRac::opmodeToString(state.mode, ha_mode);
|
||||
// Home Assistant wants mode to be off if power is also off & vice-versa.
|
||||
if (ha_mode && (state.mode == stdAc::opmode_t::kOff || !state.power)) {
|
||||
json[KEY_MODE] = IRac::opmodeToString(stdAc::opmode_t::kOff);
|
||||
json[KEY_MODE] = IRac::opmodeToString(stdAc::opmode_t::kOff, ha_mode);
|
||||
json[KEY_POWER] = IRac::boolToString(false);
|
||||
}
|
||||
json[KEY_CELSIUS] = IRac::boolToString(state.celsius);
|
||||
|
@ -2965,45 +2984,45 @@ void updateClimate(stdAc::state_t *state, const String str,
|
|||
*state = jsonToState(*state, payload.c_str());
|
||||
else
|
||||
#endif // MQTT_CLIMATE_JSON
|
||||
if (str.equals(prefix + KEY_PROTOCOL)) {
|
||||
if (str.equals(prefix + F(KEY_PROTOCOL))) {
|
||||
state->protocol = strToDecodeType(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_MODEL)) {
|
||||
} else if (str.equals(prefix + F(KEY_MODEL))) {
|
||||
state->model = IRac::strToModel(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_POWER)) {
|
||||
} else if (str.equals(prefix + F(KEY_POWER))) {
|
||||
state->power = IRac::strToBool(payload.c_str());
|
||||
#if MQTT_CLIMATE_HA_MODE
|
||||
if (!state->power) state->mode = stdAc::opmode_t::kOff;
|
||||
#endif // MQTT_CLIMATE_HA_MODE
|
||||
} else if (str.equals(prefix + KEY_MODE)) {
|
||||
} else if (str.equals(prefix + F(KEY_MODE))) {
|
||||
state->mode = IRac::strToOpmode(payload.c_str());
|
||||
#if MQTT_CLIMATE_HA_MODE
|
||||
state->power = (state->mode != stdAc::opmode_t::kOff);
|
||||
#endif // MQTT_CLIMATE_HA_MODE
|
||||
} else if (str.equals(prefix + KEY_TEMP)) {
|
||||
} else if (str.equals(prefix + F(KEY_TEMP))) {
|
||||
state->degrees = payload.toFloat();
|
||||
} else if (str.equals(prefix + KEY_FANSPEED)) {
|
||||
} else if (str.equals(prefix + F(KEY_FANSPEED))) {
|
||||
state->fanspeed = IRac::strToFanspeed(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_SWINGV)) {
|
||||
} else if (str.equals(prefix + F(KEY_SWINGV))) {
|
||||
state->swingv = IRac::strToSwingV(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_SWINGH)) {
|
||||
} else if (str.equals(prefix + F(KEY_SWINGH))) {
|
||||
state->swingh = IRac::strToSwingH(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_QUIET)) {
|
||||
} else if (str.equals(prefix + F(KEY_QUIET))) {
|
||||
state->quiet = IRac::strToBool(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_TURBO)) {
|
||||
} else if (str.equals(prefix + F(KEY_TURBO))) {
|
||||
state->turbo = IRac::strToBool(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_ECONO)) {
|
||||
} else if (str.equals(prefix + F(KEY_ECONO))) {
|
||||
state->econo = IRac::strToBool(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_LIGHT)) {
|
||||
} else if (str.equals(prefix + F(KEY_LIGHT))) {
|
||||
state->light = IRac::strToBool(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_BEEP)) {
|
||||
} else if (str.equals(prefix + F(KEY_BEEP))) {
|
||||
state->beep = IRac::strToBool(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_FILTER)) {
|
||||
} else if (str.equals(prefix + F(KEY_FILTER))) {
|
||||
state->filter = IRac::strToBool(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_CLEAN)) {
|
||||
} else if (str.equals(prefix + F(KEY_CLEAN))) {
|
||||
state->clean = IRac::strToBool(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_CELSIUS)) {
|
||||
} else if (str.equals(prefix + F(KEY_CELSIUS))) {
|
||||
state->celsius = IRac::strToBool(payload.c_str());
|
||||
} else if (str.equals(prefix + KEY_SLEEP)) {
|
||||
} else if (str.equals(prefix + F(KEY_SLEEP))) {
|
||||
state->sleep = payload.toInt();
|
||||
}
|
||||
}
|
||||
|
@ -3024,7 +3043,11 @@ bool sendClimate(const String topic_prefix, const bool retain,
|
|||
diff = true;
|
||||
success &= sendInt(topic_prefix + KEY_MODEL, next.model, 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();
|
||||
|
|
|
@ -52,6 +52,12 @@ build_flags = -D_IR_LOCALE_=it-IT ; Italian
|
|||
[env:pt-BR]
|
||||
build_flags = -D_IR_LOCALE_=pt-BR ; Portuguese (Brazilian)
|
||||
|
||||
[env:ru-RU]
|
||||
build_flags = -D_IR_LOCALE_=ru-RU ; Russian
|
||||
|
||||
[env:sv-SE]
|
||||
build_flags = -D_IR_LOCALE_=sv-SE ; Swedish
|
||||
|
||||
[env:zh-CN]
|
||||
build_flags = -D_IR_LOCALE_=zh-CN ; Chinese (Simplified)
|
||||
|
||||
|
|
|
@ -49,5 +49,14 @@ build_flags = -D_IR_LOCALE_=fr-FR ; French
|
|||
[env:it-IT]
|
||||
build_flags = -D_IR_LOCALE_=it-IT ; Italian
|
||||
|
||||
[env:pt-BR]
|
||||
build_flags = -D_IR_LOCALE_=pt-BR ; Portuguese (Brazilian)
|
||||
|
||||
[env:ru-RU]
|
||||
build_flags = -D_IR_LOCALE_=ru-RU ; Russian
|
||||
|
||||
[env:sv-SE]
|
||||
build_flags = -D_IR_LOCALE_=sv-SE ; Swedish
|
||||
|
||||
[env:zh-CN]
|
||||
build_flags = -D_IR_LOCALE_=zh-CN ; Chinese (Simplified)
|
||||
|
|
|
@ -52,6 +52,7 @@ IRKelonAc KEYWORD1
|
|||
IRKelvinatorAC KEYWORD1
|
||||
IRLgAc KEYWORD1
|
||||
IRMideaAC KEYWORD1
|
||||
IRMirageAc KEYWORD1
|
||||
IRMitsubishi112 KEYWORD1
|
||||
IRMitsubishi136 KEYWORD1
|
||||
IRMitsubishiAC KEYWORD1
|
||||
|
@ -60,6 +61,7 @@ IRMitsubishiHeavy88Ac KEYWORD1
|
|||
IRNeoclimaAc KEYWORD1
|
||||
IRPanasonicAc KEYWORD1
|
||||
IRPanasonicAc32 KEYWORD1
|
||||
IRRhossAc KEYWORD1
|
||||
IRSamsungAc KEYWORD1
|
||||
IRSanyoAc KEYWORD1
|
||||
IRSanyoAc88 KEYWORD1
|
||||
|
@ -85,16 +87,19 @@ decode_type_t KEYWORD1
|
|||
fanspeed_t KEYWORD1
|
||||
fujitsu_ac_remote_model_t KEYWORD1
|
||||
gree_ac_remote_model_t KEYWORD1
|
||||
haier_ac176_remote_model_t KEYWORD1
|
||||
hitachi_ac1_remote_model_t KEYWORD1
|
||||
irparams_t KEYWORD1
|
||||
lg_ac_remote_model_t KEYWORD1
|
||||
match_result_t KEYWORD1
|
||||
mirage_ac_remote_model_t KEYWORD1
|
||||
opmode_t KEYWORD1
|
||||
panasonic_ac_remote_model_t KEYWORD1
|
||||
sharp_ac_remote_model_t KEYWORD1
|
||||
state_t KEYWORD1
|
||||
swingh_t KEYWORD1
|
||||
swingv_t KEYWORD1
|
||||
tcl_ac_remote_model_t KEYWORD1
|
||||
voltas_ac_remote_model_t KEYWORD1
|
||||
whirlpool_ac_remote_model_t KEYWORD1
|
||||
|
||||
|
@ -107,6 +112,8 @@ _cancelOffTimer KEYWORD2
|
|||
_cancelOnTimer KEYWORD2
|
||||
_delayMicroseconds KEYWORD2
|
||||
_getEconoToggle KEYWORD2
|
||||
_getOffTimer KEYWORD2
|
||||
_getOnTimer KEYWORD2
|
||||
_getTime KEYWORD2
|
||||
_getTimer KEYWORD2
|
||||
_isAKB73757604 KEYWORD2
|
||||
|
@ -117,6 +124,9 @@ _restoreState KEYWORD2
|
|||
_sendSony KEYWORD2
|
||||
_setEconoToggle KEYWORD2
|
||||
_setMode KEYWORD2
|
||||
_setOffTimer KEYWORD2
|
||||
_setOnTimer KEYWORD2
|
||||
_setSleepTimer KEYWORD2
|
||||
_setTemp KEYWORD2
|
||||
_setTime KEYWORD2
|
||||
_setTimer KEYWORD2
|
||||
|
@ -135,6 +145,7 @@ addSwingHToString KEYWORD2
|
|||
addSwingVToString KEYWORD2
|
||||
addTempFloatToString KEYWORD2
|
||||
addTempToString KEYWORD2
|
||||
addToggleToString KEYWORD2
|
||||
adjustRepeat KEYWORD2
|
||||
airwell KEYWORD2
|
||||
amcor KEYWORD2
|
||||
|
@ -189,10 +200,12 @@ daikin2 KEYWORD2
|
|||
daikin216 KEYWORD2
|
||||
daikin64 KEYWORD2
|
||||
decode KEYWORD2
|
||||
decodeAirton KEYWORD2
|
||||
decodeAirwell KEYWORD2
|
||||
decodeAiwaRCT501 KEYWORD2
|
||||
decodeAmcor KEYWORD2
|
||||
decodeArgo KEYWORD2
|
||||
decodeArris KEYWORD2
|
||||
decodeBose KEYWORD2
|
||||
decodeCOOLIX KEYWORD2
|
||||
decodeCarrierAC KEYWORD2
|
||||
|
@ -258,6 +271,7 @@ decodePioneer KEYWORD2
|
|||
decodeRC5 KEYWORD2
|
||||
decodeRC6 KEYWORD2
|
||||
decodeRCMM KEYWORD2
|
||||
decodeRhoss KEYWORD2
|
||||
decodeSAMSUNG KEYWORD2
|
||||
decodeSamsung36 KEYWORD2
|
||||
decodeSamsungAC KEYWORD2
|
||||
|
@ -298,6 +312,7 @@ enableIROut KEYWORD2
|
|||
enableOffTimer KEYWORD2
|
||||
enableOnTimer KEYWORD2
|
||||
enableSleepTimer KEYWORD2
|
||||
encodeArris KEYWORD2
|
||||
encodeDoshisha KEYWORD2
|
||||
encodeJVC KEYWORD2
|
||||
encodeLG KEYWORD2
|
||||
|
@ -319,6 +334,7 @@ fahrenheitToCelsius KEYWORD2
|
|||
fanspeedToString KEYWORD2
|
||||
fixChecksum KEYWORD2
|
||||
fixup KEYWORD2
|
||||
fromCommon KEYWORD2
|
||||
fujitsu KEYWORD2
|
||||
get10CHeat KEYWORD2
|
||||
get3D KEYWORD2
|
||||
|
@ -331,6 +347,7 @@ getBufSize KEYWORD2
|
|||
getButton KEYWORD2
|
||||
getCelsius KEYWORD2
|
||||
getClean KEYWORD2
|
||||
getCleanToggle KEYWORD2
|
||||
getClock KEYWORD2
|
||||
getCmd KEYWORD2
|
||||
getComfort KEYWORD2
|
||||
|
@ -367,6 +384,7 @@ getIonFilter KEYWORD2
|
|||
getLed KEYWORD2
|
||||
getLight KEYWORD2
|
||||
getLightToggle KEYWORD2
|
||||
getLock KEYWORD2
|
||||
getMax KEYWORD2
|
||||
getMode KEYWORD2
|
||||
getMold KEYWORD2
|
||||
|
@ -396,9 +414,11 @@ getSectionByte KEYWORD2
|
|||
getSectionChecksum KEYWORD2
|
||||
getSensor KEYWORD2
|
||||
getSensorTemp KEYWORD2
|
||||
getSensorUpdate KEYWORD2
|
||||
getSilent KEYWORD2
|
||||
getSleep KEYWORD2
|
||||
getSleepTime KEYWORD2
|
||||
getSleepTimer KEYWORD2
|
||||
getSleepTimerEnabled KEYWORD2
|
||||
getSpecial KEYWORD2
|
||||
getSpeed KEYWORD2
|
||||
|
@ -481,6 +501,7 @@ isSwingH KEYWORD2
|
|||
isSwingV KEYWORD2
|
||||
isSwingVStep KEYWORD2
|
||||
isSwingVToggle KEYWORD2
|
||||
isTcl KEYWORD2
|
||||
isTimeCommand KEYWORD2
|
||||
isTimerActive KEYWORD2
|
||||
isTurboToggle KEYWORD2
|
||||
|
@ -509,6 +530,7 @@ matchSpaceRange KEYWORD2
|
|||
midea KEYWORD2
|
||||
minRepeats KEYWORD2
|
||||
minsToString KEYWORD2
|
||||
mirage KEYWORD2
|
||||
mitsubishi KEYWORD2
|
||||
mitsubishi112 KEYWORD2
|
||||
mitsubishi136 KEYWORD2
|
||||
|
@ -532,15 +554,18 @@ resultToSourceCode KEYWORD2
|
|||
resultToTimingInfo KEYWORD2
|
||||
resume KEYWORD2
|
||||
reverseBits KEYWORD2
|
||||
rhoss KEYWORD2
|
||||
samsung KEYWORD2
|
||||
sanyo KEYWORD2
|
||||
sanyo88 KEYWORD2
|
||||
send KEYWORD2
|
||||
sendAc KEYWORD2
|
||||
sendAirton KEYWORD2
|
||||
sendAirwell KEYWORD2
|
||||
sendAiwaRCT501 KEYWORD2
|
||||
sendAmcor KEYWORD2
|
||||
sendArgo KEYWORD2
|
||||
sendArris KEYWORD2
|
||||
sendBose KEYWORD2
|
||||
sendCOOLIX KEYWORD2
|
||||
sendCarrierAC KEYWORD2
|
||||
|
@ -621,6 +646,7 @@ sendRC5 KEYWORD2
|
|||
sendRC6 KEYWORD2
|
||||
sendRCMM KEYWORD2
|
||||
sendRaw KEYWORD2
|
||||
sendRhoss KEYWORD2
|
||||
sendSAMSUNG KEYWORD2
|
||||
sendSamsung36 KEYWORD2
|
||||
sendSamsungAC KEYWORD2
|
||||
|
@ -662,6 +688,7 @@ setBreeze KEYWORD2
|
|||
setButton KEYWORD2
|
||||
setCelsius KEYWORD2
|
||||
setClean KEYWORD2
|
||||
setCleanToggle KEYWORD2
|
||||
setClock KEYWORD2
|
||||
setCmd KEYWORD2
|
||||
setComfort KEYWORD2
|
||||
|
@ -697,6 +724,7 @@ setIonFilter KEYWORD2
|
|||
setLed KEYWORD2
|
||||
setLight KEYWORD2
|
||||
setLightToggle KEYWORD2
|
||||
setLock KEYWORD2
|
||||
setMax KEYWORD2
|
||||
setMode KEYWORD2
|
||||
setModel KEYWORD2
|
||||
|
@ -725,6 +753,7 @@ setSave KEYWORD2
|
|||
setSensor KEYWORD2
|
||||
setSensorTemp KEYWORD2
|
||||
setSensorTempRaw KEYWORD2
|
||||
setSensorUpdate KEYWORD2
|
||||
setSilent KEYWORD2
|
||||
setSleep KEYWORD2
|
||||
setSleepTimer KEYWORD2
|
||||
|
@ -791,6 +820,7 @@ teco KEYWORD2
|
|||
ticksHigh KEYWORD2
|
||||
ticksLow KEYWORD2
|
||||
toString KEYWORD2
|
||||
toggleArrisRelease KEYWORD2
|
||||
toggleRC5 KEYWORD2
|
||||
toggleRC6 KEYWORD2
|
||||
toggleSwingHoriz KEYWORD2
|
||||
|
@ -821,6 +851,7 @@ xorBytes KEYWORD2
|
|||
A705 LITERAL1
|
||||
A903 LITERAL1
|
||||
A907 LITERAL1
|
||||
AIRTON LITERAL1
|
||||
AIRWELL LITERAL1
|
||||
AIWA_RC_T501 LITERAL1
|
||||
AIWA_RC_T501_BITS LITERAL1
|
||||
|
@ -857,6 +888,7 @@ ARJW2 LITERAL1
|
|||
ARRAH2E LITERAL1
|
||||
ARREB1E LITERAL1
|
||||
ARREW4E LITERAL1
|
||||
ARRIS LITERAL1
|
||||
ARRY4 LITERAL1
|
||||
BOSE LITERAL1
|
||||
CARRIER_AC LITERAL1
|
||||
|
@ -887,10 +919,12 @@ DAIKIN_HEAT LITERAL1
|
|||
DAIKIN_MAX_TEMP LITERAL1
|
||||
DAIKIN_MIN_TEMP LITERAL1
|
||||
DECODE_AC LITERAL1
|
||||
DECODE_AIRTON LITERAL1
|
||||
DECODE_AIRWELL LITERAL1
|
||||
DECODE_AIWA_RC_T501 LITERAL1
|
||||
DECODE_AMCOR LITERAL1
|
||||
DECODE_ARGO LITERAL1
|
||||
DECODE_ARRIS LITERAL1
|
||||
DECODE_BOSE LITERAL1
|
||||
DECODE_CARRIER_AC LITERAL1
|
||||
DECODE_CARRIER_AC40 LITERAL1
|
||||
|
@ -961,6 +995,7 @@ DECODE_PRONTO LITERAL1
|
|||
DECODE_RC5 LITERAL1
|
||||
DECODE_RC6 LITERAL1
|
||||
DECODE_RCMM LITERAL1
|
||||
DECODE_RHOSS LITERAL1
|
||||
DECODE_SAMSUNG LITERAL1
|
||||
DECODE_SAMSUNG36 LITERAL1
|
||||
DECODE_SAMSUNG_AC LITERAL1
|
||||
|
@ -1054,6 +1089,7 @@ GREE_SWING_MIDDLE_DOWN LITERAL1
|
|||
GREE_SWING_MIDDLE_UP LITERAL1
|
||||
GREE_SWING_UP LITERAL1
|
||||
GREE_SWING_UP_AUTO LITERAL1
|
||||
GZ055BE1 LITERAL1
|
||||
HAIER_AC LITERAL1
|
||||
HAIER_AC176 LITERAL1
|
||||
HAIER_AC_AUTO LITERAL1
|
||||
|
@ -1063,7 +1099,7 @@ HAIER_AC_CMD_MODE LITERAL1
|
|||
HAIER_AC_CMD_OFF LITERAL1
|
||||
HAIER_AC_CMD_ON LITERAL1
|
||||
HAIER_AC_CMD_SLEEP LITERAL1
|
||||
HAIER_AC_CMD_SWING LITERAL1
|
||||
HAIER_AC_CMD_SWINGV LITERAL1
|
||||
HAIER_AC_CMD_TEMP_DOWN LITERAL1
|
||||
HAIER_AC_CMD_TEMP_UP LITERAL1
|
||||
HAIER_AC_CMD_TIMER_CANCEL LITERAL1
|
||||
|
@ -1080,10 +1116,10 @@ HAIER_AC_HEAT LITERAL1
|
|||
HAIER_AC_MAX_TEMP LITERAL1
|
||||
HAIER_AC_MIN_TEMP LITERAL1
|
||||
HAIER_AC_STATE_LENGTH LITERAL1
|
||||
HAIER_AC_SWING_CHG LITERAL1
|
||||
HAIER_AC_SWING_DOWN LITERAL1
|
||||
HAIER_AC_SWING_OFF LITERAL1
|
||||
HAIER_AC_SWING_UP LITERAL1
|
||||
HAIER_AC_SWINGV_CHG LITERAL1
|
||||
HAIER_AC_SWINGV_DOWN LITERAL1
|
||||
HAIER_AC_SWINGV_OFF LITERAL1
|
||||
HAIER_AC_SWINGV_UP LITERAL1
|
||||
HAIER_AC_YRW02 LITERAL1
|
||||
HAIER_AC_YRW02_AUTO LITERAL1
|
||||
HAIER_AC_YRW02_BUTTON_FAN LITERAL1
|
||||
|
@ -1110,8 +1146,6 @@ HAIER_AC_YRW02_SWING_DOWN LITERAL1
|
|||
HAIER_AC_YRW02_SWING_MIDDLE LITERAL1
|
||||
HAIER_AC_YRW02_SWING_OFF LITERAL1
|
||||
HAIER_AC_YRW02_SWING_TOP LITERAL1
|
||||
HAIER_AC_YRW02_TURBO_HIGH LITERAL1
|
||||
HAIER_AC_YRW02_TURBO_LOW LITERAL1
|
||||
HAIER_AC_YRW02_TURBO_OFF LITERAL1
|
||||
HIGH LITERAL1
|
||||
HITACHI_AC LITERAL1
|
||||
|
@ -1144,6 +1178,8 @@ KELVINATOR_HEAT LITERAL1
|
|||
KELVINATOR_MAX_TEMP LITERAL1
|
||||
KELVINATOR_MIN_TEMP LITERAL1
|
||||
KELVINATOR_STATE_LENGTH LITERAL1
|
||||
KKG29AC1 LITERAL1
|
||||
KKG9AC1 LITERAL1
|
||||
LASERTAG LITERAL1
|
||||
LASERTAG_BITS LITERAL1
|
||||
LEGOPF LITERAL1
|
||||
|
@ -1224,6 +1260,7 @@ RC6_36_BITS LITERAL1
|
|||
RC6_MODE0_BITS LITERAL1
|
||||
RCMM LITERAL1
|
||||
RCMM_BITS LITERAL1
|
||||
RHOSS LITERAL1
|
||||
R_LT0541_HTA_A LITERAL1
|
||||
R_LT0541_HTA_B LITERAL1
|
||||
SAMSUNG LITERAL1
|
||||
|
@ -1236,10 +1273,12 @@ SANYO_AC88 LITERAL1
|
|||
SANYO_LC7461 LITERAL1
|
||||
SANYO_LC7461_BITS LITERAL1
|
||||
SANYO_SA8650B_BITS LITERAL1
|
||||
SEND_AIRTON LITERAL1
|
||||
SEND_AIRWELL LITERAL1
|
||||
SEND_AIWA_RC_T501 LITERAL1
|
||||
SEND_AMCOR LITERAL1
|
||||
SEND_ARGO LITERAL1
|
||||
SEND_ARRIS LITERAL1
|
||||
SEND_BOSE LITERAL1
|
||||
SEND_CARRIER_AC LITERAL1
|
||||
SEND_CARRIER_AC40 LITERAL1
|
||||
|
@ -1310,6 +1349,7 @@ SEND_RAW LITERAL1
|
|||
SEND_RC5 LITERAL1
|
||||
SEND_RC6 LITERAL1
|
||||
SEND_RCMM LITERAL1
|
||||
SEND_RHOSS LITERAL1
|
||||
SEND_SAMSUNG LITERAL1
|
||||
SEND_SAMSUNG36 LITERAL1
|
||||
SEND_SAMSUNG_AC LITERAL1
|
||||
|
@ -1347,6 +1387,7 @@ SONY_15_BITS LITERAL1
|
|||
SONY_20_BITS LITERAL1
|
||||
SONY_38K LITERAL1
|
||||
SYMPHONY LITERAL1
|
||||
TAC09CHSD LITERAL1
|
||||
TCL112AC LITERAL1
|
||||
TECHNIBEL_AC LITERAL1
|
||||
TECO LITERAL1
|
||||
|
@ -1381,6 +1422,8 @@ TRUMA LITERAL1
|
|||
UNKNOWN LITERAL1
|
||||
UNUSED LITERAL1
|
||||
USE_IRAM_ATTR LITERAL1
|
||||
V9014557_A LITERAL1
|
||||
V9014557_B LITERAL1
|
||||
VESTEL_AC LITERAL1
|
||||
VOLTAS LITERAL1
|
||||
WHIRLPOOL_AC LITERAL1
|
||||
|
@ -1390,11 +1433,25 @@ XMP LITERAL1
|
|||
YAW1F LITERAL1
|
||||
YBOFB LITERAL1
|
||||
ZEPEAL LITERAL1
|
||||
k0Str LITERAL1
|
||||
k10CHeatStr LITERAL1
|
||||
k122lzfStr LITERAL1
|
||||
k1Str LITERAL1
|
||||
k3DStr LITERAL1
|
||||
k6thSenseStr LITERAL1
|
||||
k8CHeatStr LITERAL1
|
||||
kA705Str LITERAL1
|
||||
kA903Str LITERAL1
|
||||
kA907Str LITERAL1
|
||||
kAirFlowStr LITERAL1
|
||||
kAirtonBitMark LITERAL1
|
||||
kAirtonBits LITERAL1
|
||||
kAirtonDefaultRepeat LITERAL1
|
||||
kAirtonFreq LITERAL1
|
||||
kAirtonHdrMark LITERAL1
|
||||
kAirtonHdrSpace LITERAL1
|
||||
kAirtonOneSpace LITERAL1
|
||||
kAirtonZeroSpace LITERAL1
|
||||
kAirwellAuto LITERAL1
|
||||
kAirwellBits LITERAL1
|
||||
kAirwellCool LITERAL1
|
||||
|
@ -1420,6 +1477,9 @@ kAiwaRcT501PostBits LITERAL1
|
|||
kAiwaRcT501PostData LITERAL1
|
||||
kAiwaRcT501PreBits LITERAL1
|
||||
kAiwaRcT501PreData LITERAL1
|
||||
kAkb73757604Str LITERAL1
|
||||
kAkb74955603Str LITERAL1
|
||||
kAkb75215403Str LITERAL1
|
||||
kAllProtocolNamesStr LITERAL1
|
||||
kAlokaBits LITERAL1
|
||||
kAlokaLedBlue LITERAL1
|
||||
|
@ -1464,6 +1524,7 @@ kAmcorTolerance LITERAL1
|
|||
kAmcorVentOn LITERAL1
|
||||
kAmcorZeroMark LITERAL1
|
||||
kAmcorZeroSpace LITERAL1
|
||||
kArdb1Str LITERAL1
|
||||
kArgoAuto LITERAL1
|
||||
kArgoBitMark LITERAL1
|
||||
kArgoBits LITERAL1
|
||||
|
@ -1497,6 +1558,21 @@ kArgoOneSpace LITERAL1
|
|||
kArgoStateLength LITERAL1
|
||||
kArgoTempDelta LITERAL1
|
||||
kArgoZeroSpace LITERAL1
|
||||
kArjw2Str LITERAL1
|
||||
kArrah2eStr LITERAL1
|
||||
kArreb1eStr LITERAL1
|
||||
kArrew4eStr LITERAL1
|
||||
kArrisBits LITERAL1
|
||||
kArrisChecksumSize LITERAL1
|
||||
kArrisCommandSize LITERAL1
|
||||
kArrisGapSpace LITERAL1
|
||||
kArrisHalfClockPeriod LITERAL1
|
||||
kArrisHdrMark LITERAL1
|
||||
kArrisHdrSpace LITERAL1
|
||||
kArrisOverhead LITERAL1
|
||||
kArrisReleaseBit LITERAL1
|
||||
kArrisReleaseToggle LITERAL1
|
||||
kArry4Str LITERAL1
|
||||
kAuto LITERAL1
|
||||
kAutoStr LITERAL1
|
||||
kAutomaticStr LITERAL1
|
||||
|
@ -1558,6 +1634,7 @@ kCelsiusStr LITERAL1
|
|||
kCentreStr LITERAL1
|
||||
kChangeStr LITERAL1
|
||||
kCirculateStr LITERAL1
|
||||
kCkpStr LITERAL1
|
||||
kCleanStr LITERAL1
|
||||
kClockStr LITERAL1
|
||||
kCodeStr LITERAL1
|
||||
|
@ -1567,6 +1644,7 @@ kCommaSpaceStr LITERAL1
|
|||
kCommandStr LITERAL1
|
||||
kCool LITERAL1
|
||||
kCoolStr LITERAL1
|
||||
kCoolingStr LITERAL1
|
||||
kCoolixAuto LITERAL1
|
||||
kCoolixBitMark LITERAL1
|
||||
kCoolixBitMarkTicks LITERAL1
|
||||
|
@ -1866,10 +1944,12 @@ kDaikinSwingOn LITERAL1
|
|||
kDaikinTolerance LITERAL1
|
||||
kDaikinUnusedTime LITERAL1
|
||||
kDaikinZeroSpace LITERAL1
|
||||
kDashStr LITERAL1
|
||||
kDayStr LITERAL1
|
||||
kDaysStr LITERAL1
|
||||
kDefaultESP32Timer LITERAL1
|
||||
kDefaultMessageGap LITERAL1
|
||||
kDehumidifyStr LITERAL1
|
||||
kDelonghiAcAuto LITERAL1
|
||||
kDelonghiAcBitMark LITERAL1
|
||||
kDelonghiAcBits LITERAL1
|
||||
|
@ -1914,6 +1994,9 @@ kDenonOneSpaceTicks LITERAL1
|
|||
kDenonTick LITERAL1
|
||||
kDenonZeroSpace LITERAL1
|
||||
kDenonZeroSpaceTicks LITERAL1
|
||||
kDg11j104Str LITERAL1
|
||||
kDg11j13aStr LITERAL1
|
||||
kDg11j191Str LITERAL1
|
||||
kDishBitMark LITERAL1
|
||||
kDishBitMarkTicks LITERAL1
|
||||
kDishBits LITERAL1
|
||||
|
@ -1930,6 +2013,7 @@ kDishTick LITERAL1
|
|||
kDishZeroSpace LITERAL1
|
||||
kDishZeroSpaceTicks LITERAL1
|
||||
kDisplayTempStr LITERAL1
|
||||
kDkeStr LITERAL1
|
||||
kDoshishaBitMark LITERAL1
|
||||
kDoshishaBits LITERAL1
|
||||
kDoshishaHdrMark LITERAL1
|
||||
|
@ -1939,6 +2023,7 @@ kDoshishaZeroSpace LITERAL1
|
|||
kDownStr LITERAL1
|
||||
kDry LITERAL1
|
||||
kDryStr LITERAL1
|
||||
kDryingStr LITERAL1
|
||||
kDutyDefault LITERAL1
|
||||
kDutyMax LITERAL1
|
||||
kEcoclimAuto LITERAL1
|
||||
|
@ -1992,6 +2077,9 @@ kElectraAcMessageGap LITERAL1
|
|||
kElectraAcMinRepeat LITERAL1
|
||||
kElectraAcMinTemp LITERAL1
|
||||
kElectraAcOneSpace LITERAL1
|
||||
kElectraAcSensorMaxTemp LITERAL1
|
||||
kElectraAcSensorMinTemp LITERAL1
|
||||
kElectraAcSensorTempDelta LITERAL1
|
||||
kElectraAcStateLength LITERAL1
|
||||
kElectraAcSwingOff LITERAL1
|
||||
kElectraAcSwingOn LITERAL1
|
||||
|
@ -2008,8 +2096,11 @@ kEyeAutoStr LITERAL1
|
|||
kEyeStr LITERAL1
|
||||
kFalseStr LITERAL1
|
||||
kFan LITERAL1
|
||||
kFanOnlyNoSpaceStr LITERAL1
|
||||
kFanOnlyStr LITERAL1
|
||||
kFanOnlyWithSpaceStr LITERAL1
|
||||
kFanStr LITERAL1
|
||||
kFan_OnlyStr LITERAL1
|
||||
kFastStr LITERAL1
|
||||
kFilterStr LITERAL1
|
||||
kFixedStr LITERAL1
|
||||
|
@ -2064,6 +2155,7 @@ kFujitsuAcTempOffsetC LITERAL1
|
|||
kFujitsuAcTempOffsetF LITERAL1
|
||||
kFujitsuAcTimerMax LITERAL1
|
||||
kFujitsuAcZeroSpace LITERAL1
|
||||
kGe6711ar2853mStr LITERAL1
|
||||
kGicableBitMark LITERAL1
|
||||
kGicableBits LITERAL1
|
||||
kGicableHdrMark LITERAL1
|
||||
|
@ -2146,6 +2238,13 @@ kGreeStateLength LITERAL1
|
|||
kGreeSwingAuto LITERAL1
|
||||
kGreeSwingDown LITERAL1
|
||||
kGreeSwingDownAuto LITERAL1
|
||||
kGreeSwingHAuto LITERAL1
|
||||
kGreeSwingHLeft LITERAL1
|
||||
kGreeSwingHMaxLeft LITERAL1
|
||||
kGreeSwingHMaxRight LITERAL1
|
||||
kGreeSwingHMiddle LITERAL1
|
||||
kGreeSwingHOff LITERAL1
|
||||
kGreeSwingHRight LITERAL1
|
||||
kGreeSwingLastPos LITERAL1
|
||||
kGreeSwingMiddle LITERAL1
|
||||
kGreeSwingMiddleAuto LITERAL1
|
||||
|
@ -2155,6 +2254,7 @@ kGreeSwingUp LITERAL1
|
|||
kGreeSwingUpAuto LITERAL1
|
||||
kGreeTimerMax LITERAL1
|
||||
kGreeZeroSpace LITERAL1
|
||||
kGz055be1Str LITERAL1
|
||||
kHaierAC176Bits LITERAL1
|
||||
kHaierAC176StateLength LITERAL1
|
||||
kHaierACBits LITERAL1
|
||||
|
@ -2195,21 +2295,26 @@ kHaierAcMinTemp LITERAL1
|
|||
kHaierAcOneSpace LITERAL1
|
||||
kHaierAcPrefix LITERAL1
|
||||
kHaierAcSleepBit LITERAL1
|
||||
kHaierAcSwingChg LITERAL1
|
||||
kHaierAcSwingDown LITERAL1
|
||||
kHaierAcSwingOff LITERAL1
|
||||
kHaierAcSwingUp LITERAL1
|
||||
kHaierAcSwingVChg LITERAL1
|
||||
kHaierAcSwingVDown LITERAL1
|
||||
kHaierAcSwingVOff LITERAL1
|
||||
kHaierAcSwingVUp LITERAL1
|
||||
kHaierAcYrw02Auto LITERAL1
|
||||
kHaierAcYrw02ButtonCFAB LITERAL1
|
||||
kHaierAcYrw02ButtonFan LITERAL1
|
||||
kHaierAcYrw02ButtonHealth LITERAL1
|
||||
kHaierAcYrw02ButtonLock LITERAL1
|
||||
kHaierAcYrw02ButtonMode LITERAL1
|
||||
kHaierAcYrw02ButtonPower LITERAL1
|
||||
kHaierAcYrw02ButtonSleep LITERAL1
|
||||
kHaierAcYrw02ButtonSwing LITERAL1
|
||||
kHaierAcYrw02ButtonSwingH LITERAL1
|
||||
kHaierAcYrw02ButtonSwingV LITERAL1
|
||||
kHaierAcYrw02ButtonTempDown LITERAL1
|
||||
kHaierAcYrw02ButtonTempUp LITERAL1
|
||||
kHaierAcYrw02ButtonTimer LITERAL1
|
||||
kHaierAcYrw02ButtonTurbo LITERAL1
|
||||
kHaierAcYrw02Cool LITERAL1
|
||||
kHaierAcYrw02DefTempC LITERAL1
|
||||
kHaierAcYrw02DefaultRepeat LITERAL1
|
||||
kHaierAcYrw02Dry LITERAL1
|
||||
kHaierAcYrw02Fan LITERAL1
|
||||
|
@ -2218,26 +2323,35 @@ kHaierAcYrw02FanHigh LITERAL1
|
|||
kHaierAcYrw02FanLow LITERAL1
|
||||
kHaierAcYrw02FanMed LITERAL1
|
||||
kHaierAcYrw02Heat LITERAL1
|
||||
kHaierAcYrw02MaxTempC LITERAL1
|
||||
kHaierAcYrw02MaxTempF LITERAL1
|
||||
kHaierAcYrw02MinTempC LITERAL1
|
||||
kHaierAcYrw02MinTempF LITERAL1
|
||||
kHaierAcYrw02ModelA LITERAL1
|
||||
kHaierAcYrw02ModelB LITERAL1
|
||||
kHaierAcYrw02NoTimers LITERAL1
|
||||
kHaierAcYrw02OffThenOnTimer LITERAL1
|
||||
kHaierAcYrw02OffTimer LITERAL1
|
||||
kHaierAcYrw02OnThenOffTimer LITERAL1
|
||||
kHaierAcYrw02OnTimer LITERAL1
|
||||
kHaierAcYrw02Prefix LITERAL1
|
||||
kHaierAcYrw02SwingAuto LITERAL1
|
||||
kHaierAcYrw02SwingBottom LITERAL1
|
||||
kHaierAcYrw02SwingDown LITERAL1
|
||||
kHaierAcYrw02SwingMiddle LITERAL1
|
||||
kHaierAcYrw02SwingOff LITERAL1
|
||||
kHaierAcYrw02SwingTop LITERAL1
|
||||
kHaierAcYrw02TurboHigh LITERAL1
|
||||
kHaierAcYrw02TurboLow LITERAL1
|
||||
kHaierAcYrw02TurboOff LITERAL1
|
||||
kHaierAcYrw02SwingHAuto LITERAL1
|
||||
kHaierAcYrw02SwingHLeft LITERAL1
|
||||
kHaierAcYrw02SwingHLeftMax LITERAL1
|
||||
kHaierAcYrw02SwingHMiddle LITERAL1
|
||||
kHaierAcYrw02SwingHRight LITERAL1
|
||||
kHaierAcYrw02SwingHRightMax LITERAL1
|
||||
kHaierAcYrw02SwingVAuto LITERAL1
|
||||
kHaierAcYrw02SwingVBottom LITERAL1
|
||||
kHaierAcYrw02SwingVDown LITERAL1
|
||||
kHaierAcYrw02SwingVMiddle LITERAL1
|
||||
kHaierAcYrw02SwingVOff LITERAL1
|
||||
kHaierAcYrw02SwingVTop LITERAL1
|
||||
kHaierAcZeroSpace LITERAL1
|
||||
kHeader LITERAL1
|
||||
kHealthStr LITERAL1
|
||||
kHeat LITERAL1
|
||||
kHeatStr LITERAL1
|
||||
kHeatingStr LITERAL1
|
||||
kHiStr LITERAL1
|
||||
kHigh LITERAL1
|
||||
kHighNibble LITERAL1
|
||||
|
@ -2377,6 +2491,7 @@ kInaxTick LITERAL1
|
|||
kInaxZeroSpace LITERAL1
|
||||
kInsideStr LITERAL1
|
||||
kIonStr LITERAL1
|
||||
kJkeStr LITERAL1
|
||||
kJvcBitMark LITERAL1
|
||||
kJvcBitMarkTicks LITERAL1
|
||||
kJvcBits LITERAL1
|
||||
|
@ -2445,6 +2560,8 @@ kKelvinatorStateLength LITERAL1
|
|||
kKelvinatorTick LITERAL1
|
||||
kKelvinatorZeroSpace LITERAL1
|
||||
kKelvinatorZeroSpaceTicks LITERAL1
|
||||
kKkg29ac1Str LITERAL1
|
||||
kKkg9ac1Str LITERAL1
|
||||
kLasertagBits LITERAL1
|
||||
kLasertagDelta LITERAL1
|
||||
kLasertagExcess LITERAL1
|
||||
|
@ -2461,6 +2578,7 @@ kLastSwinghEnum LITERAL1
|
|||
kLastSwingvEnum LITERAL1
|
||||
kLeft LITERAL1
|
||||
kLeftMax LITERAL1
|
||||
kLeftMaxNoSpaceStr LITERAL1
|
||||
kLeftMaxStr LITERAL1
|
||||
kLeftStr LITERAL1
|
||||
kLegoPfBitMark LITERAL1
|
||||
|
@ -2544,7 +2662,9 @@ kLgRptSpace LITERAL1
|
|||
kLgZeroSpace LITERAL1
|
||||
kLightStr LITERAL1
|
||||
kLightToggleStr LITERAL1
|
||||
kLkeStr LITERAL1
|
||||
kLoStr LITERAL1
|
||||
kLockStr LITERAL1
|
||||
kLoudStr LITERAL1
|
||||
kLow LITERAL1
|
||||
kLowNibble LITERAL1
|
||||
|
@ -2578,7 +2698,9 @@ kMarkExcess LITERAL1
|
|||
kMarkState LITERAL1
|
||||
kMax LITERAL1
|
||||
kMaxAccurateUsecDelay LITERAL1
|
||||
kMaxLeftNoSpaceStr LITERAL1
|
||||
kMaxLeftStr LITERAL1
|
||||
kMaxRightNoSpaceStr LITERAL1
|
||||
kMaxRightStr LITERAL1
|
||||
kMaxStr LITERAL1
|
||||
kMaxTimeoutMs LITERAL1
|
||||
|
@ -2661,6 +2783,34 @@ kMinStr LITERAL1
|
|||
kMinimumStr LITERAL1
|
||||
kMinuteStr LITERAL1
|
||||
kMinutesStr LITERAL1
|
||||
kMirageAcCool LITERAL1
|
||||
kMirageAcDry LITERAL1
|
||||
kMirageAcFan LITERAL1
|
||||
kMirageAcFanAuto LITERAL1
|
||||
kMirageAcFanHigh LITERAL1
|
||||
kMirageAcFanLow LITERAL1
|
||||
kMirageAcFanMed LITERAL1
|
||||
kMirageAcHeat LITERAL1
|
||||
kMirageAcKKG29AC1FanAuto LITERAL1
|
||||
kMirageAcKKG29AC1FanHigh LITERAL1
|
||||
kMirageAcKKG29AC1FanLow LITERAL1
|
||||
kMirageAcKKG29AC1FanMed LITERAL1
|
||||
kMirageAcKKG29AC1PowerOff LITERAL1
|
||||
kMirageAcKKG29AC1PowerOn LITERAL1
|
||||
kMirageAcMaxTemp LITERAL1
|
||||
kMirageAcMinTemp LITERAL1
|
||||
kMirageAcPowerOff LITERAL1
|
||||
kMirageAcRecycle LITERAL1
|
||||
kMirageAcSensorTempMax LITERAL1
|
||||
kMirageAcSensorTempOffset LITERAL1
|
||||
kMirageAcSwingVAuto LITERAL1
|
||||
kMirageAcSwingVHigh LITERAL1
|
||||
kMirageAcSwingVHighest LITERAL1
|
||||
kMirageAcSwingVLow LITERAL1
|
||||
kMirageAcSwingVLowest LITERAL1
|
||||
kMirageAcSwingVMiddle LITERAL1
|
||||
kMirageAcSwingVOff LITERAL1
|
||||
kMirageAcTempOffset LITERAL1
|
||||
kMirageBitMark LITERAL1
|
||||
kMirageBits LITERAL1
|
||||
kMirageFreq LITERAL1
|
||||
|
@ -2954,6 +3104,7 @@ kNikaiOneSpaceTicks LITERAL1
|
|||
kNikaiTick LITERAL1
|
||||
kNikaiZeroSpace LITERAL1
|
||||
kNikaiZeroSpaceTicks LITERAL1
|
||||
kNkeStr LITERAL1
|
||||
kNoRepeat LITERAL1
|
||||
kNoStr LITERAL1
|
||||
kNowStr LITERAL1
|
||||
|
@ -3042,20 +3193,27 @@ kPanasonicAcTolerance LITERAL1
|
|||
kPanasonicBitMark LITERAL1
|
||||
kPanasonicBits LITERAL1
|
||||
kPanasonicCkp LITERAL1
|
||||
kPanasonicCkpStr LITERAL1
|
||||
kPanasonicDke LITERAL1
|
||||
kPanasonicDkeStr LITERAL1
|
||||
kPanasonicEndGap LITERAL1
|
||||
kPanasonicFreq LITERAL1
|
||||
kPanasonicHdrMark LITERAL1
|
||||
kPanasonicHdrSpace LITERAL1
|
||||
kPanasonicJke LITERAL1
|
||||
kPanasonicJkeStr LITERAL1
|
||||
kPanasonicKnownGoodState LITERAL1
|
||||
kPanasonicLke LITERAL1
|
||||
kPanasonicLkeStr LITERAL1
|
||||
kPanasonicManufacturer LITERAL1
|
||||
kPanasonicMinCommandLength LITERAL1
|
||||
kPanasonicMinGap LITERAL1
|
||||
kPanasonicNke LITERAL1
|
||||
kPanasonicNkeStr LITERAL1
|
||||
kPanasonicOneSpace LITERAL1
|
||||
kPanasonicPkrStr LITERAL1
|
||||
kPanasonicRkr LITERAL1
|
||||
kPanasonicRkrStr LITERAL1
|
||||
kPanasonicUnknown LITERAL1
|
||||
kPanasonicZeroSpace LITERAL1
|
||||
kPeriodOffset LITERAL1
|
||||
|
@ -3068,6 +3226,7 @@ kPioneerMinGap LITERAL1
|
|||
kPioneerOneSpace LITERAL1
|
||||
kPioneerTick LITERAL1
|
||||
kPioneerZeroSpace LITERAL1
|
||||
kPkrStr LITERAL1
|
||||
kPowerButtonStr LITERAL1
|
||||
kPowerStr LITERAL1
|
||||
kPowerToggleStr LITERAL1
|
||||
|
@ -3145,10 +3304,44 @@ kRcz01SignatureMask LITERAL1
|
|||
kRecycleStr LITERAL1
|
||||
kRepeat LITERAL1
|
||||
kRepeatStr LITERAL1
|
||||
kRhossBitMark LITERAL1
|
||||
kRhossBits LITERAL1
|
||||
kRhossDefaultFan LITERAL1
|
||||
kRhossDefaultMode LITERAL1
|
||||
kRhossDefaultPower LITERAL1
|
||||
kRhossDefaultRepeat LITERAL1
|
||||
kRhossDefaultSwing LITERAL1
|
||||
kRhossDefaultTemp LITERAL1
|
||||
kRhossFanAuto LITERAL1
|
||||
kRhossFanMax LITERAL1
|
||||
kRhossFanMed LITERAL1
|
||||
kRhossFanMin LITERAL1
|
||||
kRhossFreq LITERAL1
|
||||
kRhossGap LITERAL1
|
||||
kRhossHdrMark LITERAL1
|
||||
kRhossHdrSpace LITERAL1
|
||||
kRhossModeAuto LITERAL1
|
||||
kRhossModeCool LITERAL1
|
||||
kRhossModeDry LITERAL1
|
||||
kRhossModeFan LITERAL1
|
||||
kRhossModeHeat LITERAL1
|
||||
kRhossOneSpace LITERAL1
|
||||
kRhossPowerOff LITERAL1
|
||||
kRhossPowerOn LITERAL1
|
||||
kRhossStateLength LITERAL1
|
||||
kRhossSwingOff LITERAL1
|
||||
kRhossSwingOn LITERAL1
|
||||
kRhossTempMax LITERAL1
|
||||
kRhossTempMin LITERAL1
|
||||
kRhossZeroSpace LITERAL1
|
||||
kRight LITERAL1
|
||||
kRightMax LITERAL1
|
||||
kRightMaxNoSpaceStr LITERAL1
|
||||
kRightMaxStr LITERAL1
|
||||
kRightStr LITERAL1
|
||||
kRkrStr LITERAL1
|
||||
kRlt0541htaaStr LITERAL1
|
||||
kRlt0541htabStr LITERAL1
|
||||
kRoomStr LITERAL1
|
||||
kSamsung36BitMark LITERAL1
|
||||
kSamsung36Bits LITERAL1
|
||||
|
@ -3164,6 +3357,7 @@ kSamsungAcBreezeOn LITERAL1
|
|||
kSamsungAcCool LITERAL1
|
||||
kSamsungAcDefaultRepeat LITERAL1
|
||||
kSamsungAcDry LITERAL1
|
||||
kSamsungAcEconoOn LITERAL1
|
||||
kSamsungAcExtendedBits LITERAL1
|
||||
kSamsungAcExtendedStateLength LITERAL1
|
||||
kSamsungAcFan LITERAL1
|
||||
|
@ -3172,6 +3366,7 @@ kSamsungAcFanAuto2 LITERAL1
|
|||
kSamsungAcFanHigh LITERAL1
|
||||
kSamsungAcFanLow LITERAL1
|
||||
kSamsungAcFanMed LITERAL1
|
||||
kSamsungAcFanSpecialOff LITERAL1
|
||||
kSamsungAcFanTurbo LITERAL1
|
||||
kSamsungAcHdrMark LITERAL1
|
||||
kSamsungAcHdrSpace LITERAL1
|
||||
|
@ -3180,16 +3375,17 @@ kSamsungAcMaxTemp LITERAL1
|
|||
kSamsungAcMinTemp LITERAL1
|
||||
kSamsungAcOneSpace LITERAL1
|
||||
kSamsungAcPowerSection LITERAL1
|
||||
kSamsungAcPowerful10On LITERAL1
|
||||
kSamsungAcPowerfulMask8 LITERAL1
|
||||
kSamsungAcPowerfulOn LITERAL1
|
||||
kSamsungAcSectionGap LITERAL1
|
||||
kSamsungAcSectionLength LITERAL1
|
||||
kSamsungAcSectionMark LITERAL1
|
||||
kSamsungAcSectionSpace LITERAL1
|
||||
kSamsungAcSections LITERAL1
|
||||
kSamsungAcStateLength LITERAL1
|
||||
kSamsungAcSwingMove LITERAL1
|
||||
kSamsungAcSwingStop LITERAL1
|
||||
kSamsungAcSwingBoth LITERAL1
|
||||
kSamsungAcSwingH LITERAL1
|
||||
kSamsungAcSwingOff LITERAL1
|
||||
kSamsungAcSwingV LITERAL1
|
||||
kSamsungAcZeroSpace LITERAL1
|
||||
kSamsungBitMark LITERAL1
|
||||
kSamsungBitMarkTicks LITERAL1
|
||||
|
@ -3326,8 +3522,15 @@ kSharpAcSpecialTimer LITERAL1
|
|||
kSharpAcSpecialTimerHalfHour LITERAL1
|
||||
kSharpAcSpecialTurbo LITERAL1
|
||||
kSharpAcStateLength LITERAL1
|
||||
kSharpAcSwingNoToggle LITERAL1
|
||||
kSharpAcSwingToggle LITERAL1
|
||||
kSharpAcSwingVCoanda LITERAL1
|
||||
kSharpAcSwingVHigh LITERAL1
|
||||
kSharpAcSwingVIgnore LITERAL1
|
||||
kSharpAcSwingVLast LITERAL1
|
||||
kSharpAcSwingVLow LITERAL1
|
||||
kSharpAcSwingVLowest LITERAL1
|
||||
kSharpAcSwingVMid LITERAL1
|
||||
kSharpAcSwingVOff LITERAL1
|
||||
kSharpAcSwingVToggle LITERAL1
|
||||
kSharpAcTimerHoursMax LITERAL1
|
||||
kSharpAcTimerHoursOff LITERAL1
|
||||
kSharpAcTimerIncrement LITERAL1
|
||||
|
@ -3397,6 +3600,7 @@ kSymphonyOneMark LITERAL1
|
|||
kSymphonyOneSpace LITERAL1
|
||||
kSymphonyZeroMark LITERAL1
|
||||
kSymphonyZeroSpace LITERAL1
|
||||
kTac09chsdStr LITERAL1
|
||||
kTcl112AcAuto LITERAL1
|
||||
kTcl112AcBitMark LITERAL1
|
||||
kTcl112AcBits LITERAL1
|
||||
|
@ -3408,6 +3612,9 @@ kTcl112AcFanAuto LITERAL1
|
|||
kTcl112AcFanHigh LITERAL1
|
||||
kTcl112AcFanLow LITERAL1
|
||||
kTcl112AcFanMed LITERAL1
|
||||
kTcl112AcFanMin LITERAL1
|
||||
kTcl112AcFanNight LITERAL1
|
||||
kTcl112AcFanQuiet LITERAL1
|
||||
kTcl112AcGap LITERAL1
|
||||
kTcl112AcHdrMark LITERAL1
|
||||
kTcl112AcHdrMarkTolerance LITERAL1
|
||||
|
@ -3417,10 +3624,17 @@ kTcl112AcNormal LITERAL1
|
|||
kTcl112AcOneSpace LITERAL1
|
||||
kTcl112AcSpecial LITERAL1
|
||||
kTcl112AcStateLength LITERAL1
|
||||
kTcl112AcSwingVHigh LITERAL1
|
||||
kTcl112AcSwingVHighest LITERAL1
|
||||
kTcl112AcSwingVLow LITERAL1
|
||||
kTcl112AcSwingVLowest LITERAL1
|
||||
kTcl112AcSwingVMiddle LITERAL1
|
||||
kTcl112AcSwingVOff LITERAL1
|
||||
kTcl112AcSwingVOn LITERAL1
|
||||
kTcl112AcTempMax LITERAL1
|
||||
kTcl112AcTempMin LITERAL1
|
||||
kTcl112AcTimerMax LITERAL1
|
||||
kTcl112AcTimerResolution LITERAL1
|
||||
kTcl112AcTolerance LITERAL1
|
||||
kTcl112AcZeroSpace LITERAL1
|
||||
kTechnibelAcBitMark LITERAL1
|
||||
|
@ -3482,6 +3696,7 @@ kTempDownStr LITERAL1
|
|||
kTempStr LITERAL1
|
||||
kTempUpStr LITERAL1
|
||||
kThreeLetterDayOfWeekStr LITERAL1
|
||||
kTimeSep LITERAL1
|
||||
kTimeoutMs LITERAL1
|
||||
kTimerModeStr LITERAL1
|
||||
kTimerStr LITERAL1
|
||||
|
@ -3617,6 +3832,8 @@ kUnknownThreshold LITERAL1
|
|||
kUpStr LITERAL1
|
||||
kUpperStr LITERAL1
|
||||
kUseDefTol LITERAL1
|
||||
kV9014557AStr LITERAL1
|
||||
kV9014557BStr LITERAL1
|
||||
kVaneStr LITERAL1
|
||||
kVestelAcAuto LITERAL1
|
||||
kVestelAcBitMark LITERAL1
|
||||
|
@ -3737,6 +3954,8 @@ kXmpRepeatCodeAlt LITERAL1
|
|||
kXmpSections LITERAL1
|
||||
kXmpSpaceStep LITERAL1
|
||||
kXmpWordSize LITERAL1
|
||||
kYaw1fStr LITERAL1
|
||||
kYbofbStr LITERAL1
|
||||
kYesStr LITERAL1
|
||||
kZepealBits LITERAL1
|
||||
kZepealCommandOffOn LITERAL1
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "IRremoteESP8266",
|
||||
"version": "2.7.20",
|
||||
"version": "2.8.0",
|
||||
"keywords": "infrared, ir, remote, esp8266, esp32",
|
||||
"description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)",
|
||||
"repository":
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name=IRremoteESP8266
|
||||
version=2.7.20
|
||||
version=2.8.0
|
||||
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)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,10 +26,12 @@
|
|||
#include "ir_Kelvinator.h"
|
||||
#include "ir_LG.h"
|
||||
#include "ir_Midea.h"
|
||||
#include "ir_Mirage.h"
|
||||
#include "ir_Mitsubishi.h"
|
||||
#include "ir_MitsubishiHeavy.h"
|
||||
#include "ir_Neoclima.h"
|
||||
#include "ir_Panasonic.h"
|
||||
#include "ir_Rhoss.h"
|
||||
#include "ir_Samsung.h"
|
||||
#include "ir_Sanyo.h"
|
||||
#include "ir_Sharp.h"
|
||||
|
@ -90,7 +92,8 @@ 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 opmodeToString(const stdAc::opmode_t mode);
|
||||
static String opmodeToString(const stdAc::opmode_t mode,
|
||||
const bool ha = false);
|
||||
static String fanspeedToString(const stdAc::fanspeed_t speed);
|
||||
static String swingvToString(const stdAc::swingv_t swingv);
|
||||
static String swinghToString(const stdAc::swingh_t swingh);
|
||||
|
@ -245,7 +248,8 @@ void electra(IRElectraAc *ac,
|
|||
void 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 bool turbo, const bool light,
|
||||
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);
|
||||
#endif // SEND_GREE
|
||||
#if SEND_HAIER_AC
|
||||
|
@ -257,18 +261,20 @@ void electra(IRElectraAc *ac,
|
|||
#endif // SEND_HAIER_AC
|
||||
#if SEND_HAIER_AC176
|
||||
void haier176(IRHaierAC176 *ac,
|
||||
const bool on, const stdAc::opmode_t mode,
|
||||
const haier_ac176_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 bool turbo, const bool filter,
|
||||
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
|
||||
const bool turbo, const bool quiet, const bool filter,
|
||||
const int16_t sleep = -1);
|
||||
#endif // SEND_HAIER_AC176
|
||||
#if SEND_HAIER_AC_YRW02
|
||||
void haierYrwo2(IRHaierACYRW02 *ac,
|
||||
const bool on, const stdAc::opmode_t mode,
|
||||
const float degrees, const stdAc::fanspeed_t fan,
|
||||
const stdAc::swingv_t swingv,
|
||||
const bool turbo, const bool filter,
|
||||
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 quiet, const bool filter,
|
||||
const int16_t sleep = -1);
|
||||
#endif // SEND_HAIER_AC_YRW02
|
||||
#if SEND_HITACHI_AC
|
||||
|
@ -326,6 +332,9 @@ void electra(IRElectraAc *ac,
|
|||
const stdAc::swingv_t swingv, const bool turbo, const bool econo,
|
||||
const bool light, const int16_t sleep = -1);
|
||||
#endif // SEND_MIDEA
|
||||
#if SEND_MIRAGE
|
||||
void mirage(IRMirageAc *ac, const stdAc::state_t state);
|
||||
#endif // SEND_MIRAGE
|
||||
#if SEND_MITSUBISHI_AC
|
||||
void mitsubishi(IRMitsubishiAC *ac,
|
||||
const bool on, const stdAc::opmode_t mode,
|
||||
|
@ -386,14 +395,21 @@ void electra(IRElectraAc *ac,
|
|||
const float degrees, const stdAc::fanspeed_t fan,
|
||||
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh);
|
||||
#endif // SEND_PANASONIC_AC32
|
||||
#if SEND_RHOSS
|
||||
void rhoss(IRRhossAc *ac,
|
||||
const bool on, const stdAc::opmode_t mode, const float degrees,
|
||||
const stdAc::fanspeed_t fan, const stdAc::swingv_t swing);
|
||||
#endif // SEND_RHOSS
|
||||
#if SEND_SAMSUNG_AC
|
||||
void samsung(IRSamsungAc *ac,
|
||||
const bool on, const stdAc::opmode_t mode, const float degrees,
|
||||
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
|
||||
const bool quiet, const bool turbo, const bool light,
|
||||
const bool filter, const bool clean,
|
||||
const bool beep, const bool prevpower = true,
|
||||
const bool forcepower = true);
|
||||
const stdAc::fanspeed_t fan,
|
||||
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
|
||||
const bool quiet, const bool turbo, const bool econo,
|
||||
const bool light, const bool filter, const bool clean,
|
||||
const bool beep, const int16_t sleep = -1,
|
||||
const bool prevpower = true, const int16_t prevsleep = -1,
|
||||
const bool forceextended = true);
|
||||
#endif // SEND_SAMSUNG_AC
|
||||
#if SEND_SANYO_AC
|
||||
void sanyo(IRSanyoAc *ac,
|
||||
|
@ -413,11 +429,12 @@ void electra(IRElectraAc *ac,
|
|||
void sharp(IRSharpAc *ac, const sharp_ac_remote_model_t model,
|
||||
const bool on, const bool prev_power, const stdAc::opmode_t mode,
|
||||
const float degrees, const stdAc::fanspeed_t fan,
|
||||
const stdAc::swingv_t swingv, const bool turbo, const bool light,
|
||||
const stdAc::swingv_t swingv, const stdAc::swingv_t swingv_prev,
|
||||
const bool turbo, const bool light,
|
||||
const bool filter, const bool clean);
|
||||
#endif // SEND_SHARP_AC
|
||||
#if SEND_TCL112AC
|
||||
void tcl112(IRTcl112Ac *ac,
|
||||
void tcl112(IRTcl112Ac *ac, const tcl_ac_remote_model_t model,
|
||||
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,
|
||||
|
|
|
@ -830,8 +830,7 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
|
|||
DPRINTLN("Attempting Samsung AC (extended) decode");
|
||||
// Check the extended size first, as it should fail fast due to longer
|
||||
// length.
|
||||
if (decodeSamsungAC(results, offset, kSamsungAcExtendedBits, false))
|
||||
return true;
|
||||
if (decodeSamsungAC(results, offset, kSamsungAcExtendedBits)) return true;
|
||||
// Now check for the more common length.
|
||||
DPRINTLN("Attempting Samsung AC decode");
|
||||
if (decodeSamsungAC(results, offset, kSamsungAcBits)) return true;
|
||||
|
@ -1036,6 +1035,18 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
|
|||
DPRINTLN("Attempting Bose decode");
|
||||
if (decodeBose(results, offset)) return true;
|
||||
#endif // DECODE_BOSE
|
||||
#if DECODE_ARRIS
|
||||
DPRINTLN("Attempting Arris decode");
|
||||
if (decodeArris(results, offset)) return true;
|
||||
#endif // DECODE_ARRIS
|
||||
#if DECODE_RHOSS
|
||||
DPRINTLN("Attempting Rhoss decode");
|
||||
if (decodeRhoss(results, offset)) return true;
|
||||
#endif // DECODE_RHOSS
|
||||
#if DECODE_AIRTON
|
||||
DPRINTLN("Attempting Airton decode");
|
||||
if (decodeAirton(results, offset)) return true;
|
||||
#endif // DECODE_AIRTON
|
||||
// Typically new protocols are added above this line.
|
||||
}
|
||||
#if DECODE_HASH
|
||||
|
@ -1811,6 +1822,7 @@ uint16_t IRrecv::matchManchesterData(volatile const uint16_t *data_ptr,
|
|||
const int16_t excess,
|
||||
const bool MSBfirst,
|
||||
const bool GEThomas) {
|
||||
DPRINTLN("DEBUG: Entered matchManchesterData");
|
||||
uint16_t offset = 0;
|
||||
uint64_t data = 0;
|
||||
uint16_t nr_half_periods = 0;
|
||||
|
@ -1824,7 +1836,10 @@ uint16_t IRrecv::matchManchesterData(volatile const uint16_t *data_ptr,
|
|||
uint16_t min_remaining = nbits;
|
||||
|
||||
// Check if there is enough capture buffer to possibly have the message.
|
||||
if (remaining < min_remaining) return 0; // Nope, so abort.
|
||||
if (remaining < min_remaining) {
|
||||
DPRINTLN("DEBUG: Ran out of capture buffer!");
|
||||
return 0; // Nope, so abort.
|
||||
}
|
||||
|
||||
// Convert to ticks. Optimisation: Saves on math/extra instructions later.
|
||||
uint16_t bank = starting_balance / kRawTick;
|
||||
|
@ -1847,22 +1862,39 @@ uint16_t IRrecv::matchManchesterData(volatile const uint16_t *data_ptr,
|
|||
while ((offset < remaining || bank) &&
|
||||
nr_half_periods < expected_half_periods) {
|
||||
// Get the next entry if we haven't anything existing to process.
|
||||
DPRINT("DEBUG: Offset = ");
|
||||
DPRINTLN(offset);
|
||||
if (!bank) bank = *(data_ptr + offset++);
|
||||
DPRINT("DEBUG: Bank = ");
|
||||
DPRINTLN(bank * kRawTick);
|
||||
// Check if we don't have a short interval.
|
||||
if (!match(bank, half_period, tolerance, excess)) return 0; // Not valid.
|
||||
DPRINTLN("DEBUG: Checking for short interval");
|
||||
if (!match(bank, half_period, tolerance, excess)) {
|
||||
DPRINTLN("DEBUG: It is. Exiting");
|
||||
return 0; // Not valid.
|
||||
}
|
||||
// We've succeeded in matching half a period, so count it.
|
||||
nr_half_periods++;
|
||||
DPRINT("DEBUG: Half Periods = ");
|
||||
DPRINTLN(nr_half_periods);
|
||||
// We've now used up our bank, so refill it with the next item, unless we
|
||||
// are at the end of the capture buffer.
|
||||
// If we are assume a single half period of "space".
|
||||
if (offset < remaining)
|
||||
if (offset < remaining) {
|
||||
DPRINT("DEBUG: Offset = ");
|
||||
DPRINTLN(offset);
|
||||
bank = *(data_ptr + offset++);
|
||||
else if (offset == remaining)
|
||||
} else if (offset == remaining) {
|
||||
bank = raw_half_period;
|
||||
else
|
||||
} else {
|
||||
return 0; // We are out of buffer, so abort!
|
||||
}
|
||||
DPRINT("DEBUG: Bank = ");
|
||||
DPRINTLN(bank * kRawTick);
|
||||
|
||||
// Shift the data along and add our new bit.
|
||||
DPRINT("DEBUG: Adding bit: ");
|
||||
DPRINTLN((currentBit ? "1" : "0"));
|
||||
data <<= 1;
|
||||
data |= currentBit;
|
||||
|
||||
|
@ -1870,10 +1902,12 @@ uint16_t IRrecv::matchManchesterData(volatile const uint16_t *data_ptr,
|
|||
if (match(bank, half_period * 2, tolerance, excess)) {
|
||||
// It is, so flip the bit we need to append, and remove a half_period of
|
||||
// time from the bank.
|
||||
DPRINTLN("DEBUG: long interval detected");
|
||||
currentBit = !currentBit;
|
||||
bank -= raw_half_period;
|
||||
} else if (match(bank, half_period, tolerance, excess)) {
|
||||
// It is a short interval, so eat up all the time and move on.
|
||||
DPRINTLN("DEBUG: short interval detected");
|
||||
bank = 0;
|
||||
} else if (nr_half_periods == expected_half_periods - 1 &&
|
||||
matchAtLeast(bank, half_period, tolerance, excess)) {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
const uint16_t kHeader = 2; // Usual nr. of header entries.
|
||||
const uint16_t kFooter = 2; // Usual nr. of footer (stop bits) entries.
|
||||
const uint16_t kStartOffset = 1; // Usual rawbuf entry to start from.
|
||||
#define MS_TO_USEC(x) (x * 1000U) // Convert milli-Seconds to micro-Seconds.
|
||||
#define MS_TO_USEC(x) ((x) * 1000U) // Convert milli-Seconds to micro-Seconds.
|
||||
// Marks tend to be 100us too long, and spaces 100us too short
|
||||
// when received due to sensor lag.
|
||||
const uint16_t kMarkExcess = 50;
|
||||
|
@ -287,6 +287,10 @@ class IRrecv {
|
|||
bool decodeArgo(decode_results *results, uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kArgoBits, const bool strict = true);
|
||||
#endif // DECODE_ARGO
|
||||
#if DECODE_ARRIS
|
||||
bool decodeArris(decode_results *results, uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kArrisBits, const bool strict = true);
|
||||
#endif // DECODE_ARRIS
|
||||
#if DECODE_SONY
|
||||
bool decodeSony(decode_results *results, uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kSonyMinBits,
|
||||
|
@ -766,6 +770,15 @@ class IRrecv {
|
|||
bool decodeBose(decode_results *results, uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kBoseBits, const bool strict = true);
|
||||
#endif // DECODE_BOSE
|
||||
#if DECODE_RHOSS
|
||||
bool decodeRhoss(decode_results *results, uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kRhossBits, const bool strict = true);
|
||||
#endif // DECODE_RHOSS
|
||||
#if DECODE_AIRTON
|
||||
bool decodeAirton(decode_results *results, uint16_t offset = kStartOffset,
|
||||
const uint16_t nbits = kAirtonBits,
|
||||
const bool strict = true);
|
||||
#endif // DECODE_AIRTON
|
||||
};
|
||||
|
||||
#endif // IRRECV_H_
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
#endif // UNIT_TEST
|
||||
|
||||
// Library Version
|
||||
#define _IRREMOTEESP8266_VERSION_ "2.7.20"
|
||||
#define _IRREMOTEESP8266_VERSION_ "2.8.0"
|
||||
|
||||
// Set the language & locale for the library. See the `locale` dir for options.
|
||||
#ifndef _IR_LOCALE_
|
||||
|
@ -790,6 +790,27 @@
|
|||
#define SEND_BOSE _IR_ENABLE_DEFAULT_
|
||||
#endif // SEND_BOSE
|
||||
|
||||
#ifndef DECODE_ARRIS
|
||||
#define DECODE_ARRIS _IR_ENABLE_DEFAULT_
|
||||
#endif // DECODE_ARRIS
|
||||
#ifndef SEND_ARRIS
|
||||
#define SEND_ARRIS _IR_ENABLE_DEFAULT_
|
||||
#endif // SEND_ARRIS
|
||||
|
||||
#ifndef DECODE_RHOSS
|
||||
#define DECODE_RHOSS _IR_ENABLE_DEFAULT_
|
||||
#endif // DECODE_RHOSS
|
||||
#ifndef SEND_RHOSS
|
||||
#define SEND_RHOSS _IR_ENABLE_DEFAULT_
|
||||
#endif // SEND_RHOSS
|
||||
|
||||
#ifndef DECODE_AIRTON
|
||||
#define DECODE_AIRTON _IR_ENABLE_DEFAULT_
|
||||
#endif // DECODE_AIRTON
|
||||
#ifndef SEND_AIRTON
|
||||
#define SEND_AIRTON _IR_ENABLE_DEFAULT_
|
||||
#endif // SEND_AIRTON
|
||||
|
||||
#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 || \
|
||||
|
@ -804,7 +825,7 @@
|
|||
DECODE_HITACHI_AC344 || DECODE_CORONA_AC || DECODE_SANYO_AC || \
|
||||
DECODE_VOLTAS || DECODE_MIRAGE || DECODE_HAIER_AC176 || \
|
||||
DECODE_TEKNOPOINT || DECODE_KELON || DECODE_TROTEC_3550 || \
|
||||
DECODE_SANYO_AC88 || \
|
||||
DECODE_SANYO_AC88 || DECODE_RHOSS || \
|
||||
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
|
||||
|
@ -951,14 +972,19 @@ enum decode_type_t {
|
|||
TROTEC_3550,
|
||||
SANYO_AC88, // 105
|
||||
BOSE,
|
||||
ARRIS,
|
||||
RHOSS,
|
||||
AIRTON,
|
||||
// Add new entries before this one, and update it to point to the last entry.
|
||||
kLastDecodeType = BOSE,
|
||||
kLastDecodeType = AIRTON,
|
||||
};
|
||||
|
||||
// Message lengths & required repeat values
|
||||
const uint16_t kNoRepeat = 0;
|
||||
const uint16_t kSingleRepeat = 1;
|
||||
|
||||
const uint16_t kAirtonBits = 56;
|
||||
const uint16_t kAirtonDefaultRepeat = kNoRepeat;
|
||||
const uint16_t kAirwellBits = 34;
|
||||
const uint16_t kAirwellMinRepeats = 2;
|
||||
const uint16_t kAiwaRcT501Bits = 15;
|
||||
|
@ -970,6 +996,7 @@ const uint16_t kAmcorDefaultRepeat = kSingleRepeat;
|
|||
const uint16_t kArgoStateLength = 12;
|
||||
const uint16_t kArgoBits = kArgoStateLength * 8;
|
||||
const uint16_t kArgoDefaultRepeat = kNoRepeat;
|
||||
const uint16_t kArrisBits = 32;
|
||||
const uint16_t kCoolixBits = 24;
|
||||
const uint16_t kCoolixDefaultRepeat = kSingleRepeat;
|
||||
const uint16_t kCarrierAcBits = 32;
|
||||
|
@ -1195,6 +1222,9 @@ const uint16_t kMilesTag2ShotBits = 14;
|
|||
const uint16_t kMilesTag2MsgBits = 24;
|
||||
const uint16_t kMilesMinRepeat = 0;
|
||||
const uint16_t kBoseBits = 16;
|
||||
const uint16_t kRhossStateLength = 12;
|
||||
const uint16_t kRhossBits = kRhossStateLength * 8;
|
||||
const uint16_t kRhossDefaultRepeat = 0;
|
||||
|
||||
|
||||
// Legacy defines. (Deprecated)
|
||||
|
|
|
@ -637,6 +637,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
|
|||
case LG:
|
||||
case LG2:
|
||||
return 28;
|
||||
case ARRIS:
|
||||
case CARRIER_AC:
|
||||
case ELITESCREENS:
|
||||
case EPSON:
|
||||
|
@ -665,6 +666,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
|
|||
case MIDEA:
|
||||
case PANASONIC:
|
||||
return 48;
|
||||
case AIRTON:
|
||||
case ECOCLIM:
|
||||
case MAGIQUEST:
|
||||
case VESTEL_AC:
|
||||
|
@ -738,6 +740,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
|
|||
return kNeoclimaBits;
|
||||
case PANASONIC_AC:
|
||||
return kPanasonicAcBits;
|
||||
case RHOSS:
|
||||
return kRhossBits;
|
||||
case SAMSUNG_AC:
|
||||
return kSamsungAcBits;
|
||||
case SANYO_AC:
|
||||
|
@ -781,6 +785,11 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
|
|||
uint16_t min_repeat __attribute__((unused)) =
|
||||
std::max(IRsend::minRepeats(type), repeat);
|
||||
switch (type) {
|
||||
#if SEND_AIRTON
|
||||
case AIRTON:
|
||||
sendAirton(data, nbits, min_repeat);
|
||||
break;
|
||||
#endif // SEND_AIRTON
|
||||
#if SEND_AIRWELL
|
||||
case AIRWELL:
|
||||
sendAirwell(data, nbits, min_repeat);
|
||||
|
@ -790,7 +799,12 @@ bool IRsend::send(const decode_type_t type, const uint64_t data,
|
|||
case AIWA_RC_T501:
|
||||
sendAiwaRCT501(data, nbits, min_repeat);
|
||||
break;
|
||||
#endif
|
||||
#endif // SEND_AIWA_RC_T501
|
||||
#if SEND_ARRIS
|
||||
case ARRIS:
|
||||
sendArris(data, nbits, min_repeat);
|
||||
break;
|
||||
#endif // SEND_ARRIS
|
||||
#if SEND_BOSE
|
||||
case BOSE:
|
||||
sendBose(data, nbits, min_repeat);
|
||||
|
@ -1247,6 +1261,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
|
|||
sendPanasonicAC(state, nbytes);
|
||||
break;
|
||||
#endif // SEND_PANASONIC_AC
|
||||
#if SEND_RHOSS
|
||||
case RHOSS:
|
||||
sendRhoss(state, nbytes);
|
||||
break;
|
||||
#endif // SEND_RHOSS
|
||||
#if SEND_SAMSUNG_AC
|
||||
case SAMSUNG_AC:
|
||||
sendSamsungAC(state, nbytes);
|
||||
|
|
|
@ -136,12 +136,24 @@ enum gree_ac_remote_model_t {
|
|||
YBOFB, // (2) Green, YBOFB2, YAPOF3
|
||||
};
|
||||
|
||||
/// HAIER_AC176 A/C model numbers
|
||||
enum haier_ac176_remote_model_t {
|
||||
V9014557_A = 1, // (1) V9014557 Remote in "A" setting. (Default)
|
||||
V9014557_B, // (2) V9014557 Remote in "B" setting.
|
||||
};
|
||||
|
||||
/// HITACHI_AC1 A/C model numbers
|
||||
enum hitachi_ac1_remote_model_t {
|
||||
R_LT0541_HTA_A = 1, // (1) R-LT0541-HTA Remote in "A" setting. (Default)
|
||||
R_LT0541_HTA_B, // (2) R-LT0541-HTA Remote in "B" setting.
|
||||
};
|
||||
|
||||
/// MIRAGE A/C model numbers
|
||||
enum mirage_ac_remote_model_t {
|
||||
KKG9AC1 = 1, // (1) KKG9A-C1 Remote. (Default)
|
||||
KKG29AC1, // (2) KKG29A-C1 Remote.
|
||||
};
|
||||
|
||||
/// Panasonic A/C model numbers
|
||||
enum panasonic_ac_remote_model_t {
|
||||
kPanasonicUnknown = 0,
|
||||
|
@ -160,6 +172,12 @@ enum sharp_ac_remote_model_t {
|
|||
A903 = 3, // 820 too
|
||||
};
|
||||
|
||||
/// TCL A/C model numbers
|
||||
enum tcl_ac_remote_model_t {
|
||||
TAC09CHSD = 1,
|
||||
GZ055BE1 = 2,
|
||||
};
|
||||
|
||||
/// Voltas A/C model numbers
|
||||
enum voltas_ac_remote_model_t {
|
||||
kVoltasUnknown = 0, // Full Function
|
||||
|
@ -737,6 +755,21 @@ class IRsend {
|
|||
void sendBose(const uint64_t data, const uint16_t nbits = kBoseBits,
|
||||
const uint16_t repeat = kNoRepeat);
|
||||
#endif // SEND_BOSE
|
||||
#if SEND_ARRIS
|
||||
void sendArris(const uint64_t data, const uint16_t nbits = kArrisBits,
|
||||
const uint16_t repeat = kNoRepeat);
|
||||
static uint32_t toggleArrisRelease(const uint32_t data);
|
||||
static uint32_t encodeArris(const uint32_t command, const bool release);
|
||||
#endif // SEND_ARRIS
|
||||
#if SEND_RHOSS
|
||||
void sendRhoss(const unsigned char data[],
|
||||
const uint16_t nbytes = kRhossStateLength,
|
||||
const uint16_t repeat = kRhossDefaultRepeat);
|
||||
#endif // SEND_RHOSS
|
||||
#if SEND_AIRTON
|
||||
void sendAirton(const uint64_t data, const uint16_t nbits = kAirtonBits,
|
||||
const uint16_t repeat = kAirtonDefaultRepeat);
|
||||
#endif // SEND_AIRTON
|
||||
|
||||
protected:
|
||||
#ifdef UNIT_TEST
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
// Copyright 2019-2020 - David Conran (@crankyoldgit)
|
||||
// Copyright 2019-2021 - David Conran (@crankyoldgit)
|
||||
|
||||
/// @file IRtext.cpp
|
||||
/// @warning If you add or remove an entry in this file, you should run:
|
||||
/// '../tools/generate_irtext_h.sh' to rebuild the `IRtext.h` file.
|
||||
|
||||
#include "IRtext.h"
|
||||
#ifndef UNIT_TEST
|
||||
#include <Arduino.h>
|
||||
#endif // UNIT_TEST
|
||||
|
@ -14,178 +15,263 @@
|
|||
#define PROGMEM // Pretend we have the PROGMEM macro even if we really don't.
|
||||
#endif
|
||||
|
||||
#ifndef FPSTR
|
||||
#define FPSTR(X) X // Also pretend we have flash-string helper class cast.
|
||||
#endif
|
||||
|
||||
#define IRTEXT_CONST_BLOB_NAME(NAME)\
|
||||
NAME ## Blob
|
||||
|
||||
#define IRTEXT_CONST_BLOB_DECL(NAME)\
|
||||
const char IRTEXT_CONST_BLOB_NAME(NAME) [] PROGMEM
|
||||
|
||||
#define IRTEXT_CONST_BLOB_PTR(NAME)\
|
||||
IRTEXT_CONST_PTR(NAME) {\
|
||||
IRTEXT_CONST_PTR_CAST(IRTEXT_CONST_BLOB_NAME(NAME)) }
|
||||
|
||||
#define IRTEXT_CONST_STRING(NAME, VALUE)\
|
||||
static IRTEXT_CONST_BLOB_DECL(NAME) { VALUE };\
|
||||
IRTEXT_CONST_PTR(NAME) PROGMEM {\
|
||||
IRTEXT_CONST_PTR_CAST(&(IRTEXT_CONST_BLOB_NAME(NAME))[0]) }
|
||||
|
||||
// Common
|
||||
const PROGMEM char* kUnknownStr = D_STR_UNKNOWN; ///< "Unknown"
|
||||
const PROGMEM char* kProtocolStr = D_STR_PROTOCOL; ///< "Protocol"
|
||||
const PROGMEM char* kPowerStr = D_STR_POWER; ///< "Power"
|
||||
const PROGMEM char* kOnStr = D_STR_ON; ///< "On"
|
||||
const PROGMEM char* kOffStr = D_STR_OFF; ///< "Off"
|
||||
const PROGMEM char* kModeStr = D_STR_MODE; ///< "Mode"
|
||||
const PROGMEM char* kToggleStr = D_STR_TOGGLE; ///< "Toggle"
|
||||
const PROGMEM char* kTurboStr = D_STR_TURBO; ///< "Turbo"
|
||||
const PROGMEM char* kSuperStr = D_STR_SUPER; ///< "Super"
|
||||
const PROGMEM char* kSleepStr = D_STR_SLEEP; ///< "Sleep"
|
||||
const PROGMEM char* kLightStr = D_STR_LIGHT; ///< "Light"
|
||||
const PROGMEM char* kPowerfulStr = D_STR_POWERFUL; ///< "Powerful"
|
||||
const PROGMEM char* kQuietStr = D_STR_QUIET; ///< "Quiet"
|
||||
const PROGMEM char* kEconoStr = D_STR_ECONO; ///< "Econo"
|
||||
const PROGMEM char* kSwingStr = D_STR_SWING; ///< "Swing"
|
||||
const PROGMEM char* kSwingHStr = D_STR_SWINGH; ///< "SwingH"
|
||||
const PROGMEM char* kSwingVStr = D_STR_SWINGV; ///< "SwingV"
|
||||
const PROGMEM char* kBeepStr = D_STR_BEEP; ///< "Beep"
|
||||
const PROGMEM char* kZoneFollowStr = D_STR_ZONEFOLLOW; ///< "Zone Follow"
|
||||
const PROGMEM char* kFixedStr = D_STR_FIXED; ///< "Fixed"
|
||||
const PROGMEM char* kMouldStr = D_STR_MOULD; ///< "Mould"
|
||||
const PROGMEM char* kCleanStr = D_STR_CLEAN; ///< "Clean"
|
||||
const PROGMEM char* kPurifyStr = D_STR_PURIFY; ///< "Purify"
|
||||
const PROGMEM char* kTimerStr = D_STR_TIMER; ///< "Timer"
|
||||
const PROGMEM char* kOnTimerStr = D_STR_ONTIMER; ///< "On Timer"
|
||||
const PROGMEM char* kOffTimerStr = D_STR_OFFTIMER; ///< "Off Timer"
|
||||
const PROGMEM char* kTimerModeStr = D_STR_TIMERMODE; ///< "Timer Mode"
|
||||
const PROGMEM char* kClockStr = D_STR_CLOCK; ///< "Clock"
|
||||
const PROGMEM char* kCommandStr = D_STR_COMMAND; ///< "Command"
|
||||
const PROGMEM char* kXFanStr = D_STR_XFAN; ///< "XFan"
|
||||
const PROGMEM char* kHealthStr = D_STR_HEALTH; ///< "Health"
|
||||
const PROGMEM char* kModelStr = D_STR_MODEL; ///< "Model"
|
||||
const PROGMEM char* kTempStr = D_STR_TEMP; ///< "Temp"
|
||||
const PROGMEM char* kIFeelStr = D_STR_IFEEL; ///< "IFeel"
|
||||
const PROGMEM char* kHumidStr = D_STR_HUMID; ///< "Humid"
|
||||
const PROGMEM char* kSaveStr = D_STR_SAVE; ///< "Save"
|
||||
const PROGMEM char* kEyeStr = D_STR_EYE; ///< "Eye"
|
||||
const PROGMEM char* kFollowStr = D_STR_FOLLOW; ///< "Follow"
|
||||
const PROGMEM char* kIonStr = D_STR_ION; ///< "Ion"
|
||||
const PROGMEM char* kFreshStr = D_STR_FRESH; ///< "Fresh"
|
||||
const PROGMEM char* kHoldStr = D_STR_HOLD; ///< "Hold"
|
||||
const PROGMEM char* kButtonStr = D_STR_BUTTON; ///< "Button"
|
||||
const PROGMEM char* k8CHeatStr = D_STR_8C_HEAT; ///< "8C Heat"
|
||||
const PROGMEM char* k10CHeatStr = D_STR_10C_HEAT; ///< "10C Heat"
|
||||
const PROGMEM char* kNightStr = D_STR_NIGHT; ///< "Night"
|
||||
const PROGMEM char* kSilentStr = D_STR_SILENT; ///< "Silent"
|
||||
const PROGMEM char* kFilterStr = D_STR_FILTER; ///< "Filter"
|
||||
const PROGMEM char* k3DStr = D_STR_3D; ///< "3D"
|
||||
const PROGMEM char* kCelsiusStr = D_STR_CELSIUS; ///< "Celsius"
|
||||
const PROGMEM char* kCelsiusFahrenheitStr = D_STR_CELSIUS_FAHRENHEIT; ///<
|
||||
IRTEXT_CONST_STRING(kUnknownStr, D_STR_UNKNOWN); ///< "Unknown"
|
||||
IRTEXT_CONST_STRING(kProtocolStr, D_STR_PROTOCOL); ///< "Protocol"
|
||||
IRTEXT_CONST_STRING(kPowerStr, D_STR_POWER); ///< "Power"
|
||||
IRTEXT_CONST_STRING(kOnStr, D_STR_ON); ///< "On"
|
||||
IRTEXT_CONST_STRING(kOffStr, D_STR_OFF); ///< "Off"
|
||||
IRTEXT_CONST_STRING(k1Str, D_STR_1); ///< "1"
|
||||
IRTEXT_CONST_STRING(k0Str, D_STR_0); ///< "0"
|
||||
IRTEXT_CONST_STRING(kModeStr, D_STR_MODE); ///< "Mode"
|
||||
IRTEXT_CONST_STRING(kToggleStr, D_STR_TOGGLE); ///< "Toggle"
|
||||
IRTEXT_CONST_STRING(kTurboStr, D_STR_TURBO); ///< "Turbo"
|
||||
IRTEXT_CONST_STRING(kSuperStr, D_STR_SUPER); ///< "Super"
|
||||
IRTEXT_CONST_STRING(kSleepStr, D_STR_SLEEP); ///< "Sleep"
|
||||
IRTEXT_CONST_STRING(kLightStr, D_STR_LIGHT); ///< "Light"
|
||||
IRTEXT_CONST_STRING(kPowerfulStr, D_STR_POWERFUL); ///< "Powerful"
|
||||
IRTEXT_CONST_STRING(kQuietStr, D_STR_QUIET); ///< "Quiet"
|
||||
IRTEXT_CONST_STRING(kEconoStr, D_STR_ECONO); ///< "Econo"
|
||||
IRTEXT_CONST_STRING(kSwingStr, D_STR_SWING); ///< "Swing"
|
||||
IRTEXT_CONST_STRING(kSwingHStr, D_STR_SWINGH); ///< "SwingH"
|
||||
IRTEXT_CONST_STRING(kSwingVStr, D_STR_SWINGV); ///< "SwingV"
|
||||
IRTEXT_CONST_STRING(kBeepStr, D_STR_BEEP); ///< "Beep"
|
||||
IRTEXT_CONST_STRING(kZoneFollowStr, D_STR_ZONEFOLLOW); ///< "Zone Follow"
|
||||
IRTEXT_CONST_STRING(kFixedStr, D_STR_FIXED); ///< "Fixed"
|
||||
IRTEXT_CONST_STRING(kMouldStr, D_STR_MOULD); ///< "Mould"
|
||||
IRTEXT_CONST_STRING(kCleanStr, D_STR_CLEAN); ///< "Clean"
|
||||
IRTEXT_CONST_STRING(kPurifyStr, D_STR_PURIFY); ///< "Purify"
|
||||
IRTEXT_CONST_STRING(kTimerStr, D_STR_TIMER); ///< "Timer"
|
||||
IRTEXT_CONST_STRING(kOnTimerStr, D_STR_ONTIMER); ///< "On Timer"
|
||||
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(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(kIFeelStr, D_STR_IFEEL); ///< "IFeel"
|
||||
IRTEXT_CONST_STRING(kHumidStr, D_STR_HUMID); ///< "Humid"
|
||||
IRTEXT_CONST_STRING(kSaveStr, D_STR_SAVE); ///< "Save"
|
||||
IRTEXT_CONST_STRING(kEyeStr, D_STR_EYE); ///< "Eye"
|
||||
IRTEXT_CONST_STRING(kFollowStr, D_STR_FOLLOW); ///< "Follow"
|
||||
IRTEXT_CONST_STRING(kIonStr, D_STR_ION); ///< "Ion"
|
||||
IRTEXT_CONST_STRING(kFreshStr, D_STR_FRESH); ///< "Fresh"
|
||||
IRTEXT_CONST_STRING(kHoldStr, D_STR_HOLD); ///< "Hold"
|
||||
IRTEXT_CONST_STRING(kButtonStr, D_STR_BUTTON); ///< "Button"
|
||||
IRTEXT_CONST_STRING(k8CHeatStr, D_STR_8C_HEAT); ///< "8C Heat"
|
||||
IRTEXT_CONST_STRING(k10CHeatStr, D_STR_10C_HEAT); ///< "10C Heat"
|
||||
IRTEXT_CONST_STRING(kNightStr, D_STR_NIGHT); ///< "Night"
|
||||
IRTEXT_CONST_STRING(kSilentStr, D_STR_SILENT); ///< "Silent"
|
||||
IRTEXT_CONST_STRING(kFilterStr, D_STR_FILTER); ///< "Filter"
|
||||
IRTEXT_CONST_STRING(k3DStr, D_STR_3D); ///< "3D"
|
||||
IRTEXT_CONST_STRING(kCelsiusStr, D_STR_CELSIUS); ///< "Celsius"
|
||||
IRTEXT_CONST_STRING(kCelsiusFahrenheitStr, D_STR_CELSIUS_FAHRENHEIT); ///<
|
||||
///< "Celsius/Fahrenheit"
|
||||
const PROGMEM char* kTempUpStr = D_STR_TEMPUP; ///< "Temp Up"
|
||||
const PROGMEM char* kTempDownStr = D_STR_TEMPDOWN; ///< "Temp Down"
|
||||
const PROGMEM char* kStartStr = D_STR_START; ///< "Start"
|
||||
const PROGMEM char* kStopStr = D_STR_STOP; ///< "Stop"
|
||||
const PROGMEM char* kMoveStr = D_STR_MOVE; ///< "Move"
|
||||
const PROGMEM char* kSetStr = D_STR_SET; ///< "Set"
|
||||
const PROGMEM char* kCancelStr = D_STR_CANCEL; ///< "Cancel"
|
||||
const PROGMEM char* kUpStr = D_STR_UP; ///< "Up"
|
||||
const PROGMEM char* kDownStr = D_STR_DOWN; ///< "Down"
|
||||
const PROGMEM char* kChangeStr = D_STR_CHANGE; ///< "Change"
|
||||
const PROGMEM char* kComfortStr = D_STR_COMFORT; ///< "Comfort"
|
||||
const PROGMEM char* kSensorStr = D_STR_SENSOR; ///< "Sensor"
|
||||
const PROGMEM char* kWeeklyTimerStr = D_STR_WEEKLYTIMER; ///< "WeeklyTimer"
|
||||
const PROGMEM char* kWifiStr = D_STR_WIFI; ///< "Wifi"
|
||||
const PROGMEM char* kLastStr = D_STR_LAST; ///< "Last"
|
||||
const PROGMEM char* kFastStr = D_STR_FAST; ///< "Fast"
|
||||
const PROGMEM char* kSlowStr = D_STR_SLOW; ///< "Slow"
|
||||
const PROGMEM char* kAirFlowStr = D_STR_AIRFLOW; ///< "Air Flow"
|
||||
const PROGMEM char* kStepStr = D_STR_STEP; ///< "Step"
|
||||
const PROGMEM char* kNAStr = D_STR_NA; ///< "N/A"
|
||||
const PROGMEM char* kInsideStr = D_STR_INSIDE; ///< "Inside"
|
||||
const PROGMEM char* kOutsideStr = D_STR_OUTSIDE; ///< "Outside"
|
||||
const PROGMEM char* kLoudStr = D_STR_LOUD; ///< "Loud"
|
||||
const PROGMEM char* kLowerStr = D_STR_LOWER; ///< "Lower"
|
||||
const PROGMEM char* kUpperStr = D_STR_UPPER; ///< "Upper"
|
||||
const PROGMEM char* kBreezeStr = D_STR_BREEZE; ///< "Breeze"
|
||||
const PROGMEM char* kCirculateStr = D_STR_CIRCULATE; ///< "Circulate"
|
||||
const PROGMEM char* kCeilingStr = D_STR_CEILING; ///< "Ceiling"
|
||||
const PROGMEM char* kWallStr = D_STR_WALL; ///< "Wall"
|
||||
const PROGMEM char* kRoomStr = D_STR_ROOM; ///< "Room"
|
||||
const PROGMEM char* k6thSenseStr = D_STR_6THSENSE; ///< "6th Sense"
|
||||
const PROGMEM char* kTypeStr = D_STR_TYPE; ///< "Type"
|
||||
const PROGMEM char* kSpecialStr = D_STR_SPECIAL; ///< "Special"
|
||||
const PROGMEM char* kIdStr = D_STR_ID; ///< "Id" / Device Identifier
|
||||
const PROGMEM char* kVaneStr = D_STR_VANE; ///< "Vane"
|
||||
IRTEXT_CONST_STRING(kTempUpStr, D_STR_TEMPUP); ///< "Temp Up"
|
||||
IRTEXT_CONST_STRING(kTempDownStr, D_STR_TEMPDOWN); ///< "Temp Down"
|
||||
IRTEXT_CONST_STRING(kStartStr, D_STR_START); ///< "Start"
|
||||
IRTEXT_CONST_STRING(kStopStr, D_STR_STOP); ///< "Stop"
|
||||
IRTEXT_CONST_STRING(kMoveStr, D_STR_MOVE); ///< "Move"
|
||||
IRTEXT_CONST_STRING(kSetStr, D_STR_SET); ///< "Set"
|
||||
IRTEXT_CONST_STRING(kCancelStr, D_STR_CANCEL); ///< "Cancel"
|
||||
IRTEXT_CONST_STRING(kUpStr, D_STR_UP); ///< "Up"
|
||||
IRTEXT_CONST_STRING(kDownStr, D_STR_DOWN); ///< "Down"
|
||||
IRTEXT_CONST_STRING(kChangeStr, D_STR_CHANGE); ///< "Change"
|
||||
IRTEXT_CONST_STRING(kComfortStr, D_STR_COMFORT); ///< "Comfort"
|
||||
IRTEXT_CONST_STRING(kSensorStr, D_STR_SENSOR); ///< "Sensor"
|
||||
IRTEXT_CONST_STRING(kWeeklyTimerStr, D_STR_WEEKLYTIMER); ///< "WeeklyTimer"
|
||||
IRTEXT_CONST_STRING(kWifiStr, D_STR_WIFI); ///< "Wifi"
|
||||
IRTEXT_CONST_STRING(kLastStr, D_STR_LAST); ///< "Last"
|
||||
IRTEXT_CONST_STRING(kFastStr, D_STR_FAST); ///< "Fast"
|
||||
IRTEXT_CONST_STRING(kSlowStr, D_STR_SLOW); ///< "Slow"
|
||||
IRTEXT_CONST_STRING(kAirFlowStr, D_STR_AIRFLOW); ///< "Air Flow"
|
||||
IRTEXT_CONST_STRING(kStepStr, D_STR_STEP); ///< "Step"
|
||||
IRTEXT_CONST_STRING(kNAStr, D_STR_NA); ///< "N/A"
|
||||
IRTEXT_CONST_STRING(kInsideStr, D_STR_INSIDE); ///< "Inside"
|
||||
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(kBreezeStr, D_STR_BREEZE); ///< "Breeze"
|
||||
IRTEXT_CONST_STRING(kCirculateStr, D_STR_CIRCULATE); ///< "Circulate"
|
||||
IRTEXT_CONST_STRING(kCeilingStr, D_STR_CEILING); ///< "Ceiling"
|
||||
IRTEXT_CONST_STRING(kWallStr, D_STR_WALL); ///< "Wall"
|
||||
IRTEXT_CONST_STRING(kRoomStr, D_STR_ROOM); ///< "Room"
|
||||
IRTEXT_CONST_STRING(k6thSenseStr, D_STR_6THSENSE); ///< "6th Sense"
|
||||
IRTEXT_CONST_STRING(kTypeStr, D_STR_TYPE); ///< "Type"
|
||||
IRTEXT_CONST_STRING(kSpecialStr, D_STR_SPECIAL); ///< "Special"
|
||||
IRTEXT_CONST_STRING(kIdStr, D_STR_ID); ///< "Id" / Device Identifier
|
||||
IRTEXT_CONST_STRING(kVaneStr, D_STR_VANE); ///< "Vane"
|
||||
IRTEXT_CONST_STRING(kLockStr, D_STR_LOCK); ///< "Lock"
|
||||
|
||||
const PROGMEM char* kAutoStr = D_STR_AUTO; ///< "Auto"
|
||||
const PROGMEM char* kAutomaticStr = D_STR_AUTOMATIC; ///< "Automatic"
|
||||
const PROGMEM char* kManualStr = D_STR_MANUAL; ///< "Manual"
|
||||
const PROGMEM char* kCoolStr = D_STR_COOL; ///< "Cool"
|
||||
const PROGMEM char* kHeatStr = D_STR_HEAT; ///< "Heat"
|
||||
const PROGMEM char* kFanStr = D_STR_FAN; ///< "Fan"
|
||||
const PROGMEM char* kDryStr = D_STR_DRY; ///< "Dry"
|
||||
const PROGMEM char* kFanOnlyStr = D_STR_FANONLY; ///< "fan_only"
|
||||
const PROGMEM char* kRecycleStr = D_STR_RECYCLE; ///< "Recycle"
|
||||
IRTEXT_CONST_STRING(kAutoStr, D_STR_AUTO); ///< "Auto"
|
||||
IRTEXT_CONST_STRING(kAutomaticStr, D_STR_AUTOMATIC); ///< "Automatic"
|
||||
IRTEXT_CONST_STRING(kManualStr, D_STR_MANUAL); ///< "Manual"
|
||||
IRTEXT_CONST_STRING(kCoolStr, D_STR_COOL); ///< "Cool"
|
||||
IRTEXT_CONST_STRING(kCoolingStr, D_STR_COOLING); ///< "Cooling"
|
||||
IRTEXT_CONST_STRING(kHeatStr, D_STR_HEAT); ///< "Heat"
|
||||
IRTEXT_CONST_STRING(kHeatingStr, D_STR_HEATING); ///< "Heating"
|
||||
IRTEXT_CONST_STRING(kDryStr, D_STR_DRY); ///< "Dry"
|
||||
IRTEXT_CONST_STRING(kDryingStr, D_STR_DRYING); ///< "Drying"
|
||||
IRTEXT_CONST_STRING(kDehumidifyStr, D_STR_DEHUMIDIFY); ///< "Dehumidify"
|
||||
IRTEXT_CONST_STRING(kFanStr, D_STR_FAN); ///< "Fan"
|
||||
// The following Fans strings with "only" are required to help with
|
||||
// HomeAssistant & Google Home Climate integration. For compatibility only.
|
||||
// Ref: https://www.home-assistant.io/integrations/google_assistant/#climate-operation-modes
|
||||
IRTEXT_CONST_STRING(kFanOnlyStr, D_STR_FANONLY); ///< "fan-only"
|
||||
IRTEXT_CONST_STRING(kFan_OnlyStr, D_STR_FAN_ONLY); ///< "fan_only" (HA/legacy)
|
||||
IRTEXT_CONST_STRING(kFanOnlyWithSpaceStr, D_STR_FANSPACEONLY); ///< "Fan Only"
|
||||
IRTEXT_CONST_STRING(kFanOnlyNoSpaceStr, D_STR_FANONLYNOSPACE); ///< "FanOnly"
|
||||
|
||||
const PROGMEM char* kMaxStr = D_STR_MAX; ///< "Max"
|
||||
const PROGMEM char* kMaximumStr = D_STR_MAXIMUM; ///< "Maximum"
|
||||
const PROGMEM char* kMinStr = D_STR_MIN; ///< "Min"
|
||||
const PROGMEM char* kMinimumStr = D_STR_MINIMUM; ///< "Minimum"
|
||||
const PROGMEM char* kMedStr = D_STR_MED; ///< "Med"
|
||||
const PROGMEM char* kMediumStr = D_STR_MEDIUM; ///< "Medium"
|
||||
IRTEXT_CONST_STRING(kRecycleStr, D_STR_RECYCLE); ///< "Recycle"
|
||||
|
||||
const PROGMEM char* kHighestStr = D_STR_HIGHEST; ///< "Highest"
|
||||
const PROGMEM char* kHighStr = D_STR_HIGH; ///< "High"
|
||||
const PROGMEM char* kHiStr = D_STR_HI; ///< "Hi"
|
||||
const PROGMEM char* kMidStr = D_STR_MID; ///< "Mid"
|
||||
const PROGMEM char* kMiddleStr = D_STR_MIDDLE; ///< "Middle"
|
||||
const PROGMEM char* kLowStr = D_STR_LOW; ///< "Low"
|
||||
const PROGMEM char* kLoStr = D_STR_LO; ///< "Lo"
|
||||
const PROGMEM char* kLowestStr = D_STR_LOWEST; ///< "Lowest"
|
||||
const PROGMEM char* kMaxRightStr = D_STR_MAXRIGHT; ///< "Max Right"
|
||||
const PROGMEM char* kRightMaxStr = D_STR_RIGHTMAX_NOSPACE; ///< "RightMax"
|
||||
const PROGMEM char* kRightStr = D_STR_RIGHT; ///< "Right"
|
||||
const PROGMEM char* kLeftStr = D_STR_LEFT; ///< "Left"
|
||||
const PROGMEM char* kMaxLeftStr = D_STR_MAXLEFT; ///< "Max Left"
|
||||
const PROGMEM char* kLeftMaxStr = D_STR_LEFTMAX_NOSPACE; ///< "LeftMax"
|
||||
const PROGMEM char* kWideStr = D_STR_WIDE; ///< "Wide"
|
||||
const PROGMEM char* kCentreStr = D_STR_CENTRE; ///< "Centre"
|
||||
const PROGMEM char* kTopStr = D_STR_TOP; ///< "Top"
|
||||
const PROGMEM char* kBottomStr = D_STR_BOTTOM; ///< "Bottom"
|
||||
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(kMedStr, D_STR_MED); ///< "Med"
|
||||
IRTEXT_CONST_STRING(kMediumStr, D_STR_MEDIUM); ///< "Medium"
|
||||
|
||||
IRTEXT_CONST_STRING(kHighestStr, D_STR_HIGHEST); ///< "Highest"
|
||||
IRTEXT_CONST_STRING(kHighStr, D_STR_HIGH); ///< "High"
|
||||
IRTEXT_CONST_STRING(kHiStr, D_STR_HI); ///< "Hi"
|
||||
IRTEXT_CONST_STRING(kMidStr, D_STR_MID); ///< "Mid"
|
||||
IRTEXT_CONST_STRING(kMiddleStr, D_STR_MIDDLE); ///< "Middle"
|
||||
IRTEXT_CONST_STRING(kLowStr, D_STR_LOW); ///< "Low"
|
||||
IRTEXT_CONST_STRING(kLoStr, D_STR_LO); ///< "Lo"
|
||||
IRTEXT_CONST_STRING(kLowestStr, D_STR_LOWEST); ///< "Lowest"
|
||||
IRTEXT_CONST_STRING(kMaxRightStr, D_STR_MAXRIGHT); ///< "Max Right"
|
||||
IRTEXT_CONST_STRING(kMaxRightNoSpaceStr, D_STR_MAXRIGHT_NOSPACE); ///<
|
||||
///< "MaxRight"
|
||||
IRTEXT_CONST_STRING(kRightMaxStr, D_STR_RIGHTMAX); ///< "Right Max"
|
||||
IRTEXT_CONST_STRING(kRightMaxNoSpaceStr, D_STR_RIGHTMAX_NOSPACE); ///<
|
||||
///< "RightMax"
|
||||
IRTEXT_CONST_STRING(kRightStr, D_STR_RIGHT); ///< "Right"
|
||||
IRTEXT_CONST_STRING(kLeftStr, D_STR_LEFT); ///< "Left"
|
||||
IRTEXT_CONST_STRING(kMaxLeftStr, D_STR_MAXLEFT); ///< "Max Left"
|
||||
IRTEXT_CONST_STRING(kMaxLeftNoSpaceStr, D_STR_MAXLEFT_NOSPACE); ///< "MaxLeft"
|
||||
IRTEXT_CONST_STRING(kLeftMaxStr, D_STR_LEFTMAX); ///< "Left Max"
|
||||
IRTEXT_CONST_STRING(kLeftMaxNoSpaceStr, D_STR_LEFTMAX_NOSPACE); ///< "LeftMax"
|
||||
IRTEXT_CONST_STRING(kWideStr, D_STR_WIDE); ///< "Wide"
|
||||
IRTEXT_CONST_STRING(kCentreStr, D_STR_CENTRE); ///< "Centre"
|
||||
IRTEXT_CONST_STRING(kTopStr, D_STR_TOP); ///< "Top"
|
||||
IRTEXT_CONST_STRING(kBottomStr, D_STR_BOTTOM); ///< "Bottom"
|
||||
|
||||
// Compound words/phrases/descriptions from pre-defined words.
|
||||
const PROGMEM char* kEconoToggleStr = D_STR_ECONOTOGGLE; ///< "Econo Toggle"
|
||||
const PROGMEM char* kEyeAutoStr = D_STR_EYEAUTO; ///< "Eye Auto"
|
||||
const PROGMEM char* kLightToggleStr = D_STR_LIGHTTOGGLE; ///< "Light Toggle"
|
||||
const PROGMEM char* kOutsideQuietStr = D_STR_OUTSIDEQUIET; ///< "Outside Quiet"
|
||||
const PROGMEM char* kPowerToggleStr = D_STR_POWERTOGGLE; ///< "Power Toggle"
|
||||
const PROGMEM char* kPowerButtonStr = D_STR_POWERBUTTON; ///< "Power Button"
|
||||
const PROGMEM char* kPreviousPowerStr = D_STR_PREVIOUSPOWER; ///<
|
||||
IRTEXT_CONST_STRING(kEconoToggleStr, D_STR_ECONOTOGGLE); ///< "Econo Toggle"
|
||||
IRTEXT_CONST_STRING(kEyeAutoStr, D_STR_EYEAUTO); ///< "Eye Auto"
|
||||
IRTEXT_CONST_STRING(kLightToggleStr, D_STR_LIGHTTOGGLE); ///< "Light Toggle"
|
||||
///< "Outside Quiet"
|
||||
IRTEXT_CONST_STRING(kOutsideQuietStr, D_STR_OUTSIDEQUIET);
|
||||
IRTEXT_CONST_STRING(kPowerToggleStr, D_STR_POWERTOGGLE); ///< "Power Toggle"
|
||||
IRTEXT_CONST_STRING(kPowerButtonStr, D_STR_POWERBUTTON); ///< "Power Button"
|
||||
IRTEXT_CONST_STRING(kPreviousPowerStr, D_STR_PREVIOUSPOWER); ///<
|
||||
///< "Previous Power"
|
||||
const PROGMEM char* kDisplayTempStr = D_STR_DISPLAYTEMP; ///< "Display Temp"
|
||||
const PROGMEM char* kSensorTempStr = D_STR_SENSORTEMP; ///< "Sensor Temp"
|
||||
const PROGMEM char* kSleepTimerStr = D_STR_SLEEP_TIMER; ///< "Sleep Timer"
|
||||
const PROGMEM char* kSwingVModeStr = D_STR_SWINGVMODE; ///< "Swing(V) Mode"
|
||||
const PROGMEM char* kSwingVToggleStr = D_STR_SWINGVTOGGLE; ///<
|
||||
IRTEXT_CONST_STRING(kDisplayTempStr, D_STR_DISPLAYTEMP); ///< "Display Temp"
|
||||
IRTEXT_CONST_STRING(kSensorTempStr, D_STR_SENSORTEMP); ///< "Sensor Temp"
|
||||
IRTEXT_CONST_STRING(kSleepTimerStr, D_STR_SLEEP_TIMER); ///< "Sleep Timer"
|
||||
IRTEXT_CONST_STRING(kSwingVModeStr, D_STR_SWINGVMODE); ///< "Swing(V) Mode"
|
||||
IRTEXT_CONST_STRING(kSwingVToggleStr, D_STR_SWINGVTOGGLE); ///<
|
||||
///< "Swing(V) Toggle"
|
||||
const PROGMEM char* kTurboToggleStr = D_STR_TURBOTOGGLE; ///< "Turbo Toggle"
|
||||
IRTEXT_CONST_STRING(kTurboToggleStr, D_STR_TURBOTOGGLE); ///< "Turbo Toggle"
|
||||
|
||||
// Separators
|
||||
char kTimeSep = D_CHR_TIME_SEP; ///< ':'
|
||||
const PROGMEM char* kSpaceLBraceStr = D_STR_SPACELBRACE; ///< " ("
|
||||
const PROGMEM char* kCommaSpaceStr = D_STR_COMMASPACE; ///< ", "
|
||||
const PROGMEM char* kColonSpaceStr = D_STR_COLONSPACE; ///< ": "
|
||||
// Separators & Punctuation
|
||||
const char kTimeSep = D_CHR_TIME_SEP; ///< ':'
|
||||
IRTEXT_CONST_STRING(kSpaceLBraceStr, D_STR_SPACELBRACE); ///< " ("
|
||||
IRTEXT_CONST_STRING(kCommaSpaceStr, D_STR_COMMASPACE); ///< ", "
|
||||
IRTEXT_CONST_STRING(kColonSpaceStr, D_STR_COLONSPACE); ///< ": "
|
||||
IRTEXT_CONST_STRING(kDashStr, D_STR_DASH); ///< "-"
|
||||
|
||||
// IRutils
|
||||
// - Time
|
||||
const PROGMEM char* kDayStr = D_STR_DAY; ///< "Day"
|
||||
const PROGMEM char* kDaysStr = D_STR_DAYS; ///< "Days"
|
||||
const PROGMEM char* kHourStr = D_STR_HOUR; ///< "Hour"
|
||||
const PROGMEM char* kHoursStr = D_STR_HOURS; ///< "Hours"
|
||||
const PROGMEM char* kMinuteStr = D_STR_MINUTE; ///< "Minute"
|
||||
const PROGMEM char* kMinutesStr = D_STR_MINUTES; ///< "Minutes"
|
||||
const PROGMEM char* kSecondStr = D_STR_SECOND; ///< "Second"
|
||||
const PROGMEM char* kSecondsStr = D_STR_SECONDS; ///< "Seconds"
|
||||
const PROGMEM char* kNowStr = D_STR_NOW; ///< "Now"
|
||||
const PROGMEM char* kThreeLetterDayOfWeekStr = D_STR_THREELETTERDAYS; ///<
|
||||
IRTEXT_CONST_STRING(kDayStr, D_STR_DAY); ///< "Day"
|
||||
IRTEXT_CONST_STRING(kDaysStr, D_STR_DAYS); ///< "Days"
|
||||
IRTEXT_CONST_STRING(kHourStr, D_STR_HOUR); ///< "Hour"
|
||||
IRTEXT_CONST_STRING(kHoursStr, D_STR_HOURS); ///< "Hours"
|
||||
IRTEXT_CONST_STRING(kMinuteStr, D_STR_MINUTE); ///< "Minute"
|
||||
IRTEXT_CONST_STRING(kMinutesStr, D_STR_MINUTES); ///< "Minutes"
|
||||
IRTEXT_CONST_STRING(kSecondStr, D_STR_SECOND); ///< "Second"
|
||||
IRTEXT_CONST_STRING(kSecondsStr, D_STR_SECONDS); ///< "Seconds"
|
||||
IRTEXT_CONST_STRING(kNowStr, D_STR_NOW); ///< "Now"
|
||||
IRTEXT_CONST_STRING(kThreeLetterDayOfWeekStr, D_STR_THREELETTERDAYS); ///<
|
||||
///< "SunMonTueWedThuFriSat"
|
||||
const PROGMEM char* kYesStr = D_STR_YES; ///< "Yes"
|
||||
const PROGMEM char* kNoStr = D_STR_NO; ///< "No"
|
||||
const PROGMEM char* kTrueStr = D_STR_TRUE; ///< "True"
|
||||
const PROGMEM char* kFalseStr = D_STR_FALSE; ///< "False"
|
||||
IRTEXT_CONST_STRING(kYesStr, D_STR_YES); ///< "Yes"
|
||||
IRTEXT_CONST_STRING(kNoStr, D_STR_NO); ///< "No"
|
||||
IRTEXT_CONST_STRING(kTrueStr, D_STR_TRUE); ///< "True"
|
||||
IRTEXT_CONST_STRING(kFalseStr, D_STR_FALSE); ///< "False"
|
||||
|
||||
const PROGMEM char* kRepeatStr = D_STR_REPEAT; ///< "Repeat"
|
||||
const PROGMEM char* kCodeStr = D_STR_CODE; ///< "Code"
|
||||
const PROGMEM char* kBitsStr = D_STR_BITS; ///< "Bits"
|
||||
IRTEXT_CONST_STRING(kRepeatStr, D_STR_REPEAT); ///< "Repeat"
|
||||
IRTEXT_CONST_STRING(kCodeStr, D_STR_CODE); ///< "Code"
|
||||
IRTEXT_CONST_STRING(kBitsStr, D_STR_BITS); ///< "Bits"
|
||||
|
||||
// Model Names
|
||||
IRTEXT_CONST_STRING(kYaw1fStr, D_STR_YAW1F); ///< "YAW1F"
|
||||
IRTEXT_CONST_STRING(kYbofbStr, D_STR_YBOFB); ///< "YBOFB"
|
||||
IRTEXT_CONST_STRING(kV9014557AStr, D_STR_V9014557_A); ///< "V9014557-A"
|
||||
IRTEXT_CONST_STRING(kV9014557BStr, D_STR_V9014557_B); ///< "V9014557-B"
|
||||
IRTEXT_CONST_STRING(kRlt0541htaaStr, D_STR_RLT0541HTA_A); ///< "R-LT0541-HTA-A"
|
||||
IRTEXT_CONST_STRING(kRlt0541htabStr, D_STR_RLT0541HTA_B); ///< "R-LT0541-HTA-B"
|
||||
IRTEXT_CONST_STRING(kArrah2eStr, D_STR_ARRAH2E); ///< "ARRAH2E"
|
||||
IRTEXT_CONST_STRING(kArdb1Str, D_STR_ARDB1); ///< "ARDB1"
|
||||
IRTEXT_CONST_STRING(kArreb1eStr, D_STR_ARREB1E); ///< "ARREB1E"
|
||||
IRTEXT_CONST_STRING(kArjw2Str, D_STR_ARJW2); ///< "ARJW2"
|
||||
IRTEXT_CONST_STRING(kArry4Str, D_STR_ARRY4); ///< "ARRY4"
|
||||
IRTEXT_CONST_STRING(kArrew4eStr, D_STR_ARREW4E); ///< "ARREW4E"
|
||||
IRTEXT_CONST_STRING(kGe6711ar2853mStr, D_STR_GE6711AR2853M); ///<
|
||||
///< "GE6711AR2853M"
|
||||
IRTEXT_CONST_STRING(kAkb75215403Str, D_STR_AKB75215403); ///< "AKB75215403"
|
||||
IRTEXT_CONST_STRING(kAkb74955603Str, D_STR_AKB74955603); ///< "AKB74955603"
|
||||
IRTEXT_CONST_STRING(kAkb73757604Str, D_STR_AKB73757604); ///< "AKB73757604"
|
||||
IRTEXT_CONST_STRING(kKkg9ac1Str, D_STR_KKG9AC1); ///< "KKG9AC1"
|
||||
IRTEXT_CONST_STRING(kKkg29ac1Str, D_STR_KKG29AC1); ///< "KKG29AC1"
|
||||
IRTEXT_CONST_STRING(kLkeStr, D_STR_LKE); ///< "LKE"
|
||||
IRTEXT_CONST_STRING(kNkeStr, D_STR_NKE); ///< "NKE"
|
||||
IRTEXT_CONST_STRING(kDkeStr, D_STR_DKE); ///< "DKE"
|
||||
IRTEXT_CONST_STRING(kPkrStr, D_STR_PKR); ///< "PKR"
|
||||
IRTEXT_CONST_STRING(kJkeStr, D_STR_JKE); ///< "JKE"
|
||||
IRTEXT_CONST_STRING(kCkpStr, D_STR_CKP); ///< "CKP"
|
||||
IRTEXT_CONST_STRING(kRkrStr, D_STR_RKR); ///< "RKR"
|
||||
IRTEXT_CONST_STRING(kPanasonicLkeStr, D_STR_PANASONICLKE); ///< "PANASONICLKE"
|
||||
IRTEXT_CONST_STRING(kPanasonicNkeStr, D_STR_PANASONICNKE); ///< "PANASONICNKE"
|
||||
IRTEXT_CONST_STRING(kPanasonicDkeStr, D_STR_PANASONICDKE); ///< "PANASONICDKE"
|
||||
IRTEXT_CONST_STRING(kPanasonicPkrStr, D_STR_PANASONICPKR); ///< "PANASONICPKR"
|
||||
IRTEXT_CONST_STRING(kPanasonicJkeStr, D_STR_PANASONICJKE); ///< "PANASONICJKE"
|
||||
IRTEXT_CONST_STRING(kPanasonicCkpStr, D_STR_PANASONICCKP); ///< "PANASONICCKP"
|
||||
IRTEXT_CONST_STRING(kPanasonicRkrStr, D_STR_PANASONICRKR); ///< "PANASONICRKR"
|
||||
IRTEXT_CONST_STRING(kA907Str, D_STR_A907); ///< "A907"
|
||||
IRTEXT_CONST_STRING(kA705Str, D_STR_A705); ///< "A705"
|
||||
IRTEXT_CONST_STRING(kA903Str, D_STR_A903); ///< "A903"
|
||||
IRTEXT_CONST_STRING(kTac09chsdStr, D_STR_TAC09CHSD); ///< "TAC09CHSD"
|
||||
IRTEXT_CONST_STRING(kGz055be1Str, D_STR_GZ055BE1); ///< "GZ055BE1"
|
||||
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"
|
||||
|
||||
// Protocol Names
|
||||
// Needs to be in decode_type_t order.
|
||||
const PROGMEM char *kAllProtocolNamesStr =
|
||||
IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) {
|
||||
D_STR_UNUSED "\x0"
|
||||
D_STR_RC5 "\x0"
|
||||
D_STR_RC6 "\x0"
|
||||
|
@ -293,5 +379,11 @@ const PROGMEM char *kAllProtocolNamesStr =
|
|||
D_STR_TROTEC_3550 "\x0"
|
||||
D_STR_SANYO_AC88 "\x0"
|
||||
D_STR_BOSE "\x0"
|
||||
D_STR_ARRIS "\x0"
|
||||
D_STR_RHOSS "\x0"
|
||||
D_STR_AIRTON "\x0"
|
||||
///< New protocol strings should be added just above this line.
|
||||
"\x0"; ///< This string requires double null termination.
|
||||
"\x0" ///< This string requires double null termination.
|
||||
};
|
||||
|
||||
IRTEXT_CONST_BLOB_PTR(kAllProtocolNamesStr);
|
||||
|
|
|
@ -12,158 +12,224 @@
|
|||
// Constant text to be shared across all object files.
|
||||
// This means there is only one copy of the character/string/text etc.
|
||||
|
||||
extern char kTimeSep;
|
||||
extern const char* k10CHeatStr;
|
||||
extern const char* k3DStr;
|
||||
extern const char* k6thSenseStr;
|
||||
extern const char* k8CHeatStr;
|
||||
extern const char* kAirFlowStr;
|
||||
extern const char *kAllProtocolNamesStr;
|
||||
extern const char* kAutomaticStr;
|
||||
extern const char* kAutoStr;
|
||||
extern const char* kBeepStr;
|
||||
extern const char* kBitsStr;
|
||||
extern const char* kBottomStr;
|
||||
extern const char* kBreezeStr;
|
||||
extern const char* kButtonStr;
|
||||
extern const char* kCancelStr;
|
||||
extern const char* kCeilingStr;
|
||||
extern const char* kCelsiusFahrenheitStr;
|
||||
extern const char* kCelsiusStr;
|
||||
extern const char* kCentreStr;
|
||||
extern const char* kChangeStr;
|
||||
extern const char* kCirculateStr;
|
||||
extern const char* kCleanStr;
|
||||
extern const char* kClockStr;
|
||||
extern const char* kCodeStr;
|
||||
extern const char* kColonSpaceStr;
|
||||
extern const char* kComfortStr;
|
||||
extern const char* kCommandStr;
|
||||
extern const char* kCommaSpaceStr;
|
||||
extern const char* kCoolStr;
|
||||
extern const char* kDaysStr;
|
||||
extern const char* kDayStr;
|
||||
extern const char* kDisplayTempStr;
|
||||
extern const char* kDownStr;
|
||||
extern const char* kDryStr;
|
||||
extern const char* kEconoStr;
|
||||
extern const char* kEconoToggleStr;
|
||||
extern const char* kEyeAutoStr;
|
||||
extern const char* kEyeStr;
|
||||
extern const char* kFalseStr;
|
||||
extern const char* kFanOnlyStr;
|
||||
extern const char* kFanStr;
|
||||
extern const char* kFastStr;
|
||||
extern const char* kFilterStr;
|
||||
extern const char* kFixedStr;
|
||||
extern const char* kFollowStr;
|
||||
extern const char* kFreshStr;
|
||||
extern const char* kHealthStr;
|
||||
extern const char* kHeatStr;
|
||||
extern const char* kHighestStr;
|
||||
extern const char* kHighStr;
|
||||
extern const char* kHiStr;
|
||||
extern const char* kHoldStr;
|
||||
extern const char* kHoursStr;
|
||||
extern const char* kHourStr;
|
||||
extern const char* kHumidStr;
|
||||
extern const char* kIdStr;
|
||||
extern const char* kIFeelStr;
|
||||
extern const char* kInsideStr;
|
||||
extern const char* kIonStr;
|
||||
extern const char* kLastStr;
|
||||
extern const char* kLeftMaxStr;
|
||||
extern const char* kLeftStr;
|
||||
extern const char* kLightStr;
|
||||
extern const char* kLightToggleStr;
|
||||
extern const char* kLoStr;
|
||||
extern const char* kLoudStr;
|
||||
extern const char* kLowerStr;
|
||||
extern const char* kLowestStr;
|
||||
extern const char* kLowStr;
|
||||
extern const char* kManualStr;
|
||||
extern const char* kMaximumStr;
|
||||
extern const char* kMaxLeftStr;
|
||||
extern const char* kMaxRightStr;
|
||||
extern const char* kMaxStr;
|
||||
extern const char* kMediumStr;
|
||||
extern const char* kMedStr;
|
||||
extern const char* kMiddleStr;
|
||||
extern const char* kMidStr;
|
||||
extern const char* kMinimumStr;
|
||||
extern const char* kMinStr;
|
||||
extern const char* kMinutesStr;
|
||||
extern const char* kMinuteStr;
|
||||
extern const char* kModelStr;
|
||||
extern const char* kModeStr;
|
||||
extern const char* kMouldStr;
|
||||
extern const char* kMoveStr;
|
||||
extern const char* kNAStr;
|
||||
extern const char* kNightStr;
|
||||
extern const char* kNoStr;
|
||||
extern const char* kNowStr;
|
||||
extern const char* kOffStr;
|
||||
extern const char* kOffTimerStr;
|
||||
extern const char* kOnStr;
|
||||
extern const char* kOnTimerStr;
|
||||
extern const char* kOutsideQuietStr;
|
||||
extern const char* kOutsideStr;
|
||||
extern const char* kPowerButtonStr;
|
||||
extern const char* kPowerfulStr;
|
||||
extern const char* kPowerStr;
|
||||
extern const char* kPowerToggleStr;
|
||||
extern const char* kPreviousPowerStr;
|
||||
extern const char* kProtocolStr;
|
||||
extern const char* kPurifyStr;
|
||||
extern const char* kQuietStr;
|
||||
extern const char* kRecycleStr;
|
||||
extern const char* kRepeatStr;
|
||||
extern const char* kRightMaxStr;
|
||||
extern const char* kRightStr;
|
||||
extern const char* kRoomStr;
|
||||
extern const char* kSaveStr;
|
||||
extern const char* kSecondsStr;
|
||||
extern const char* kSecondStr;
|
||||
extern const char* kSensorStr;
|
||||
extern const char* kSensorTempStr;
|
||||
extern const char* kSetStr;
|
||||
extern const char* kSilentStr;
|
||||
extern const char* kSleepStr;
|
||||
extern const char* kSleepTimerStr;
|
||||
extern const char* kSlowStr;
|
||||
extern const char* kSpaceLBraceStr;
|
||||
extern const char* kSpecialStr;
|
||||
extern const char* kStartStr;
|
||||
extern const char* kStepStr;
|
||||
extern const char* kStopStr;
|
||||
extern const char* kSuperStr;
|
||||
extern const char* kSwingHStr;
|
||||
extern const char* kSwingStr;
|
||||
extern const char* kSwingVModeStr;
|
||||
extern const char* kSwingVStr;
|
||||
extern const char* kSwingVToggleStr;
|
||||
extern const char* kTempDownStr;
|
||||
extern const char* kTempStr;
|
||||
extern const char* kTempUpStr;
|
||||
extern const char* kThreeLetterDayOfWeekStr;
|
||||
extern const char* kTimerModeStr;
|
||||
extern const char* kTimerStr;
|
||||
extern const char* kToggleStr;
|
||||
extern const char* kTopStr;
|
||||
extern const char* kTrueStr;
|
||||
extern const char* kTurboStr;
|
||||
extern const char* kTurboToggleStr;
|
||||
extern const char* kTypeStr;
|
||||
extern const char* kUnknownStr;
|
||||
extern const char* kUpperStr;
|
||||
extern const char* kUpStr;
|
||||
extern const char* kVaneStr;
|
||||
extern const char* kWallStr;
|
||||
extern const char* kWeeklyTimerStr;
|
||||
extern const char* kWideStr;
|
||||
extern const char* kWifiStr;
|
||||
extern const char* kXFanStr;
|
||||
extern const char* kYesStr;
|
||||
extern const char* kZoneFollowStr;
|
||||
#ifdef ESP8266
|
||||
class __FlashStringHelper;
|
||||
#define IRTEXT_CONST_PTR_CAST(PTR)\
|
||||
reinterpret_cast<const __FlashStringHelper*>(PTR)
|
||||
#define IRTEXT_CONST_PTR(NAME) const __FlashStringHelper* const NAME
|
||||
#else // ESP8266
|
||||
#define IRTEXT_CONST_PTR_CAST(PTR) PTR
|
||||
#define IRTEXT_CONST_PTR(NAME) const char* const NAME
|
||||
#endif // ESP8266
|
||||
|
||||
extern const char kTimeSep;
|
||||
extern IRTEXT_CONST_PTR(k0Str);
|
||||
extern IRTEXT_CONST_PTR(k10CHeatStr);
|
||||
extern IRTEXT_CONST_PTR(k122lzfStr);
|
||||
extern IRTEXT_CONST_PTR(k1Str);
|
||||
extern IRTEXT_CONST_PTR(k3DStr);
|
||||
extern IRTEXT_CONST_PTR(k6thSenseStr);
|
||||
extern IRTEXT_CONST_PTR(k8CHeatStr);
|
||||
extern IRTEXT_CONST_PTR(kA705Str);
|
||||
extern IRTEXT_CONST_PTR(kA903Str);
|
||||
extern IRTEXT_CONST_PTR(kA907Str);
|
||||
extern IRTEXT_CONST_PTR(kAirFlowStr);
|
||||
extern IRTEXT_CONST_PTR(kAkb73757604Str);
|
||||
extern IRTEXT_CONST_PTR(kAkb74955603Str);
|
||||
extern IRTEXT_CONST_PTR(kAkb75215403Str);
|
||||
extern IRTEXT_CONST_PTR(kArdb1Str);
|
||||
extern IRTEXT_CONST_PTR(kArjw2Str);
|
||||
extern IRTEXT_CONST_PTR(kArrah2eStr);
|
||||
extern IRTEXT_CONST_PTR(kArreb1eStr);
|
||||
extern IRTEXT_CONST_PTR(kArrew4eStr);
|
||||
extern IRTEXT_CONST_PTR(kArry4Str);
|
||||
extern IRTEXT_CONST_PTR(kAutomaticStr);
|
||||
extern IRTEXT_CONST_PTR(kAutoStr);
|
||||
extern IRTEXT_CONST_PTR(kBeepStr);
|
||||
extern IRTEXT_CONST_PTR(kBitsStr);
|
||||
extern IRTEXT_CONST_PTR(kBottomStr);
|
||||
extern IRTEXT_CONST_PTR(kBreezeStr);
|
||||
extern IRTEXT_CONST_PTR(kButtonStr);
|
||||
extern IRTEXT_CONST_PTR(kCancelStr);
|
||||
extern IRTEXT_CONST_PTR(kCeilingStr);
|
||||
extern IRTEXT_CONST_PTR(kCelsiusFahrenheitStr);
|
||||
extern IRTEXT_CONST_PTR(kCelsiusStr);
|
||||
extern IRTEXT_CONST_PTR(kCentreStr);
|
||||
extern IRTEXT_CONST_PTR(kChangeStr);
|
||||
extern IRTEXT_CONST_PTR(kCirculateStr);
|
||||
extern IRTEXT_CONST_PTR(kCkpStr);
|
||||
extern IRTEXT_CONST_PTR(kCleanStr);
|
||||
extern IRTEXT_CONST_PTR(kClockStr);
|
||||
extern IRTEXT_CONST_PTR(kCodeStr);
|
||||
extern IRTEXT_CONST_PTR(kColonSpaceStr);
|
||||
extern IRTEXT_CONST_PTR(kComfortStr);
|
||||
extern IRTEXT_CONST_PTR(kCommandStr);
|
||||
extern IRTEXT_CONST_PTR(kCommaSpaceStr);
|
||||
extern IRTEXT_CONST_PTR(kCoolingStr);
|
||||
extern IRTEXT_CONST_PTR(kCoolStr);
|
||||
extern IRTEXT_CONST_PTR(kDashStr);
|
||||
extern IRTEXT_CONST_PTR(kDaysStr);
|
||||
extern IRTEXT_CONST_PTR(kDayStr);
|
||||
extern IRTEXT_CONST_PTR(kDehumidifyStr);
|
||||
extern IRTEXT_CONST_PTR(kDg11j104Str);
|
||||
extern IRTEXT_CONST_PTR(kDg11j13aStr);
|
||||
extern IRTEXT_CONST_PTR(kDg11j191Str);
|
||||
extern IRTEXT_CONST_PTR(kDisplayTempStr);
|
||||
extern IRTEXT_CONST_PTR(kDkeStr);
|
||||
extern IRTEXT_CONST_PTR(kDownStr);
|
||||
extern IRTEXT_CONST_PTR(kDryingStr);
|
||||
extern IRTEXT_CONST_PTR(kDryStr);
|
||||
extern IRTEXT_CONST_PTR(kEconoStr);
|
||||
extern IRTEXT_CONST_PTR(kEconoToggleStr);
|
||||
extern IRTEXT_CONST_PTR(kEyeAutoStr);
|
||||
extern IRTEXT_CONST_PTR(kEyeStr);
|
||||
extern IRTEXT_CONST_PTR(kFalseStr);
|
||||
extern IRTEXT_CONST_PTR(kFanOnlyNoSpaceStr);
|
||||
extern IRTEXT_CONST_PTR(kFan_OnlyStr);
|
||||
extern IRTEXT_CONST_PTR(kFanOnlyStr);
|
||||
extern IRTEXT_CONST_PTR(kFanOnlyWithSpaceStr);
|
||||
extern IRTEXT_CONST_PTR(kFanStr);
|
||||
extern IRTEXT_CONST_PTR(kFastStr);
|
||||
extern IRTEXT_CONST_PTR(kFilterStr);
|
||||
extern IRTEXT_CONST_PTR(kFixedStr);
|
||||
extern IRTEXT_CONST_PTR(kFollowStr);
|
||||
extern IRTEXT_CONST_PTR(kFreshStr);
|
||||
extern IRTEXT_CONST_PTR(kGe6711ar2853mStr);
|
||||
extern IRTEXT_CONST_PTR(kGz055be1Str);
|
||||
extern IRTEXT_CONST_PTR(kHealthStr);
|
||||
extern IRTEXT_CONST_PTR(kHeatingStr);
|
||||
extern IRTEXT_CONST_PTR(kHeatStr);
|
||||
extern IRTEXT_CONST_PTR(kHighestStr);
|
||||
extern IRTEXT_CONST_PTR(kHighStr);
|
||||
extern IRTEXT_CONST_PTR(kHiStr);
|
||||
extern IRTEXT_CONST_PTR(kHoldStr);
|
||||
extern IRTEXT_CONST_PTR(kHoursStr);
|
||||
extern IRTEXT_CONST_PTR(kHourStr);
|
||||
extern IRTEXT_CONST_PTR(kHumidStr);
|
||||
extern IRTEXT_CONST_PTR(kIdStr);
|
||||
extern IRTEXT_CONST_PTR(kIFeelStr);
|
||||
extern IRTEXT_CONST_PTR(kInsideStr);
|
||||
extern IRTEXT_CONST_PTR(kIonStr);
|
||||
extern IRTEXT_CONST_PTR(kJkeStr);
|
||||
extern IRTEXT_CONST_PTR(kKkg29ac1Str);
|
||||
extern IRTEXT_CONST_PTR(kKkg9ac1Str);
|
||||
extern IRTEXT_CONST_PTR(kLastStr);
|
||||
extern IRTEXT_CONST_PTR(kLeftMaxNoSpaceStr);
|
||||
extern IRTEXT_CONST_PTR(kLeftMaxStr);
|
||||
extern IRTEXT_CONST_PTR(kLeftStr);
|
||||
extern IRTEXT_CONST_PTR(kLightStr);
|
||||
extern IRTEXT_CONST_PTR(kLightToggleStr);
|
||||
extern IRTEXT_CONST_PTR(kLkeStr);
|
||||
extern IRTEXT_CONST_PTR(kLoStr);
|
||||
extern IRTEXT_CONST_PTR(kLockStr);
|
||||
extern IRTEXT_CONST_PTR(kLoudStr);
|
||||
extern IRTEXT_CONST_PTR(kLowerStr);
|
||||
extern IRTEXT_CONST_PTR(kLowestStr);
|
||||
extern IRTEXT_CONST_PTR(kLowStr);
|
||||
extern IRTEXT_CONST_PTR(kManualStr);
|
||||
extern IRTEXT_CONST_PTR(kMaximumStr);
|
||||
extern IRTEXT_CONST_PTR(kMaxLeftNoSpaceStr);
|
||||
extern IRTEXT_CONST_PTR(kMaxLeftStr);
|
||||
extern IRTEXT_CONST_PTR(kMaxRightNoSpaceStr);
|
||||
extern IRTEXT_CONST_PTR(kMaxRightStr);
|
||||
extern IRTEXT_CONST_PTR(kMaxStr);
|
||||
extern IRTEXT_CONST_PTR(kMediumStr);
|
||||
extern IRTEXT_CONST_PTR(kMedStr);
|
||||
extern IRTEXT_CONST_PTR(kMiddleStr);
|
||||
extern IRTEXT_CONST_PTR(kMidStr);
|
||||
extern IRTEXT_CONST_PTR(kMinimumStr);
|
||||
extern IRTEXT_CONST_PTR(kMinStr);
|
||||
extern IRTEXT_CONST_PTR(kMinutesStr);
|
||||
extern IRTEXT_CONST_PTR(kMinuteStr);
|
||||
extern IRTEXT_CONST_PTR(kModelStr);
|
||||
extern IRTEXT_CONST_PTR(kModeStr);
|
||||
extern IRTEXT_CONST_PTR(kMouldStr);
|
||||
extern IRTEXT_CONST_PTR(kMoveStr);
|
||||
extern IRTEXT_CONST_PTR(kNAStr);
|
||||
extern IRTEXT_CONST_PTR(kNightStr);
|
||||
extern IRTEXT_CONST_PTR(kNkeStr);
|
||||
extern IRTEXT_CONST_PTR(kNoStr);
|
||||
extern IRTEXT_CONST_PTR(kNowStr);
|
||||
extern IRTEXT_CONST_PTR(kOffStr);
|
||||
extern IRTEXT_CONST_PTR(kOffTimerStr);
|
||||
extern IRTEXT_CONST_PTR(kOnStr);
|
||||
extern IRTEXT_CONST_PTR(kOnTimerStr);
|
||||
extern IRTEXT_CONST_PTR(kOutsideQuietStr);
|
||||
extern IRTEXT_CONST_PTR(kOutsideStr);
|
||||
extern IRTEXT_CONST_PTR(kPanasonicCkpStr);
|
||||
extern IRTEXT_CONST_PTR(kPanasonicDkeStr);
|
||||
extern IRTEXT_CONST_PTR(kPanasonicJkeStr);
|
||||
extern IRTEXT_CONST_PTR(kPanasonicLkeStr);
|
||||
extern IRTEXT_CONST_PTR(kPanasonicNkeStr);
|
||||
extern IRTEXT_CONST_PTR(kPanasonicPkrStr);
|
||||
extern IRTEXT_CONST_PTR(kPanasonicRkrStr);
|
||||
extern IRTEXT_CONST_PTR(kPkrStr);
|
||||
extern IRTEXT_CONST_PTR(kPowerButtonStr);
|
||||
extern IRTEXT_CONST_PTR(kPowerfulStr);
|
||||
extern IRTEXT_CONST_PTR(kPowerStr);
|
||||
extern IRTEXT_CONST_PTR(kPowerToggleStr);
|
||||
extern IRTEXT_CONST_PTR(kPreviousPowerStr);
|
||||
extern IRTEXT_CONST_PTR(kProtocolStr);
|
||||
extern IRTEXT_CONST_PTR(kPurifyStr);
|
||||
extern IRTEXT_CONST_PTR(kQuietStr);
|
||||
extern IRTEXT_CONST_PTR(kRecycleStr);
|
||||
extern IRTEXT_CONST_PTR(kRepeatStr);
|
||||
extern IRTEXT_CONST_PTR(kRightMaxNoSpaceStr);
|
||||
extern IRTEXT_CONST_PTR(kRightMaxStr);
|
||||
extern IRTEXT_CONST_PTR(kRightStr);
|
||||
extern IRTEXT_CONST_PTR(kRkrStr);
|
||||
extern IRTEXT_CONST_PTR(kRlt0541htaaStr);
|
||||
extern IRTEXT_CONST_PTR(kRlt0541htabStr);
|
||||
extern IRTEXT_CONST_PTR(kRoomStr);
|
||||
extern IRTEXT_CONST_PTR(kSaveStr);
|
||||
extern IRTEXT_CONST_PTR(kSecondsStr);
|
||||
extern IRTEXT_CONST_PTR(kSecondStr);
|
||||
extern IRTEXT_CONST_PTR(kSensorStr);
|
||||
extern IRTEXT_CONST_PTR(kSensorTempStr);
|
||||
extern IRTEXT_CONST_PTR(kSetStr);
|
||||
extern IRTEXT_CONST_PTR(kSilentStr);
|
||||
extern IRTEXT_CONST_PTR(kSleepStr);
|
||||
extern IRTEXT_CONST_PTR(kSleepTimerStr);
|
||||
extern IRTEXT_CONST_PTR(kSlowStr);
|
||||
extern IRTEXT_CONST_PTR(kSpaceLBraceStr);
|
||||
extern IRTEXT_CONST_PTR(kSpecialStr);
|
||||
extern IRTEXT_CONST_PTR(kStartStr);
|
||||
extern IRTEXT_CONST_PTR(kStepStr);
|
||||
extern IRTEXT_CONST_PTR(kStopStr);
|
||||
extern IRTEXT_CONST_PTR(kSuperStr);
|
||||
extern IRTEXT_CONST_PTR(kSwingHStr);
|
||||
extern IRTEXT_CONST_PTR(kSwingStr);
|
||||
extern IRTEXT_CONST_PTR(kSwingVModeStr);
|
||||
extern IRTEXT_CONST_PTR(kSwingVStr);
|
||||
extern IRTEXT_CONST_PTR(kSwingVToggleStr);
|
||||
extern IRTEXT_CONST_PTR(kTac09chsdStr);
|
||||
extern IRTEXT_CONST_PTR(kTempDownStr);
|
||||
extern IRTEXT_CONST_PTR(kTempStr);
|
||||
extern IRTEXT_CONST_PTR(kTempUpStr);
|
||||
extern IRTEXT_CONST_PTR(kThreeLetterDayOfWeekStr);
|
||||
extern IRTEXT_CONST_PTR(kTimerModeStr);
|
||||
extern IRTEXT_CONST_PTR(kTimerStr);
|
||||
extern IRTEXT_CONST_PTR(kToggleStr);
|
||||
extern IRTEXT_CONST_PTR(kTopStr);
|
||||
extern IRTEXT_CONST_PTR(kTrueStr);
|
||||
extern IRTEXT_CONST_PTR(kTurboStr);
|
||||
extern IRTEXT_CONST_PTR(kTurboToggleStr);
|
||||
extern IRTEXT_CONST_PTR(kTypeStr);
|
||||
extern IRTEXT_CONST_PTR(kUnknownStr);
|
||||
extern IRTEXT_CONST_PTR(kUpperStr);
|
||||
extern IRTEXT_CONST_PTR(kUpStr);
|
||||
extern IRTEXT_CONST_PTR(kV9014557AStr);
|
||||
extern IRTEXT_CONST_PTR(kV9014557BStr);
|
||||
extern IRTEXT_CONST_PTR(kVaneStr);
|
||||
extern IRTEXT_CONST_PTR(kWallStr);
|
||||
extern IRTEXT_CONST_PTR(kWeeklyTimerStr);
|
||||
extern IRTEXT_CONST_PTR(kWideStr);
|
||||
extern IRTEXT_CONST_PTR(kWifiStr);
|
||||
extern IRTEXT_CONST_PTR(kXFanStr);
|
||||
extern IRTEXT_CONST_PTR(kYaw1fStr);
|
||||
extern IRTEXT_CONST_PTR(kYbofbStr);
|
||||
extern IRTEXT_CONST_PTR(kYesStr);
|
||||
extern IRTEXT_CONST_PTR(kZoneFollowStr);
|
||||
extern IRTEXT_CONST_PTR(kAllProtocolNamesStr);
|
||||
|
||||
#endif // IRTEXT_H_
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2017 David Conran
|
||||
// Copyright 2017-2021 David Conran
|
||||
|
||||
#include "IRutils.h"
|
||||
#ifndef UNIT_TEST
|
||||
|
@ -17,6 +17,27 @@
|
|||
#include "IRsend.h"
|
||||
#include "IRtext.h"
|
||||
|
||||
// On the ESP8266 platform we need to use a set of ..._P functions
|
||||
// to handle the strings stored in the flash address space.
|
||||
#ifndef STRCASECMP
|
||||
#if defined(ESP8266)
|
||||
#define STRCASECMP(LHS, RHS) \
|
||||
strcasecmp_P(LHS, reinterpret_cast<const char*>(RHS))
|
||||
#else // ESP8266
|
||||
#define STRCASECMP strcasecmp
|
||||
#endif // ESP8266
|
||||
#endif // STRCASECMP
|
||||
#ifndef STRLEN
|
||||
#if defined(ESP8266)
|
||||
#define STRLEN(PTR) strlen_P(PTR)
|
||||
#else // ESP8266
|
||||
#define STRLEN(PTR) strlen(PTR)
|
||||
#endif // ESP8266
|
||||
#endif // STRLEN
|
||||
#ifndef FPSTR
|
||||
#define FPSTR(X) X
|
||||
#endif // FPSTR
|
||||
|
||||
/// Reverse the order of the requested least significant nr. of bits.
|
||||
/// @param[in] input Bit pattern/integer to reverse.
|
||||
/// @param[in] nbits Nr. of bits to reverse. (LSB -> MSB)
|
||||
|
@ -74,7 +95,10 @@ String uint64ToString(uint64_t input, uint8_t base) {
|
|||
/// @returns A String representation of the integer.
|
||||
String int64ToString(int64_t input, uint8_t base) {
|
||||
if (input < 0) {
|
||||
return "-" + uint64ToString(-input, base);
|
||||
// Using String(kDashStr) to keep compatible with old arduino
|
||||
// frameworks. Not needed with 3.0.2.
|
||||
///> @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1639#issuecomment-944906016
|
||||
return String(kDashStr) + uint64ToString(-input, base);
|
||||
}
|
||||
return uint64ToString(input, base);
|
||||
}
|
||||
|
@ -93,20 +117,19 @@ void serialPrintUint64(uint64_t input, uint8_t base) {
|
|||
/// @param[in] str A C-style string containing a protocol name or number.
|
||||
/// @return A decode_type_t enum. (decode_type_t::UNKNOWN if no match.)
|
||||
decode_type_t strToDecodeType(const char * const str) {
|
||||
const char *ptr = kAllProtocolNamesStr;
|
||||
uint16_t length = strlen(ptr);
|
||||
auto *ptr = reinterpret_cast<const char*>(kAllProtocolNamesStr);
|
||||
uint16_t length = STRLEN(ptr);
|
||||
for (uint16_t i = 0; length; i++) {
|
||||
if (!strcasecmp(str, ptr)) return (decode_type_t)i;
|
||||
if (!STRCASECMP(str, ptr)) return (decode_type_t)i;
|
||||
ptr += length + 1;
|
||||
length = strlen(ptr);
|
||||
length = STRLEN(ptr);
|
||||
}
|
||||
|
||||
// Handle integer values of the type by converting to a string and back again.
|
||||
decode_type_t result = strToDecodeType(
|
||||
typeToString((decode_type_t)atoi(str)).c_str());
|
||||
if (result > 0)
|
||||
return result;
|
||||
else
|
||||
|
||||
return decode_type_t::UNKNOWN;
|
||||
}
|
||||
|
||||
|
@ -117,16 +140,20 @@ decode_type_t strToDecodeType(const char * const str) {
|
|||
String typeToString(const decode_type_t protocol, const bool isRepeat) {
|
||||
String result = "";
|
||||
result.reserve(30); // Size of longest protocol name + " (Repeat)"
|
||||
const char *ptr = kAllProtocolNamesStr;
|
||||
if (protocol > kLastDecodeType || protocol == decode_type_t::UNKNOWN) {
|
||||
result = kUnknownStr;
|
||||
} else {
|
||||
for (uint16_t i = 0; i <= protocol && strlen(ptr); i++) {
|
||||
auto *ptr = reinterpret_cast<const char*>(kAllProtocolNamesStr);
|
||||
if (protocol > kLastDecodeType || protocol == decode_type_t::UNKNOWN) {
|
||||
result = kUnknownStr;
|
||||
} else {
|
||||
for (uint16_t i = 0; i <= protocol && STRLEN(ptr); i++) {
|
||||
if (i == protocol) {
|
||||
result = ptr;
|
||||
result = FPSTR(ptr);
|
||||
break;
|
||||
}
|
||||
ptr += strlen(ptr) + 1;
|
||||
ptr += STRLEN(ptr) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isRepeat) {
|
||||
|
@ -175,6 +202,7 @@ bool hasACState(const decode_type_t protocol) {
|
|||
case MWM:
|
||||
case NEOCLIMA:
|
||||
case PANASONIC_AC:
|
||||
case RHOSS:
|
||||
case SAMSUNG_AC:
|
||||
case SANYO_AC:
|
||||
case SANYO_AC88:
|
||||
|
@ -318,7 +346,7 @@ String resultToTimingInfo(const decode_results * const results) {
|
|||
|
||||
for (uint16_t i = 1; i < results->rawlen; i++) {
|
||||
if (i % 2 == 0)
|
||||
output += '-'; // even
|
||||
output += kDashStr; // even
|
||||
else
|
||||
output += F(" +"); // odd
|
||||
value = uint64ToString(results->rawbuf[i] * kRawTick);
|
||||
|
@ -515,7 +543,18 @@ namespace irutils {
|
|||
/// @return The resulting String.
|
||||
String addBoolToString(const bool value, const String label,
|
||||
const bool precomma) {
|
||||
return addLabeledString((value ? kOnStr : kOffStr), label, precomma);
|
||||
return addLabeledString(value ? kOnStr : kOffStr, label, precomma);
|
||||
}
|
||||
|
||||
/// Create a String with a colon separated toggle flag suitable for Humans.
|
||||
/// e.g. "Light: Toggle", "Light: -"
|
||||
/// @param[in] toggle The value of the toggle to come after the label.
|
||||
/// @param[in] label The label to precede the value.
|
||||
/// @param[in] precomma Should the output string start with ", " or not?
|
||||
/// @return The resulting String.
|
||||
String addToggleToString(const bool toggle, const String label,
|
||||
const bool precomma) {
|
||||
return addLabeledString(toggle ? kToggleStr : kDashStr, label, precomma);
|
||||
}
|
||||
|
||||
/// Create a String with a colon separated labeled Integer suitable for
|
||||
|
@ -547,74 +586,100 @@ namespace irutils {
|
|||
/// @param[in] protocol The IR protocol.
|
||||
/// @param[in] model The model number for that protocol.
|
||||
/// @return The resulting String.
|
||||
/// @note After adding a new model you should update IRac::strToModel() too.
|
||||
String modelToStr(const decode_type_t protocol, const int16_t model) {
|
||||
switch (protocol) {
|
||||
case decode_type_t::FUJITSU_AC:
|
||||
switch (model) {
|
||||
case fujitsu_ac_remote_model_t::ARRAH2E: return F("ARRAH2E");
|
||||
case fujitsu_ac_remote_model_t::ARDB1: return F("ARDB1");
|
||||
case fujitsu_ac_remote_model_t::ARREB1E: return F("ARREB1E");
|
||||
case fujitsu_ac_remote_model_t::ARJW2: return F("ARJW2");
|
||||
case fujitsu_ac_remote_model_t::ARRY4: return F("ARRY4");
|
||||
case fujitsu_ac_remote_model_t::ARREW4E: return F("ARREW4E");
|
||||
case fujitsu_ac_remote_model_t::ARRAH2E: return kArrah2eStr;
|
||||
case fujitsu_ac_remote_model_t::ARDB1: return kArdb1Str;
|
||||
case fujitsu_ac_remote_model_t::ARREB1E: return kArreb1eStr;
|
||||
case fujitsu_ac_remote_model_t::ARJW2: return kArjw2Str;
|
||||
case fujitsu_ac_remote_model_t::ARRY4: return kArry4Str;
|
||||
case fujitsu_ac_remote_model_t::ARREW4E: return kArrew4eStr;
|
||||
default: return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
case decode_type_t::GREE:
|
||||
switch (model) {
|
||||
case gree_ac_remote_model_t::YAW1F: return F("YAW1F");
|
||||
case gree_ac_remote_model_t::YBOFB: return F("YBOFB");
|
||||
case gree_ac_remote_model_t::YAW1F: return kYaw1fStr;
|
||||
case gree_ac_remote_model_t::YBOFB: return kYbofbStr;
|
||||
default: return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
case decode_type_t::HAIER_AC176:
|
||||
switch (model) {
|
||||
case haier_ac176_remote_model_t::V9014557_A:
|
||||
return kV9014557AStr;
|
||||
case haier_ac176_remote_model_t::V9014557_B:
|
||||
return kV9014557BStr;
|
||||
default:
|
||||
return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
case decode_type_t::HITACHI_AC1:
|
||||
switch (model) {
|
||||
case hitachi_ac1_remote_model_t::R_LT0541_HTA_A:
|
||||
return F("R-LT0541-HTA-A");
|
||||
return kRlt0541htaaStr;
|
||||
case hitachi_ac1_remote_model_t::R_LT0541_HTA_B:
|
||||
return F("R-LT0541-HTA-B");
|
||||
default: return kUnknownStr;
|
||||
return kRlt0541htabStr;
|
||||
default:
|
||||
return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
case decode_type_t::LG:
|
||||
case decode_type_t::LG2:
|
||||
switch (model) {
|
||||
case lg_ac_remote_model_t::GE6711AR2853M: return F("GE6711AR2853M");
|
||||
case lg_ac_remote_model_t::AKB75215403: return F("AKB75215403");
|
||||
case lg_ac_remote_model_t::AKB74955603: return F("AKB74955603");
|
||||
case lg_ac_remote_model_t::AKB73757604: return F("AKB73757604");
|
||||
case lg_ac_remote_model_t::GE6711AR2853M: return kGe6711ar2853mStr;
|
||||
case lg_ac_remote_model_t::AKB75215403: return kAkb75215403Str;
|
||||
case lg_ac_remote_model_t::AKB74955603: return kAkb74955603Str;
|
||||
case lg_ac_remote_model_t::AKB73757604: return kAkb73757604Str;
|
||||
default: return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
case decode_type_t::SHARP_AC:
|
||||
case decode_type_t::MIRAGE:
|
||||
switch (model) {
|
||||
case sharp_ac_remote_model_t::A907: return F("A907");
|
||||
case sharp_ac_remote_model_t::A705: return F("A705");
|
||||
case sharp_ac_remote_model_t::A903: return F("A903");
|
||||
case mirage_ac_remote_model_t::KKG9AC1: return kKkg9ac1Str;
|
||||
case mirage_ac_remote_model_t::KKG29AC1: return kKkg29ac1Str;
|
||||
default: return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
case decode_type_t::PANASONIC_AC:
|
||||
switch (model) {
|
||||
case panasonic_ac_remote_model_t::kPanasonicLke: return F("LKE");
|
||||
case panasonic_ac_remote_model_t::kPanasonicNke: return F("NKE");
|
||||
case panasonic_ac_remote_model_t::kPanasonicDke: return F("DKE");
|
||||
case panasonic_ac_remote_model_t::kPanasonicJke: return F("JKE");
|
||||
case panasonic_ac_remote_model_t::kPanasonicCkp: return F("CKP");
|
||||
case panasonic_ac_remote_model_t::kPanasonicRkr: return F("RKR");
|
||||
case panasonic_ac_remote_model_t::kPanasonicLke: return kLkeStr;
|
||||
case panasonic_ac_remote_model_t::kPanasonicNke: return kNkeStr;
|
||||
case panasonic_ac_remote_model_t::kPanasonicDke: return kDkeStr;
|
||||
case panasonic_ac_remote_model_t::kPanasonicJke: return kJkeStr;
|
||||
case panasonic_ac_remote_model_t::kPanasonicCkp: return kCkpStr;
|
||||
case panasonic_ac_remote_model_t::kPanasonicRkr: return kRkrStr;
|
||||
default: return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
case decode_type_t::SHARP_AC:
|
||||
switch (model) {
|
||||
case sharp_ac_remote_model_t::A907: return kA907Str;
|
||||
case sharp_ac_remote_model_t::A705: return kA705Str;
|
||||
case sharp_ac_remote_model_t::A903: return kA903Str;
|
||||
default: return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
case decode_type_t::TCL112AC:
|
||||
switch (model) {
|
||||
case tcl_ac_remote_model_t::TAC09CHSD: return kTac09chsdStr;
|
||||
case tcl_ac_remote_model_t::GZ055BE1: return kGz055be1Str;
|
||||
default: return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
case decode_type_t::VOLTAS:
|
||||
switch (model) {
|
||||
case voltas_ac_remote_model_t::kVoltas122LZF: return F("122LZF");
|
||||
case voltas_ac_remote_model_t::kVoltas122LZF: return k122lzfStr;
|
||||
default: return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
case decode_type_t::WHIRLPOOL_AC:
|
||||
switch (model) {
|
||||
case whirlpool_ac_remote_model_t::DG11J13A: return F("DG11J13A");
|
||||
case whirlpool_ac_remote_model_t::DG11J191: return F("DG11J191");
|
||||
case whirlpool_ac_remote_model_t::DG11J13A: return kDg11j13aStr;
|
||||
case whirlpool_ac_remote_model_t::DG11J191: return kDg11j191Str;
|
||||
default: return kUnknownStr;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -48,6 +48,8 @@ float fahrenheitToCelsius(const float deg);
|
|||
namespace irutils {
|
||||
String addBoolToString(const bool value, const String label,
|
||||
const bool precomma = true);
|
||||
String addToggleToString(const bool toggle, const String label,
|
||||
const bool precomma = true);
|
||||
String addIntToString(const uint16_t value, const String label,
|
||||
const bool precomma = true);
|
||||
String addSignedIntToString(const int16_t value, const String label,
|
||||
|
@ -97,10 +99,10 @@ namespace irutils {
|
|||
bool getBit(const uint64_t data, const uint8_t position,
|
||||
const uint8_t size = 64);
|
||||
bool getBit(const uint8_t data, const uint8_t position);
|
||||
#define GETBIT8(a, b) (a & ((uint8_t)1 << b))
|
||||
#define GETBIT16(a, b) (a & ((uint16_t)1 << b))
|
||||
#define GETBIT32(a, b) (a & ((uint32_t)1 << b))
|
||||
#define GETBIT64(a, b) (a & ((uint64_t)1 << b))
|
||||
#define GETBIT8(a, b) ((a) & ((uint8_t)1 << (b)))
|
||||
#define GETBIT16(a, b) ((a) & ((uint16_t)1 << (b)))
|
||||
#define GETBIT32(a, b) ((a) & ((uint32_t)1 << (b)))
|
||||
#define GETBIT64(a, b) ((a) & ((uint64_t)1 << (b)))
|
||||
#define GETBITS8(data, offset, size) \
|
||||
(((data) & (((uint8_t)UINT8_MAX >> (8 - (size))) << (offset))) >> (offset))
|
||||
#define GETBITS16(data, offset, size) \
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright 2021 David Conran (crankyoldgit)
|
||||
/// @file
|
||||
/// @brief Support for Airton protocol
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1670
|
||||
|
||||
// Supports:
|
||||
// Brand: Airton, Model: SMVH09B-2A2A3NH ref. 409730 A/C
|
||||
// Brand: Airton, Model: RD1A1 remote
|
||||
|
||||
#include "IRrecv.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRutils.h"
|
||||
|
||||
const uint16_t kAirtonHdrMark = 6630;
|
||||
const uint16_t kAirtonBitMark = 400;
|
||||
const uint16_t kAirtonHdrSpace = 3350;
|
||||
const uint16_t kAirtonOneSpace = 1260;
|
||||
const uint16_t kAirtonZeroSpace = 430;
|
||||
const uint16_t kAirtonFreq = 38000; // Hz. (Just a guess)
|
||||
|
||||
#if SEND_AIRTON
|
||||
// Function should be safe up to 64 bits.
|
||||
/// Send a Airton formatted message.
|
||||
/// Status: STABLE / Confirmed working.
|
||||
/// @param[in] data containing the IR command.
|
||||
/// @param[in] nbits Nr. of bits to send. usually kAirtonBits
|
||||
/// @param[in] repeat Nr. of times the message is to be repeated.
|
||||
void IRsend::sendAirton(const uint64_t data, const uint16_t nbits,
|
||||
const uint16_t repeat) {
|
||||
sendGeneric(kAirtonHdrMark, kAirtonHdrSpace,
|
||||
kAirtonBitMark, kAirtonOneSpace,
|
||||
kAirtonBitMark, kAirtonZeroSpace,
|
||||
kAirtonBitMark, kDefaultMessageGap,
|
||||
data, nbits, kAirtonFreq, false, repeat, kDutyDefault);
|
||||
}
|
||||
#endif // SEND_AIRTON
|
||||
|
||||
#if DECODE_AIRTON
|
||||
/// Decode the supplied Airton message.
|
||||
/// Status: STABLE / Confirmed working. LSBF ordering confirmed via temperature.
|
||||
/// @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::decodeAirton(decode_results *results, uint16_t offset,
|
||||
const uint16_t nbits, const bool strict) {
|
||||
if (results->rawlen < 2 * nbits + kHeader + kFooter - offset)
|
||||
return false; // Too short a message to match.
|
||||
if (strict && nbits != kAirtonBits)
|
||||
return false;
|
||||
|
||||
// Header + Data + Footer
|
||||
if (!matchGeneric(&(results->rawbuf[offset]), &(results->value),
|
||||
results->rawlen - offset, nbits,
|
||||
kAirtonHdrMark, kAirtonHdrSpace,
|
||||
kAirtonBitMark, kAirtonOneSpace,
|
||||
kAirtonBitMark, kAirtonZeroSpace,
|
||||
kAirtonBitMark, kDefaultMessageGap,
|
||||
true, kUseDefTol, kMarkExcess, false)) return false;
|
||||
|
||||
// Success
|
||||
results->decode_type = decode_type_t::AIRTON;
|
||||
results->bits = nbits;
|
||||
results->command = 0;
|
||||
results->address = 0;
|
||||
return true;
|
||||
}
|
||||
#endif // DECODE_AIRTON
|
|
@ -0,0 +1,123 @@
|
|||
// Copyright 2021 David Conran
|
||||
#include "IRrecv.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRutils.h"
|
||||
|
||||
/// @file
|
||||
/// @brief Arris "Manchester code" based protocol.
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1595
|
||||
|
||||
// Supports:
|
||||
// Brand: Arris, Model: VIP1113M Set-top box
|
||||
// Brand: Arris, Model: 120A V1.0 A18 remote
|
||||
|
||||
const uint8_t kArrisOverhead = 2;
|
||||
const uint16_t kArrisHalfClockPeriod = 320; // uSeconds
|
||||
const uint16_t kArrisHdrMark = 8 * kArrisHalfClockPeriod; // uSeconds
|
||||
const uint16_t kArrisHdrSpace = 6 * kArrisHalfClockPeriod; // uSeconds
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1595#issuecomment-913755841
|
||||
// aka. 77184 uSeconds.
|
||||
const uint32_t kArrisGapSpace = 102144 - ((8 + 6 + kArrisBits * 2) *
|
||||
kArrisHalfClockPeriod); // uSeconds
|
||||
const uint32_t kArrisReleaseToggle = 0x800008;
|
||||
const uint8_t kArrisChecksumSize = 4;
|
||||
const uint8_t kArrisCommandSize = 19;
|
||||
const uint8_t kArrisReleaseBit = kArrisChecksumSize + kArrisCommandSize;
|
||||
|
||||
using irutils::sumNibbles;
|
||||
|
||||
#if SEND_ARRIS
|
||||
/// Send an Arris Manchester Code formatted message.
|
||||
/// Status: STABLE / Confirmed working.
|
||||
/// @param[in] data The message to be sent.
|
||||
/// @param[in] nbits The number of bits of the message to be sent.
|
||||
/// @param[in] repeat The number of times the command is to be repeated.
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1595
|
||||
void IRsend::sendArris(const uint64_t data, const uint16_t nbits,
|
||||
const uint16_t repeat) {
|
||||
enableIROut(38);
|
||||
for (uint16_t r = 0; r <= repeat; r++) {
|
||||
// Header (part 1)
|
||||
mark(kArrisHdrMark);
|
||||
space(kArrisHdrSpace);
|
||||
// Header (part 2) + Data + Footer
|
||||
sendManchester(kArrisHalfClockPeriod * 2, 0, kArrisHalfClockPeriod,
|
||||
0, kArrisGapSpace, data, nbits);
|
||||
}
|
||||
}
|
||||
|
||||
/// Flip the toggle button release bits of an Arris message.
|
||||
/// Used to indicate a change of remote button's state. e.g. Press vs. Release.
|
||||
/// @param[in] data The existing Arris message.
|
||||
/// @return A data message suitable for use in sendArris() with the release bits
|
||||
/// flipped.
|
||||
uint32_t IRsend::toggleArrisRelease(const uint32_t data) {
|
||||
return data ^ kArrisReleaseToggle;
|
||||
}
|
||||
|
||||
/// Construct a raw 32-bit Arris message code from the supplied command &
|
||||
/// release setting.
|
||||
/// @param[in] command The command code.
|
||||
/// @param[in] release The button/command action: press (false), release (true)
|
||||
/// @return A raw 32-bit Arris message code suitable for sendArris() etc.
|
||||
/// @note Sequence of bits = header + release + command + checksum.
|
||||
uint32_t IRsend::encodeArris(const uint32_t command, const bool release) {
|
||||
uint32_t result = 0x10000000;
|
||||
irutils::setBits(&result, kArrisChecksumSize, kArrisCommandSize, command);
|
||||
irutils::setBit(&result, kArrisReleaseBit, release);
|
||||
return result + sumNibbles(result);
|
||||
}
|
||||
#endif // SEND_ARRIS
|
||||
|
||||
#if DECODE_ARRIS
|
||||
/// Decode the supplied Arris "Manchester code" 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.
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1595
|
||||
bool IRrecv::decodeArris(decode_results *results, uint16_t offset,
|
||||
const uint16_t nbits, const bool strict) {
|
||||
if (results->rawlen < nbits + kArrisOverhead - offset)
|
||||
return false; // Too short a message to match.
|
||||
|
||||
// Compliance
|
||||
if (strict && nbits != kArrisBits)
|
||||
return false; // Doesn't match our protocol defn.
|
||||
|
||||
// Header (part 1)
|
||||
if (!matchMark(results->rawbuf[offset++], kArrisHdrMark)) return false;
|
||||
if (!matchSpace(results->rawbuf[offset++], kArrisHdrSpace)) return false;
|
||||
|
||||
// Header (part 2) + Data
|
||||
uint64_t data = 0;
|
||||
if (!matchManchester(results->rawbuf + offset, &data,
|
||||
results->rawlen - offset, nbits,
|
||||
kArrisHalfClockPeriod * 2, 0,
|
||||
kArrisHalfClockPeriod, 0, 0,
|
||||
false, kUseDefTol, kMarkExcess, true, false))
|
||||
return false;
|
||||
|
||||
// Compliance
|
||||
if (strict)
|
||||
// Validate the checksum.
|
||||
if (GETBITS32(data, 0, kArrisChecksumSize) !=
|
||||
sumNibbles(data >> kArrisChecksumSize))
|
||||
return false;
|
||||
|
||||
// Success
|
||||
results->decode_type = decode_type_t::ARRIS;
|
||||
results->bits = nbits;
|
||||
results->value = data;
|
||||
// Set the address as the Release Bit for something useful.
|
||||
results->address = static_cast<bool>(GETBIT32(data, kArrisReleaseBit));
|
||||
// The last 4 bits are likely a checksum value, so skip those. Everything else
|
||||
// after the release bit. e.g. Bits 10-28
|
||||
results->command = GETBITS32(data, kArrisChecksumSize, kArrisCommandSize);
|
||||
return true;
|
||||
}
|
||||
#endif // DECODE_ARRIS
|
|
@ -611,7 +611,11 @@ String IRCoolixAC::toString(void) const {
|
|||
result += addBoolToString(getZoneFollow(), kZoneFollowStr);
|
||||
result += addLabeledString(
|
||||
(getSensorTemp() == kCoolixSensorTempIgnoreCode)
|
||||
? kOffStr : uint64ToString(getSensorTemp()) + 'C', kSensorTempStr);
|
||||
// Encasing with String(blah) to keep compatible with old arduino
|
||||
// frameworks. Not needed with 3.0.2.
|
||||
///> @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1639#issuecomment-944906016
|
||||
? kOffStr : String(uint64ToString(getSensorTemp()) + 'C'),
|
||||
kSensorTempStr);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2018, 2019 David Conran
|
||||
// Copyright 2018-2021 David Conran
|
||||
/// @file
|
||||
/// @brief Support for Electra A/C protocols.
|
||||
/// @see https://github.com/ToniA/arduino-heatpumpir/blob/master/AUXHeatpumpIR.cpp
|
||||
|
@ -28,6 +28,7 @@ using irutils::addLabeledString;
|
|||
using irutils::addModeToString;
|
||||
using irutils::addFanToString;
|
||||
using irutils::addTempToString;
|
||||
using irutils::addToggleToString;
|
||||
|
||||
#if SEND_ELECTRA_AC
|
||||
/// Send a Electra A/C formatted message.
|
||||
|
@ -309,6 +310,52 @@ bool IRElectraAc::getTurbo(void) const {
|
|||
return _.Turbo;
|
||||
}
|
||||
|
||||
/// Get the IFeel mode of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRElectraAc::getIFeel(void) const { return _.IFeel; }
|
||||
|
||||
/// Set the IFeel mode of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRElectraAc::setIFeel(const bool on) {
|
||||
_.IFeel = on;
|
||||
if (_.IFeel)
|
||||
// Make sure there is a reasonable value in _.SensorTemp
|
||||
setSensorTemp(getSensorTemp());
|
||||
else
|
||||
// Clear any previous stored temp..
|
||||
_.SensorTemp = kElectraAcSensorMinTemp;
|
||||
}
|
||||
|
||||
/// Get the silent Sensor Update setting of the message.
|
||||
/// i.e. Is this _just_ a sensor temp update message from the remote?
|
||||
/// @note The A/C just takes the sensor temp value from the message and
|
||||
/// will not follow any of the other settings in the message.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRElectraAc::getSensorUpdate(void) const { return _.SensorUpdate; }
|
||||
|
||||
/// Set the silent Sensor Update setting of the message.
|
||||
/// i.e. Is this _just_ a sensor temp update message from the remote?
|
||||
/// @note The A/C will just take the sensor temp value from the message and
|
||||
/// will not follow any of the other settings in the message. If set, the A/C
|
||||
/// unit will also not beep in response to the message.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRElectraAc::setSensorUpdate(const bool on) { _.SensorUpdate = on; }
|
||||
|
||||
/// Set the Sensor temperature for the IFeel mode.
|
||||
/// @param[in] temp The temperature in degrees celsius.
|
||||
void IRElectraAc::setSensorTemp(const uint8_t temp) {
|
||||
_.SensorTemp = std::min(kElectraAcSensorMaxTemp,
|
||||
std::max(kElectraAcSensorMinTemp, temp)) +
|
||||
kElectraAcSensorTempDelta;
|
||||
}
|
||||
|
||||
/// Get the current sensor temperature setting for the IFeel mode.
|
||||
/// @return The current setting for temp. in degrees celsius.
|
||||
uint8_t IRElectraAc::getSensorTemp(void) const {
|
||||
return std::max(kElectraAcSensorTempDelta, _.SensorTemp) -
|
||||
kElectraAcSensorTempDelta;
|
||||
}
|
||||
|
||||
/// Convert the current internal state into its stdAc::state_t equivalent.
|
||||
/// @return The stdAc equivalent of the native settings.
|
||||
stdAc::state_t IRElectraAc::toCommon(void) const {
|
||||
|
@ -341,7 +388,8 @@ stdAc::state_t IRElectraAc::toCommon(void) const {
|
|||
/// @return A human readable string.
|
||||
String IRElectraAc::toString(void) const {
|
||||
String result = "";
|
||||
result.reserve(130); // Reserve some heap for the string to reduce fragging.
|
||||
result.reserve(160); // Reserve some heap for the string to reduce fragging.
|
||||
if (!_.SensorUpdate) {
|
||||
result += addBoolToString(_.Power, kPowerStr, false);
|
||||
result += addModeToString(_.Mode, kElectraAcAuto, kElectraAcCool,
|
||||
kElectraAcHeat, kElectraAcDry, kElectraAcFan);
|
||||
|
@ -351,9 +399,15 @@ String IRElectraAc::toString(void) const {
|
|||
kElectraAcFanMed);
|
||||
result += addBoolToString(getSwingV(), kSwingVStr);
|
||||
result += addBoolToString(getSwingH(), kSwingHStr);
|
||||
result += addLabeledString(getLightToggle() ? kToggleStr : "-", kLightStr);
|
||||
result += addToggleToString(getLightToggle(), kLightStr);
|
||||
result += addBoolToString(_.Clean, kCleanStr);
|
||||
result += addBoolToString(_.Turbo, kTurboStr);
|
||||
result += addBoolToString(_.IFeel, kIFeelStr);
|
||||
}
|
||||
if (_.IFeel || _.SensorUpdate) {
|
||||
result += addIntToString(getSensorTemp(), kSensorTempStr, !_.SensorUpdate);
|
||||
result += 'C';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2019 David Conran
|
||||
// Copyright 2019-2021 David Conran
|
||||
/// @file
|
||||
/// @brief Support for Electra A/C protocols.
|
||||
/// @see https://github.com/ToniA/arduino-heatpumpir/blob/master/AUXHeatpumpIR.cpp
|
||||
|
@ -9,6 +9,10 @@
|
|||
// Brand: Electra, Model: Classic INV 17 / AXW12DCS A/C
|
||||
// Brand: Electra, Model: YKR-M/003E remote
|
||||
// Brand: Frigidaire, Model: FGPC102AB1 A/C
|
||||
// Brand: Subtropic, Model: SUB-07HN1_18Y A/C
|
||||
// Brand: Subtropic, Model: YKR-H/102E remote
|
||||
// Brand: Centek, Model: SCT-65Q09 A/C
|
||||
// Brand: Centek, Model: YKR-P/002E remote
|
||||
|
||||
#ifndef IR_ELECTRA_H_
|
||||
#define IR_ELECTRA_H_
|
||||
|
@ -37,7 +41,9 @@ union ElectraProtocol {
|
|||
uint8_t :5;
|
||||
uint8_t SwingH :3;
|
||||
// Byte 3
|
||||
uint8_t :8;
|
||||
uint8_t :6;
|
||||
uint8_t SensorUpdate :1;
|
||||
uint8_t :1;
|
||||
// Byte 4
|
||||
uint8_t :5;
|
||||
uint8_t Fan :3;
|
||||
|
@ -46,10 +52,12 @@ union ElectraProtocol {
|
|||
uint8_t Turbo :1;
|
||||
uint8_t :1;
|
||||
// Byte 6
|
||||
uint8_t :5;
|
||||
uint8_t :3;
|
||||
uint8_t IFeel :1;
|
||||
uint8_t :1;
|
||||
uint8_t Mode :3;
|
||||
// Byte 7
|
||||
uint8_t :8;
|
||||
uint8_t SensorTemp :8;
|
||||
// Byte 8
|
||||
uint8_t :8;
|
||||
// Byte 9
|
||||
|
@ -93,6 +101,11 @@ const uint8_t kElectraAcLightToggleMask = 0x11;
|
|||
// and known OFF values of 0x08 (0b00001000) & 0x05 (0x00000101)
|
||||
const uint8_t kElectraAcLightToggleOff = 0x08;
|
||||
|
||||
// Re: Byte[7]. Or Delta == 0xA and Temperature are stored in last 6 bits,
|
||||
// and bit 7 stores Unknown flag
|
||||
const uint8_t kElectraAcSensorTempDelta = 0x4A;
|
||||
const uint8_t kElectraAcSensorMinTemp = 0; // 0C
|
||||
const uint8_t kElectraAcSensorMaxTemp = 50; // 50C
|
||||
|
||||
// Classes
|
||||
/// Class for handling detailed Electra A/C messages.
|
||||
|
@ -130,6 +143,12 @@ class IRElectraAc {
|
|||
bool getLightToggle(void) const;
|
||||
void setTurbo(const bool on);
|
||||
bool getTurbo(void) const;
|
||||
void setIFeel(const bool on);
|
||||
bool getIFeel(void) const;
|
||||
void setSensorUpdate(const bool on);
|
||||
bool getSensorUpdate(void) const;
|
||||
void setSensorTemp(const uint8_t temp);
|
||||
uint8_t getSensorTemp(void) const;
|
||||
uint8_t* getRaw(void);
|
||||
void setRaw(const uint8_t new_code[],
|
||||
const uint16_t length = kElectraAcStateLength);
|
||||
|
|
|
@ -6,6 +6,13 @@
|
|||
|
||||
// Supports:
|
||||
// Brand: Epson, Model: EN-TW9100W Projector
|
||||
// Brand: Epson, Model: VS230 Projector
|
||||
// Brand: Epson, Model: VS330 Projector
|
||||
// Brand: Epson, Model: EX3220 Projector
|
||||
// Brand: Epson, Model: EX5220 Projector
|
||||
// Brand: Epson, Model: EX5230 Projector
|
||||
// Brand: Epson, Model: EX6220 Projector
|
||||
// Brand: Epson, Model: EX7220 Projector
|
||||
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#include <stdint.h>
|
||||
|
|
|
@ -21,6 +21,7 @@ using irutils::addLabeledString;
|
|||
using irutils::addModeToString;
|
||||
using irutils::addFanToString;
|
||||
using irutils::addTempToString;
|
||||
using irutils::addToggleToString;
|
||||
|
||||
#if SEND_GOODWEATHER
|
||||
/// Send a Goodweather HVAC formatted message.
|
||||
|
@ -346,9 +347,10 @@ String IRGoodweatherAc::toString(void) const {
|
|||
result += addFanToString(_.Fan, kGoodweatherFanHigh, kGoodweatherFanLow,
|
||||
kGoodweatherFanAuto, kGoodweatherFanAuto,
|
||||
kGoodweatherFanMed);
|
||||
result += addLabeledString(_.Turbo ? kToggleStr : "-", kTurboStr);
|
||||
result += addLabeledString(_.Light ? kToggleStr : "-", kLightStr);
|
||||
result += addLabeledString(_.Sleep ? kToggleStr : "-", kSleepStr);
|
||||
|
||||
result += addToggleToString(_.Turbo, kTurboStr);
|
||||
result += addToggleToString(_.Light, kLightStr);
|
||||
result += addToggleToString(_.Sleep, kSleepStr);
|
||||
result += addIntToString(_.Swing, kSwingStr);
|
||||
result += kSpaceLBraceStr;
|
||||
switch (_.Swing) {
|
||||
|
|
|
@ -35,6 +35,7 @@ using irutils::addLabeledString;
|
|||
using irutils::addModeToString;
|
||||
using irutils::addModelToString;
|
||||
using irutils::addFanToString;
|
||||
using irutils::addSwingHToString;
|
||||
using irutils::addTempToString;
|
||||
using irutils::minsToString;
|
||||
|
||||
|
@ -220,15 +221,11 @@ bool IRGreeAC::getPower(void) const {
|
|||
/// Set the default temperature units to use.
|
||||
/// @param[in] on Use Fahrenheit as the units.
|
||||
/// true is Fahrenheit, false is Celsius.
|
||||
void IRGreeAC::setUseFahrenheit(const bool on) {
|
||||
_.UseFahrenheit = on;
|
||||
}
|
||||
void IRGreeAC::setUseFahrenheit(const bool on) { _.UseFahrenheit = on; }
|
||||
|
||||
/// Get the default temperature units in use.
|
||||
/// @return true is Fahrenheit, false is Celsius.
|
||||
bool IRGreeAC::getUseFahrenheit(void) const {
|
||||
return _.UseFahrenheit;
|
||||
}
|
||||
bool IRGreeAC::getUseFahrenheit(void) const { return _.UseFahrenheit; }
|
||||
|
||||
/// Set the temp. in degrees
|
||||
/// @param[in] temp Desired temperature in Degrees.
|
||||
|
@ -281,9 +278,7 @@ void IRGreeAC::setFan(const uint8_t speed) {
|
|||
|
||||
/// Get the current fan speed setting.
|
||||
/// @return The current fan speed.
|
||||
uint8_t IRGreeAC::getFan(void) const {
|
||||
return _.Fan;
|
||||
}
|
||||
uint8_t IRGreeAC::getFan(void) const { return _.Fan; }
|
||||
|
||||
/// Set the operating mode of the A/C.
|
||||
/// @param[in] new_mode The desired operating mode.
|
||||
|
@ -305,81 +300,63 @@ void IRGreeAC::setMode(const uint8_t new_mode) {
|
|||
|
||||
/// Get the operating mode setting of the A/C.
|
||||
/// @return The current operating mode setting.
|
||||
uint8_t IRGreeAC::getMode(void) const {
|
||||
return _.Mode;
|
||||
}
|
||||
uint8_t IRGreeAC::getMode(void) const { return _.Mode; }
|
||||
|
||||
/// Set the Light (LED) setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRGreeAC::setLight(const bool on) {
|
||||
_.Light = on;
|
||||
}
|
||||
void IRGreeAC::setLight(const bool on) { _.Light = on; }
|
||||
|
||||
/// Get the Light (LED) setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRGreeAC::getLight(void) const {
|
||||
return _.Light;
|
||||
}
|
||||
bool IRGreeAC::getLight(void) const { return _.Light; }
|
||||
|
||||
/// Set the IFeel setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRGreeAC::setIFeel(const bool on) {
|
||||
_.IFeel = on;
|
||||
}
|
||||
void IRGreeAC::setIFeel(const bool on) { _.IFeel = on; }
|
||||
|
||||
/// Get the IFeel setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRGreeAC::getIFeel(void) const {
|
||||
return _.IFeel;
|
||||
}
|
||||
bool IRGreeAC::getIFeel(void) const { return _.IFeel; }
|
||||
|
||||
/// Set the Wifi (enabled) setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRGreeAC::setWiFi(const bool on) {
|
||||
_.WiFi = on;
|
||||
}
|
||||
void IRGreeAC::setWiFi(const bool on) { _.WiFi = on; }
|
||||
|
||||
/// Get the Wifi (enabled) setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRGreeAC::getWiFi(void) const {
|
||||
return _.WiFi;
|
||||
}
|
||||
bool IRGreeAC::getWiFi(void) const { return _.WiFi; }
|
||||
|
||||
/// Set the XFan (Mould) setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRGreeAC::setXFan(const bool on) {
|
||||
_.Xfan = on;
|
||||
}
|
||||
void IRGreeAC::setXFan(const bool on) { _.Xfan = on; }
|
||||
|
||||
/// Get the XFan (Mould) setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRGreeAC::getXFan(void) const {
|
||||
return _.Xfan;
|
||||
}
|
||||
bool IRGreeAC::getXFan(void) const { return _.Xfan; }
|
||||
|
||||
/// Set the Sleep setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRGreeAC::setSleep(const bool on) {
|
||||
_.Sleep = on;
|
||||
}
|
||||
void IRGreeAC::setSleep(const bool on) { _.Sleep = on; }
|
||||
|
||||
/// Get the Sleep setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRGreeAC::getSleep(void) const {
|
||||
return _.Sleep;
|
||||
}
|
||||
bool IRGreeAC::getSleep(void) const { return _.Sleep; }
|
||||
|
||||
/// Set the Turbo setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRGreeAC::setTurbo(const bool on) {
|
||||
_.Turbo = on;
|
||||
}
|
||||
void IRGreeAC::setTurbo(const bool on) { _.Turbo = on; }
|
||||
|
||||
/// Get the Turbo setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRGreeAC::getTurbo(void) const {
|
||||
return _.Turbo;
|
||||
}
|
||||
bool IRGreeAC::getTurbo(void) const { return _.Turbo; }
|
||||
|
||||
/// Set the Econo setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRGreeAC::setEcono(const bool on) { _.Econo = on; }
|
||||
|
||||
/// Get the Econo setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRGreeAC::getEcono(void) const { return _.Econo; }
|
||||
|
||||
/// Set the Vertical Swing mode of the A/C.
|
||||
/// @param[in] automatic Do we use the automatic setting?
|
||||
|
@ -409,32 +386,37 @@ void IRGreeAC::setSwingVertical(const bool automatic, const uint8_t position) {
|
|||
new_position = kGreeSwingAuto;
|
||||
}
|
||||
}
|
||||
_.Swing = new_position;
|
||||
_.SwingV = new_position;
|
||||
}
|
||||
|
||||
/// Get the Vertical Swing Automatic mode setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRGreeAC::getSwingVerticalAuto(void) const {
|
||||
return _.SwingAuto;
|
||||
}
|
||||
bool IRGreeAC::getSwingVerticalAuto(void) const { return _.SwingAuto; }
|
||||
|
||||
/// Get the Vertical Swing position setting of the A/C.
|
||||
/// @return The native position/mode.
|
||||
uint8_t IRGreeAC::getSwingVerticalPosition(void) const {
|
||||
return _.Swing;
|
||||
uint8_t IRGreeAC::getSwingVerticalPosition(void) const { return _.SwingV; }
|
||||
|
||||
/// Get the Horizontal Swing position setting of the A/C.
|
||||
/// @return The native position/mode.
|
||||
uint8_t IRGreeAC::getSwingHorizontal(void) const { return _.SwingH; }
|
||||
|
||||
/// Set the Horizontal Swing mode of the A/C.
|
||||
/// @param[in] position The position/mode to set the vanes to.
|
||||
void IRGreeAC::setSwingHorizontal(const uint8_t position) {
|
||||
if (position <= kGreeSwingHMaxRight)
|
||||
_.SwingH = position;
|
||||
else
|
||||
_.SwingH = kGreeSwingHOff;
|
||||
}
|
||||
|
||||
/// Set the timer enable setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRGreeAC::setTimerEnabled(const bool on) {
|
||||
_.TimerEnabled = on;
|
||||
}
|
||||
void IRGreeAC::setTimerEnabled(const bool on) { _.TimerEnabled = on; }
|
||||
|
||||
/// Get the timer enabled setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRGreeAC::getTimerEnabled(void) const {
|
||||
return _.TimerEnabled;
|
||||
}
|
||||
bool IRGreeAC::getTimerEnabled(void) const { return _.TimerEnabled; }
|
||||
|
||||
/// Get the timer time value from the A/C.
|
||||
/// @return The number of minutes the timer is set for.
|
||||
|
@ -478,9 +460,7 @@ void IRGreeAC::setDisplayTempSource(const uint8_t mode) {
|
|||
/// Get the temperature display mode.
|
||||
/// i.e. Internal, External temperature sensing.
|
||||
/// @return The current temp source being displayed.
|
||||
uint8_t IRGreeAC::getDisplayTempSource(void) const {
|
||||
return _.DisplayTemp;
|
||||
}
|
||||
uint8_t IRGreeAC::getDisplayTempSource(void) const { return _.DisplayTemp; }
|
||||
|
||||
/// Convert a stdAc::opmode_t enum into its native mode.
|
||||
/// @param[in] mode The enum to be converted.
|
||||
|
@ -523,6 +503,21 @@ uint8_t IRGreeAC::convertSwingV(const stdAc::swingv_t swingv) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert a stdAc::swingh_t enum into it's native setting.
|
||||
/// @param[in] swingh The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
uint8_t IRGreeAC::convertSwingH(const stdAc::swingh_t swingh) {
|
||||
switch (swingh) {
|
||||
case stdAc::swingh_t::kAuto: return kGreeSwingHAuto;
|
||||
case stdAc::swingh_t::kLeftMax: return kGreeSwingHMaxLeft;
|
||||
case stdAc::swingh_t::kLeft: return kGreeSwingHLeft;
|
||||
case stdAc::swingh_t::kMiddle: return kGreeSwingHMiddle;
|
||||
case stdAc::swingh_t::kRight: return kGreeSwingHRight;
|
||||
case stdAc::swingh_t::kRightMax: return kGreeSwingHMaxRight;
|
||||
default: return kGreeSwingHOff;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
@ -562,6 +557,21 @@ stdAc::swingv_t IRGreeAC::toCommonSwingV(const uint8_t pos) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert a native Horizontal Swing into its stdAc equivalent.
|
||||
/// @param[in] pos The native setting to be converted.
|
||||
/// @return The stdAc equivalent of the native setting.
|
||||
stdAc::swingh_t IRGreeAC::toCommonSwingH(const uint8_t pos) {
|
||||
switch (pos) {
|
||||
case kGreeSwingHAuto: return stdAc::swingh_t::kAuto;
|
||||
case kGreeSwingHMaxLeft: return stdAc::swingh_t::kLeftMax;
|
||||
case kGreeSwingHLeft: return stdAc::swingh_t::kLeft;
|
||||
case kGreeSwingHMiddle: return stdAc::swingh_t::kMiddle;
|
||||
case kGreeSwingHRight: return stdAc::swingh_t::kRight;
|
||||
case kGreeSwingHMaxRight: return stdAc::swingh_t::kRightMax;
|
||||
default: return stdAc::swingh_t::kOff;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the current internal state into its stdAc::state_t equivalent.
|
||||
/// @return The stdAc equivalent of the native settings.
|
||||
stdAc::state_t IRGreeAC::toCommon(void) {
|
||||
|
@ -576,15 +586,15 @@ stdAc::state_t IRGreeAC::toCommon(void) {
|
|||
if (_.SwingAuto)
|
||||
result.swingv = stdAc::swingv_t::kAuto;
|
||||
else
|
||||
result.swingv = toCommonSwingV(_.Swing);
|
||||
result.swingv = toCommonSwingV(_.SwingV);
|
||||
result.swingh = toCommonSwingH(_.SwingH);
|
||||
result.turbo = _.Turbo;
|
||||
result.econo = _.Econo;
|
||||
result.light = _.Light;
|
||||
result.clean = _.Xfan;
|
||||
result.sleep = _.Sleep ? 0 : -1;
|
||||
// Not supported.
|
||||
result.swingh = stdAc::swingh_t::kOff;
|
||||
result.quiet = false;
|
||||
result.econo = false;
|
||||
result.filter = false;
|
||||
result.beep = false;
|
||||
result.clock = -1;
|
||||
|
@ -604,6 +614,7 @@ String IRGreeAC::toString(void) {
|
|||
result += addFanToString(_.Fan, kGreeFanMax, kGreeFanMin, kGreeFanAuto,
|
||||
kGreeFanAuto, kGreeFanMed);
|
||||
result += addBoolToString(_.Turbo, kTurboStr);
|
||||
result += addBoolToString(_.Econo, kEconoStr);
|
||||
result += addBoolToString(_.IFeel, kIFeelStr);
|
||||
result += addBoolToString(_.WiFi, kWifiStr);
|
||||
result += addBoolToString(_.Xfan, kXFanStr);
|
||||
|
@ -611,9 +622,9 @@ String IRGreeAC::toString(void) {
|
|||
result += addBoolToString(_.Sleep, kSleepStr);
|
||||
result += addLabeledString(_.SwingAuto ? kAutoStr : kManualStr,
|
||||
kSwingVModeStr);
|
||||
result += addIntToString(_.Swing, kSwingVStr);
|
||||
result += addIntToString(_.SwingV, kSwingVStr);
|
||||
result += kSpaceLBraceStr;
|
||||
switch (_.Swing) {
|
||||
switch (_.SwingV) {
|
||||
case kGreeSwingLastPos:
|
||||
result += kLastStr;
|
||||
break;
|
||||
|
@ -623,6 +634,12 @@ String IRGreeAC::toString(void) {
|
|||
default: result += kUnknownStr;
|
||||
}
|
||||
result += ')';
|
||||
result += addSwingHToString(_.SwingH, kGreeSwingHAuto, kGreeSwingHMaxLeft,
|
||||
kGreeSwingHLeft, kGreeSwingHMiddle,
|
||||
kGreeSwingHRight, kGreeSwingHMaxRight,
|
||||
kGreeSwingHOff,
|
||||
// rest are unused.
|
||||
0xFF, 0xFF, 0xFF, 0xFF);
|
||||
result += addLabeledString(
|
||||
_.TimerEnabled ? minsToString(getTimer()) : kOffStr, kTimerStr);
|
||||
uint8_t src = _.DisplayTemp;
|
||||
|
|
|
@ -14,10 +14,15 @@
|
|||
// Brand: Green, Model: YBOFB2 remote
|
||||
// Brand: Gree, Model: YAA1FBF remote
|
||||
// Brand: Gree, Model: YB1F2F remote
|
||||
// Brand: Gree, Model: YAN1F1 remote
|
||||
// Brand: Gree, Model: VIR09HP115V1AH A/C
|
||||
// Brand: Gree, Model: VIR12HP230V1AH A/C
|
||||
// Brand: Amana, Model: PBC093G00CC A/C
|
||||
// Brand: Amana, Model: YX1FF remote
|
||||
// Brand: Cooper & Hunter, Model: YB1F2 remote
|
||||
// Brand: Cooper & Hunter, Model: CH-S09FTXG A/C
|
||||
// Brand: Vailland, Model: YACIFB remote
|
||||
// Brand: Vailland, Model: VAI5-035WNI A/C
|
||||
|
||||
#ifndef IR_GREE_H_
|
||||
#define IR_GREE_H_
|
||||
|
@ -60,19 +65,22 @@ union GreeProtocol{
|
|||
uint8_t UseFahrenheit :1;
|
||||
uint8_t unknown1 :4; // value=0b0101
|
||||
// Byte 4
|
||||
uint8_t Swing:4;
|
||||
uint8_t :0;
|
||||
uint8_t SwingV :4;
|
||||
uint8_t SwingH :3;
|
||||
uint8_t :1;
|
||||
// Byte 5
|
||||
uint8_t DisplayTemp :2;
|
||||
uint8_t IFeel :1;
|
||||
uint8_t unknown2 :3; // value = 0b100
|
||||
uint8_t WiFi :1;
|
||||
uint8_t :0;
|
||||
uint8_t :1;
|
||||
// Byte 6
|
||||
uint8_t :8;
|
||||
// Byte 7
|
||||
uint8_t :4;
|
||||
uint8_t Sum:4;
|
||||
uint8_t :2;
|
||||
uint8_t Econo :1;
|
||||
uint8_t :1;
|
||||
uint8_t Sum :4;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -95,16 +103,24 @@ const uint8_t kGreeMinTempF = 61; // Fahrenheit
|
|||
const uint8_t kGreeMaxTempF = 86; // Fahrenheit
|
||||
const uint16_t kGreeTimerMax = 24 * 60;
|
||||
|
||||
const uint8_t kGreeSwingLastPos = 0b0000;
|
||||
const uint8_t kGreeSwingAuto = 0b0001;
|
||||
const uint8_t kGreeSwingUp = 0b0010;
|
||||
const uint8_t kGreeSwingMiddleUp = 0b0011;
|
||||
const uint8_t kGreeSwingMiddle = 0b0100;
|
||||
const uint8_t kGreeSwingMiddleDown = 0b0101;
|
||||
const uint8_t kGreeSwingDown = 0b0110;
|
||||
const uint8_t kGreeSwingDownAuto = 0b0111;
|
||||
const uint8_t kGreeSwingMiddleAuto = 0b1001;
|
||||
const uint8_t kGreeSwingUpAuto = 0b1011;
|
||||
const uint8_t kGreeSwingLastPos = 0b0000; // 0
|
||||
const uint8_t kGreeSwingAuto = 0b0001; // 1
|
||||
const uint8_t kGreeSwingUp = 0b0010; // 2
|
||||
const uint8_t kGreeSwingMiddleUp = 0b0011; // 3
|
||||
const uint8_t kGreeSwingMiddle = 0b0100; // 4
|
||||
const uint8_t kGreeSwingMiddleDown = 0b0101; // 5
|
||||
const uint8_t kGreeSwingDown = 0b0110; // 6
|
||||
const uint8_t kGreeSwingDownAuto = 0b0111; // 7
|
||||
const uint8_t kGreeSwingMiddleAuto = 0b1001; // 9
|
||||
const uint8_t kGreeSwingUpAuto = 0b1011; // 11
|
||||
|
||||
const uint8_t kGreeSwingHOff = 0b000; // 0
|
||||
const uint8_t kGreeSwingHAuto = 0b001; // 1
|
||||
const uint8_t kGreeSwingHMaxLeft = 0b010; // 2
|
||||
const uint8_t kGreeSwingHLeft = 0b011; // 3
|
||||
const uint8_t kGreeSwingHMiddle = 0b100; // 4
|
||||
const uint8_t kGreeSwingHRight = 0b101; // 5
|
||||
const uint8_t kGreeSwingHMaxRight = 0b110; // 6
|
||||
|
||||
const uint8_t kGreeDisplayTempOff = 0b00; // 0
|
||||
const uint8_t kGreeDisplayTempSet = 0b01; // 1
|
||||
|
@ -171,6 +187,8 @@ class IRGreeAC {
|
|||
bool getSleep(void) const;
|
||||
void setTurbo(const bool on);
|
||||
bool getTurbo(void) const;
|
||||
void setEcono(const bool on);
|
||||
bool getEcono(void) const;
|
||||
void setIFeel(const bool on);
|
||||
bool getIFeel(void) const;
|
||||
void setWiFi(const bool on);
|
||||
|
@ -178,6 +196,8 @@ class IRGreeAC {
|
|||
void setSwingVertical(const bool automatic, const uint8_t position);
|
||||
bool getSwingVerticalAuto(void) const;
|
||||
uint8_t getSwingVerticalPosition(void) const;
|
||||
void setSwingHorizontal(const uint8_t position);
|
||||
uint8_t getSwingHorizontal(void) const;
|
||||
uint16_t getTimer(void) const;
|
||||
void setTimer(const uint16_t minutes);
|
||||
void setDisplayTempSource(const uint8_t mode);
|
||||
|
@ -185,9 +205,11 @@ class IRGreeAC {
|
|||
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 swingv);
|
||||
static uint8_t convertSwingH(const stdAc::swingh_t swingh);
|
||||
static stdAc::opmode_t toCommonMode(const uint8_t mode);
|
||||
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
|
||||
static stdAc::swingv_t toCommonSwingV(const uint8_t pos);
|
||||
static stdAc::swingh_t toCommonSwingH(const uint8_t pos);
|
||||
stdAc::state_t toCommon(void);
|
||||
uint8_t* getRaw(void);
|
||||
void setRaw(const uint8_t new_code[]);
|
||||
|
|
|
@ -32,6 +32,8 @@ using irutils::addBoolToString;
|
|||
using irutils::addIntToString;
|
||||
using irutils::addLabeledString;
|
||||
using irutils::addModeToString;
|
||||
using irutils::addModelToString;
|
||||
using irutils::addSwingHToString;
|
||||
using irutils::addFanToString;
|
||||
using irutils::addTempToString;
|
||||
using irutils::minsToString;
|
||||
|
@ -322,22 +324,22 @@ void IRHaierAC::setCurrTime(const uint16_t nr_mins) {
|
|||
}
|
||||
|
||||
/// Get the Vertical Swing position setting of the A/C.
|
||||
/// @return The native swing mode.
|
||||
uint8_t IRHaierAC::getSwing(void) const {
|
||||
return _.Swing;
|
||||
/// @return The native vertical swing mode.
|
||||
uint8_t IRHaierAC::getSwingV(void) const {
|
||||
return _.SwingV;
|
||||
}
|
||||
|
||||
/// Set the Vertical Swing mode of the A/C.
|
||||
/// @param[in] state The mode to set the vanes to.
|
||||
void IRHaierAC::setSwing(const uint8_t state) {
|
||||
if (state == _.Swing) return; // Nothing to do.
|
||||
void IRHaierAC::setSwingV(const uint8_t state) {
|
||||
if (state == _.SwingV) return; // Nothing to do.
|
||||
switch (state) {
|
||||
case kHaierAcSwingOff:
|
||||
case kHaierAcSwingUp:
|
||||
case kHaierAcSwingDown:
|
||||
case kHaierAcSwingChg:
|
||||
case kHaierAcSwingVOff:
|
||||
case kHaierAcSwingVUp:
|
||||
case kHaierAcSwingVDown:
|
||||
case kHaierAcSwingVChg:
|
||||
_.Command = kHaierAcCmdSwing;
|
||||
_.Swing = state;
|
||||
_.SwingV = state;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -376,11 +378,11 @@ uint8_t IRHaierAC::convertSwingV(const stdAc::swingv_t position) {
|
|||
switch (position) {
|
||||
case stdAc::swingv_t::kHighest:
|
||||
case stdAc::swingv_t::kHigh:
|
||||
case stdAc::swingv_t::kMiddle: return kHaierAcSwingUp;
|
||||
case stdAc::swingv_t::kMiddle: return kHaierAcSwingVUp;
|
||||
case stdAc::swingv_t::kLow:
|
||||
case stdAc::swingv_t::kLowest: return kHaierAcSwingDown;
|
||||
case stdAc::swingv_t::kOff: return kHaierAcSwingOff;
|
||||
default: return kHaierAcSwingChg;
|
||||
case stdAc::swingv_t::kLowest: return kHaierAcSwingVDown;
|
||||
case stdAc::swingv_t::kOff: return kHaierAcSwingVOff;
|
||||
default: return kHaierAcSwingVChg;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -414,9 +416,9 @@ stdAc::fanspeed_t IRHaierAC::toCommonFanSpeed(const uint8_t speed) {
|
|||
/// @return The native equivalent of the enum.
|
||||
stdAc::swingv_t IRHaierAC::toCommonSwingV(const uint8_t pos) {
|
||||
switch (pos) {
|
||||
case kHaierAcSwingUp: return stdAc::swingv_t::kHighest;
|
||||
case kHaierAcSwingDown: return stdAc::swingv_t::kLowest;
|
||||
case kHaierAcSwingOff: return stdAc::swingv_t::kOff;
|
||||
case kHaierAcSwingVUp: return stdAc::swingv_t::kHighest;
|
||||
case kHaierAcSwingVDown: return stdAc::swingv_t::kLowest;
|
||||
case kHaierAcSwingVOff: return stdAc::swingv_t::kOff;
|
||||
default: return stdAc::swingv_t::kAuto;
|
||||
}
|
||||
}
|
||||
|
@ -433,7 +435,7 @@ stdAc::state_t IRHaierAC::toCommon(void) const {
|
|||
result.celsius = true;
|
||||
result.degrees = getTemp();
|
||||
result.fanspeed = toCommonFanSpeed(getFan());
|
||||
result.swingv = toCommonSwingV(_.Swing);
|
||||
result.swingv = toCommonSwingV(_.SwingV);
|
||||
result.filter = _.Health;
|
||||
result.sleep = _.Sleep ? 0 : -1;
|
||||
// Not supported.
|
||||
|
@ -443,7 +445,7 @@ stdAc::state_t IRHaierAC::toCommon(void) const {
|
|||
result.econo = false;
|
||||
result.light = false;
|
||||
result.clean = false;
|
||||
result.beep = false;
|
||||
result.beep = true;
|
||||
result.clock = -1;
|
||||
return result;
|
||||
}
|
||||
|
@ -452,7 +454,7 @@ stdAc::state_t IRHaierAC::toCommon(void) const {
|
|||
/// @return A human readable string.
|
||||
String IRHaierAC::toString(void) const {
|
||||
String result = "";
|
||||
result.reserve(150); // Reserve some heap for the string to reduce fragging.
|
||||
result.reserve(170); // Reserve some heap for the string to reduce fragging.
|
||||
uint8_t cmd = _.Command;
|
||||
result += addIntToString(cmd, kCommandStr, false);
|
||||
result += kSpaceLBraceStr;
|
||||
|
@ -492,7 +494,7 @@ String IRHaierAC::toString(void) const {
|
|||
result += kHealthStr;
|
||||
break;
|
||||
case kHaierAcCmdSwing:
|
||||
result += kSwingStr;
|
||||
result += kSwingVStr;
|
||||
break;
|
||||
default:
|
||||
result += kUnknownStr;
|
||||
|
@ -503,19 +505,19 @@ String IRHaierAC::toString(void) const {
|
|||
result += addTempToString(getTemp());
|
||||
result += addFanToString(getFan(), kHaierAcFanHigh, kHaierAcFanLow,
|
||||
kHaierAcFanAuto, kHaierAcFanAuto, kHaierAcFanMed);
|
||||
result += addIntToString(_.Swing, kSwingStr);
|
||||
result += addIntToString(_.SwingV, kSwingVStr);
|
||||
result += kSpaceLBraceStr;
|
||||
switch (_.Swing) {
|
||||
case kHaierAcSwingOff:
|
||||
switch (_.SwingV) {
|
||||
case kHaierAcSwingVOff:
|
||||
result += kOffStr;
|
||||
break;
|
||||
case kHaierAcSwingUp:
|
||||
case kHaierAcSwingVUp:
|
||||
result += kUpStr;
|
||||
break;
|
||||
case kHaierAcSwingDown:
|
||||
case kHaierAcSwingVDown:
|
||||
result += kDownStr;
|
||||
break;
|
||||
case kHaierAcSwingChg:
|
||||
case kHaierAcSwingVChg:
|
||||
result += kChangeStr;
|
||||
break;
|
||||
default:
|
||||
|
@ -581,9 +583,9 @@ bool IRHaierAC176::validChecksum(const uint8_t state[], const uint16_t length) {
|
|||
/// Reset the internal state to a fixed known good state.
|
||||
void IRHaierAC176::stateReset(void) {
|
||||
std::memset(_.raw, 0, sizeof _.raw);
|
||||
_.Prefix = kHaierAcYrw02Prefix;
|
||||
_.Model = kHaierAcYrw02ModelA;
|
||||
_.Prefix2 = kHaierAc176Prefix;
|
||||
_.Temp = kHaierAcDefTemp - kHaierAcMinTemp;
|
||||
_.Temp = kHaierAcYrw02DefTempC - kHaierAcYrw02MinTempC;
|
||||
_.Health = true;
|
||||
setFan(kHaierAcYrw02FanAuto);
|
||||
_.Power = true;
|
||||
|
@ -609,17 +611,42 @@ void IRHaierAC176::setButton(uint8_t button) {
|
|||
switch (button) {
|
||||
case kHaierAcYrw02ButtonTempUp:
|
||||
case kHaierAcYrw02ButtonTempDown:
|
||||
case kHaierAcYrw02ButtonSwing:
|
||||
case kHaierAcYrw02ButtonSwingV:
|
||||
case kHaierAcYrw02ButtonSwingH:
|
||||
case kHaierAcYrw02ButtonFan:
|
||||
case kHaierAcYrw02ButtonPower:
|
||||
case kHaierAcYrw02ButtonMode:
|
||||
case kHaierAcYrw02ButtonHealth:
|
||||
case kHaierAcYrw02ButtonTurbo:
|
||||
case kHaierAcYrw02ButtonSleep:
|
||||
case kHaierAcYrw02ButtonLock:
|
||||
case kHaierAcYrw02ButtonCFAB:
|
||||
_.Button = button;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get/Detect the model of the A/C.
|
||||
/// @return The enum of the compatible model.
|
||||
haier_ac176_remote_model_t IRHaierAC176::getModel(void) const {
|
||||
switch (_.Model) {
|
||||
case kHaierAcYrw02ModelB: return haier_ac176_remote_model_t::V9014557_B;
|
||||
default: return haier_ac176_remote_model_t::V9014557_A;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the model of the A/C to emulate.
|
||||
/// @param[in] model The enum of the appropriate model.
|
||||
void IRHaierAC176::setModel(haier_ac176_remote_model_t model) {
|
||||
_.Button = kHaierAcYrw02ButtonCFAB;
|
||||
switch (model) {
|
||||
case haier_ac176_remote_model_t::V9014557_B:
|
||||
_.Model = kHaierAcYrw02ModelB;
|
||||
break;
|
||||
default:
|
||||
_.Model = kHaierAcYrw02ModelA;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Button/Command setting of the A/C.
|
||||
/// @return The value of the button/command that was pressed.
|
||||
uint8_t IRHaierAC176::getButton(void) const {
|
||||
|
@ -629,47 +656,118 @@ uint8_t IRHaierAC176::getButton(void) const {
|
|||
/// Set the operating mode of the A/C.
|
||||
/// @param[in] mode The desired operating mode.
|
||||
void IRHaierAC176::setMode(uint8_t mode) {
|
||||
uint8_t new_mode = mode;
|
||||
_.Button = kHaierAcYrw02ButtonMode;
|
||||
switch (mode) {
|
||||
case kHaierAcYrw02Auto:
|
||||
case kHaierAcYrw02Cool:
|
||||
case kHaierAcYrw02Dry:
|
||||
case kHaierAcYrw02Fan:
|
||||
// Turbo & Quiet is only available in Cool/Heat mode.
|
||||
_.Turbo = false;
|
||||
_.Quiet = false;
|
||||
// FALL-THRU
|
||||
case kHaierAcYrw02Cool:
|
||||
case kHaierAcYrw02Heat:
|
||||
case kHaierAcYrw02Fan: break;
|
||||
default: new_mode = kHaierAcYrw02Auto; // Unexpected, default to auto mode.
|
||||
_.Button = kHaierAcYrw02ButtonMode;
|
||||
_.Mode = mode;
|
||||
break;
|
||||
default:
|
||||
setMode(kHaierAcYrw02Auto); // Unexpected, default to auto mode.
|
||||
}
|
||||
_.Mode = new_mode;
|
||||
}
|
||||
|
||||
/// Get the operating mode setting of the A/C.
|
||||
/// @return The current operating mode setting.
|
||||
uint8_t IRHaierAC176::getMode(void) const {
|
||||
return _.Mode;
|
||||
}
|
||||
uint8_t IRHaierAC176::getMode(void) const { return _.Mode; }
|
||||
|
||||
/// Set the default temperature units to use.
|
||||
/// @param[in] on Use Fahrenheit as the units.
|
||||
/// true is Fahrenheit, false is Celsius.
|
||||
void IRHaierAC176::setUseFahrenheit(const bool on) { _.UseFahrenheit = on; }
|
||||
|
||||
/// Get the default temperature units in use.
|
||||
/// @return true is Fahrenheit, false is Celsius.
|
||||
bool IRHaierAC176::getUseFahrenheit(void) const { return _.UseFahrenheit; }
|
||||
|
||||
/// Set the temperature.
|
||||
/// @param[in] celsius The temperature in degrees celsius.
|
||||
void IRHaierAC176::setTemp(const uint8_t celsius) {
|
||||
uint8_t temp = celsius;
|
||||
if (temp < kHaierAcMinTemp)
|
||||
temp = kHaierAcMinTemp;
|
||||
else if (temp > kHaierAcMaxTemp)
|
||||
temp = kHaierAcMaxTemp;
|
||||
|
||||
/// @param[in] degree The temperature in degrees.
|
||||
/// @param[in] fahrenheit Use units of Fahrenheit and set that as units used.
|
||||
void IRHaierAC176::setTemp(const uint8_t degree, const bool fahrenheit) {
|
||||
uint8_t old_temp = getTemp();
|
||||
if (old_temp == temp) return;
|
||||
if (old_temp > temp)
|
||||
if (old_temp == degree) return;
|
||||
|
||||
if (_.UseFahrenheit == fahrenheit) {
|
||||
if (old_temp > degree)
|
||||
_.Button = kHaierAcYrw02ButtonTempDown;
|
||||
else
|
||||
_.Button = kHaierAcYrw02ButtonTempUp;
|
||||
_.Temp = temp - kHaierAcMinTemp;
|
||||
} else {
|
||||
_.Button = kHaierAcYrw02ButtonCFAB;
|
||||
}
|
||||
_.UseFahrenheit = fahrenheit;
|
||||
|
||||
uint8_t temp = degree;
|
||||
if (fahrenheit) {
|
||||
if (temp < kHaierAcYrw02MinTempF)
|
||||
temp = kHaierAcYrw02MinTempF;
|
||||
else if (temp > kHaierAcYrw02MaxTempF)
|
||||
temp = kHaierAcYrw02MaxTempF;
|
||||
if (degree >= 77) { temp++; }
|
||||
if (degree >= 79) { temp++; }
|
||||
// See at IRHaierAC176::getTemp() comments for clarification
|
||||
_.ExtraDegreeF = temp % 2;
|
||||
_.Temp = (temp - kHaierAcYrw02MinTempF -_.ExtraDegreeF) >> 1;
|
||||
} else {
|
||||
if (temp < kHaierAcYrw02MinTempC)
|
||||
temp = kHaierAcYrw02MinTempC;
|
||||
else if (temp > kHaierAcYrw02MaxTempC)
|
||||
temp = kHaierAcYrw02MaxTempC;
|
||||
_.Temp = temp - kHaierAcYrw02MinTempC;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current temperature setting.
|
||||
/// @return The current setting for temp. in degrees celsius.
|
||||
/// The unit of temperature is specified by UseFahrenheit value.
|
||||
/// @return The current setting for temperature.
|
||||
uint8_t IRHaierAC176::getTemp(void) const {
|
||||
return _.Temp + kHaierAcMinTemp;
|
||||
if (!_.UseFahrenheit) { return _.Temp + kHaierAcYrw02MinTempC; }
|
||||
uint8_t degree = _.Temp*2 + kHaierAcYrw02MinTempF + _.ExtraDegreeF;
|
||||
// The way of coding the temperature in degree Fahrenheit is
|
||||
// kHaierAcYrw02MinTempF + Temp*2 + ExtraDegreeF, for example
|
||||
// Temp = 0b0011, ExtraDegreeF = 0b1, temperature is 60 + 3*2 + 1 = 67F
|
||||
// But around 78F there is unconsistency, see table below
|
||||
//
|
||||
// | Fahrenheit | Temp | ExtraDegreeF |
|
||||
// | 60F | 0b0000 | 0b0 |
|
||||
// | 61F | 0b0000 | 0b1 |
|
||||
// | 62F | 0b0001 | 0b0 |
|
||||
// | 63F | 0b0001 | 0b1 |
|
||||
// | 64F | 0b0010 | 0b0 |
|
||||
// | 65F | 0b0010 | 0b1 |
|
||||
// | 66F | 0b0011 | 0b0 |
|
||||
// | 67F | 0b0011 | 0b1 |
|
||||
// | 68F | 0b0100 | 0b0 |
|
||||
// | 69F | 0b0100 | 0b1 |
|
||||
// | 70F | 0b0101 | 0b0 |
|
||||
// | 71F | 0b0101 | 0b1 |
|
||||
// | 72F | 0b0110 | 0b0 |
|
||||
// | 73F | 0b0110 | 0b1 |
|
||||
// | 74F | 0b0111 | 0b0 |
|
||||
// | 75F | 0b0111 | 0b1 |
|
||||
// | 76F | 0b1000 | 0b0 |
|
||||
// | Not Used | 0b1000 | 0b1 |
|
||||
// | 77F | 0b1001 | 0b0 |
|
||||
// | Not Used | 0b1001 | 0b1 |
|
||||
// | 78F | 0b1010 | 0b0 |
|
||||
// | 79F | 0b1010 | 0b1 |
|
||||
// | 80F | 0b1011 | 0b0 |
|
||||
// | 81F | 0b1011 | 0b1 |
|
||||
// | 82F | 0b1100 | 0b0 |
|
||||
// | 83F | 0b1100 | 0b1 |
|
||||
// | 84F | 0b1101 | 0b0 |
|
||||
// | 86F | 0b1110 | 0b0 |
|
||||
// | 85F | 0b1101 | 0b1 |
|
||||
if (degree >= 77) { degree--; }
|
||||
if (degree >= 79) { degree--; }
|
||||
return degree;
|
||||
}
|
||||
|
||||
/// Set the Health (filter) setting of the A/C.
|
||||
|
@ -681,15 +779,11 @@ void IRHaierAC176::setHealth(const bool on) {
|
|||
|
||||
/// Get the Health (filter) setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRHaierAC176::getHealth(void) const {
|
||||
return _.Health;
|
||||
}
|
||||
bool IRHaierAC176::getHealth(void) const { return _.Health; }
|
||||
|
||||
/// Get the value of the current power setting.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRHaierAC176::getPower(void) const {
|
||||
return _.Power;
|
||||
}
|
||||
bool IRHaierAC176::getPower(void) const { return _.Power; }
|
||||
|
||||
/// Change the power setting.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
|
@ -706,9 +800,7 @@ void IRHaierAC176::off(void) { setPower(false); }
|
|||
|
||||
/// Get the Sleep setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRHaierAC176::getSleep(void) const {
|
||||
return _.Sleep;
|
||||
}
|
||||
bool IRHaierAC176::getSleep(void) const { return _.Sleep; }
|
||||
|
||||
/// Set the Sleep setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
|
@ -718,30 +810,42 @@ void IRHaierAC176::setSleep(const bool on) {
|
|||
}
|
||||
|
||||
/// Get the Turbo setting of the A/C.
|
||||
/// @return The current turbo speed setting.
|
||||
uint8_t IRHaierAC176::getTurbo(void) const {
|
||||
return _.Turbo;
|
||||
}
|
||||
/// @return The current turbo setting.
|
||||
bool IRHaierAC176::getTurbo(void) const { return _.Turbo; }
|
||||
|
||||
/// Set the Turbo setting of the A/C.
|
||||
/// @param[in] speed The desired turbo speed setting.
|
||||
/// @note Valid speeds are kHaierAcYrw02TurboOff, kHaierAcYrw02TurboLow, &
|
||||
/// kHaierAcYrw02TurboHigh.
|
||||
void IRHaierAC176::setTurbo(uint8_t speed) {
|
||||
switch (speed) {
|
||||
case kHaierAcYrw02TurboOff:
|
||||
case kHaierAcYrw02TurboLow:
|
||||
case kHaierAcYrw02TurboHigh:
|
||||
_.Turbo = speed;
|
||||
/// @param[in] on The desired turbo setting.
|
||||
/// @note Turbo & Quiet can't be on at the same time, and only in Heat/Cool mode
|
||||
void IRHaierAC176::setTurbo(const bool on) {
|
||||
switch (getMode()) {
|
||||
case kHaierAcYrw02Cool:
|
||||
case kHaierAcYrw02Heat:
|
||||
_.Turbo = on;
|
||||
_.Button = kHaierAcYrw02ButtonTurbo;
|
||||
if (on) _.Quiet = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Quiet setting of the A/C.
|
||||
/// @return The current Quiet setting.
|
||||
bool IRHaierAC176::getQuiet(void) const { return _.Quiet; }
|
||||
|
||||
/// Set the Quiet setting of the A/C.
|
||||
/// @param[in] on The desired Quiet setting.
|
||||
/// @note Turbo & Quiet can't be on at the same time, and only in Heat/Cool mode
|
||||
void IRHaierAC176::setQuiet(const bool on) {
|
||||
switch (getMode()) {
|
||||
case kHaierAcYrw02Cool:
|
||||
case kHaierAcYrw02Heat:
|
||||
_.Quiet = on;
|
||||
_.Button = kHaierAcYrw02ButtonTurbo;
|
||||
if (on) _.Turbo = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current fan speed setting.
|
||||
/// @return The current fan speed.
|
||||
uint8_t IRHaierAC176::getFan(void) const {
|
||||
return _.Fan;
|
||||
}
|
||||
uint8_t IRHaierAC176::getFan(void) const { return _.Fan; }
|
||||
|
||||
/// Set the speed of the fan.
|
||||
/// @param[in] speed The desired setting.
|
||||
|
@ -757,30 +861,61 @@ void IRHaierAC176::setFan(uint8_t speed) {
|
|||
}
|
||||
}
|
||||
|
||||
/// For backward compatibility. Use getSwingV() instead.
|
||||
/// Get the Vertical Swing position setting of the A/C.
|
||||
/// @return The native position/mode.
|
||||
uint8_t IRHaierAC176::getSwing(void) const { return _.Swing; }
|
||||
uint8_t IRHaierAC176::getSwing(void) const {
|
||||
return IRHaierAC176::getSwingV();
|
||||
}
|
||||
|
||||
/// For backward compatibility. Use setSwingV() instead.
|
||||
/// Set the Vertical Swing mode of the A/C.
|
||||
/// @param[in] pos The position/mode to set the vanes to.
|
||||
void IRHaierAC176::setSwing(uint8_t pos) { setSwingV(pos); }
|
||||
|
||||
/// Get the Vertical Swing position setting of the A/C.
|
||||
/// @return The native position/mode.
|
||||
uint8_t IRHaierAC176::getSwingV(void) const { return _.SwingV; }
|
||||
|
||||
/// Set the Vertical Swing mode of the A/C.
|
||||
/// @param[in] pos The position/mode to set the vanes to.
|
||||
void IRHaierAC176::setSwing(uint8_t pos) {
|
||||
void IRHaierAC176::setSwingV(uint8_t pos) {
|
||||
uint8_t newpos = pos;
|
||||
switch (pos) {
|
||||
case kHaierAcYrw02SwingOff:
|
||||
case kHaierAcYrw02SwingAuto:
|
||||
case kHaierAcYrw02SwingTop:
|
||||
case kHaierAcYrw02SwingMiddle:
|
||||
case kHaierAcYrw02SwingBottom:
|
||||
case kHaierAcYrw02SwingDown: _.Button = kHaierAcYrw02ButtonSwing; break;
|
||||
case kHaierAcYrw02SwingVOff:
|
||||
case kHaierAcYrw02SwingVAuto:
|
||||
case kHaierAcYrw02SwingVTop:
|
||||
case kHaierAcYrw02SwingVMiddle:
|
||||
case kHaierAcYrw02SwingVBottom:
|
||||
case kHaierAcYrw02SwingVDown: _.Button = kHaierAcYrw02ButtonSwingV; break;
|
||||
default: return; // Unexpected value so don't do anything.
|
||||
}
|
||||
// Heat mode has no MIDDLE setting, use BOTTOM instead.
|
||||
if (pos == kHaierAcYrw02SwingMiddle && _.Mode == kHaierAcYrw02Heat)
|
||||
newpos = kHaierAcYrw02SwingBottom;
|
||||
if (pos == kHaierAcYrw02SwingVMiddle && _.Mode == kHaierAcYrw02Heat)
|
||||
newpos = kHaierAcYrw02SwingVBottom;
|
||||
// BOTTOM is only allowed if we are in Heat mode, otherwise MIDDLE.
|
||||
if (pos == kHaierAcYrw02SwingBottom && _.Mode != kHaierAcYrw02Heat)
|
||||
newpos = kHaierAcYrw02SwingMiddle;
|
||||
_.Swing = newpos;
|
||||
if (pos == kHaierAcYrw02SwingVBottom && _.Mode != kHaierAcYrw02Heat)
|
||||
newpos = kHaierAcYrw02SwingVMiddle;
|
||||
_.SwingV = newpos;
|
||||
}
|
||||
|
||||
/// Get the Horizontal Swing position setting of the A/C.
|
||||
/// @return The native position/mode.
|
||||
uint8_t IRHaierAC176::getSwingH(void) const { return _.SwingH; }
|
||||
|
||||
/// Set the Horizontal Swing mode of the A/C.
|
||||
/// @param[in] pos The position/mode to set the vanes to.
|
||||
void IRHaierAC176::setSwingH(uint8_t pos) {
|
||||
switch (pos) {
|
||||
case kHaierAcYrw02SwingHMiddle:
|
||||
case kHaierAcYrw02SwingHLeftMax:
|
||||
case kHaierAcYrw02SwingHLeft:
|
||||
case kHaierAcYrw02SwingHRight:
|
||||
case kHaierAcYrw02SwingHRightMax:
|
||||
case kHaierAcYrw02SwingHAuto: _.Button = kHaierAcYrw02ButtonSwingH; break;
|
||||
default: return; // Unexpected value so don't do anything.
|
||||
}
|
||||
_.SwingH = pos;
|
||||
}
|
||||
|
||||
|
||||
|
@ -867,6 +1002,17 @@ uint16_t IRHaierAC176::getOffTimer(void) const {
|
|||
return _.OffTimerHrs * 60 + _.OffTimerMins;
|
||||
}
|
||||
|
||||
/// Get the Lock setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRHaierAC176::getLock(void) const { return _.Lock; }
|
||||
|
||||
/// Set the Lock setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRHaierAC176::setLock(const bool on) {
|
||||
_.Button = kHaierAcYrw02ButtonLock;
|
||||
_.Lock = on;
|
||||
}
|
||||
|
||||
/// Convert a stdAc::opmode_t enum into its native mode.
|
||||
/// @param[in] mode The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
|
@ -900,12 +1046,27 @@ uint8_t IRHaierAC176::convertFan(const stdAc::fanspeed_t speed) {
|
|||
uint8_t IRHaierAC176::convertSwingV(const stdAc::swingv_t position) {
|
||||
switch (position) {
|
||||
case stdAc::swingv_t::kHighest:
|
||||
case stdAc::swingv_t::kHigh: return kHaierAcYrw02SwingTop;
|
||||
case stdAc::swingv_t::kMiddle: return kHaierAcYrw02SwingMiddle;
|
||||
case stdAc::swingv_t::kLow: return kHaierAcYrw02SwingDown;
|
||||
case stdAc::swingv_t::kLowest: return kHaierAcYrw02SwingBottom;
|
||||
case stdAc::swingv_t::kOff: return kHaierAcYrw02SwingOff;
|
||||
default: return kHaierAcYrw02SwingAuto;
|
||||
case stdAc::swingv_t::kHigh: return kHaierAcYrw02SwingVTop;
|
||||
case stdAc::swingv_t::kMiddle: return kHaierAcYrw02SwingVMiddle;
|
||||
case stdAc::swingv_t::kLow: return kHaierAcYrw02SwingVDown;
|
||||
case stdAc::swingv_t::kLowest: return kHaierAcYrw02SwingVBottom;
|
||||
case stdAc::swingv_t::kOff: return kHaierAcYrw02SwingVOff;
|
||||
default: return kHaierAcYrw02SwingVAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a stdAc::swingh_t enum into it's native setting.
|
||||
/// @param[in] position The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
uint8_t IRHaierAC176::convertSwingH(const stdAc::swingh_t position) {
|
||||
switch (position) {
|
||||
case stdAc::swingh_t::kMiddle: return kHaierAcYrw02SwingHMiddle;
|
||||
case stdAc::swingh_t::kLeftMax: return kHaierAcYrw02SwingHLeftMax;
|
||||
case stdAc::swingh_t::kLeft: return kHaierAcYrw02SwingHLeft;
|
||||
case stdAc::swingh_t::kRight: return kHaierAcYrw02SwingHRight;
|
||||
case stdAc::swingh_t::kRightMax: return kHaierAcYrw02SwingHRightMax;
|
||||
case stdAc::swingh_t::kAuto: return kHaierAcYrw02SwingHAuto;
|
||||
default: return kHaierAcYrw02SwingHMiddle;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -939,37 +1100,52 @@ stdAc::fanspeed_t IRHaierAC176::toCommonFanSpeed(const uint8_t speed) {
|
|||
/// @return The native equivalent of the enum.
|
||||
stdAc::swingv_t IRHaierAC176::toCommonSwingV(const uint8_t pos) {
|
||||
switch (pos) {
|
||||
case kHaierAcYrw02SwingTop: return stdAc::swingv_t::kHighest;
|
||||
case kHaierAcYrw02SwingMiddle: return stdAc::swingv_t::kMiddle;
|
||||
case kHaierAcYrw02SwingDown: return stdAc::swingv_t::kLow;
|
||||
case kHaierAcYrw02SwingBottom: return stdAc::swingv_t::kLowest;
|
||||
case kHaierAcYrw02SwingOff: return stdAc::swingv_t::kOff;
|
||||
case kHaierAcYrw02SwingVTop: return stdAc::swingv_t::kHighest;
|
||||
case kHaierAcYrw02SwingVMiddle: return stdAc::swingv_t::kMiddle;
|
||||
case kHaierAcYrw02SwingVDown: return stdAc::swingv_t::kLow;
|
||||
case kHaierAcYrw02SwingVBottom: return stdAc::swingv_t::kLowest;
|
||||
case kHaierAcYrw02SwingVOff: return stdAc::swingv_t::kOff;
|
||||
default: return stdAc::swingv_t::kAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a stdAc::swingh_t enum into it's native setting.
|
||||
/// @param[in] pos The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
stdAc::swingh_t IRHaierAC176::toCommonSwingH(const uint8_t pos) {
|
||||
switch (pos) {
|
||||
case kHaierAcYrw02SwingHMiddle: return stdAc::swingh_t::kMiddle;
|
||||
case kHaierAcYrw02SwingHLeftMax: return stdAc::swingh_t::kLeftMax;
|
||||
case kHaierAcYrw02SwingHLeft: return stdAc::swingh_t::kLeft;
|
||||
case kHaierAcYrw02SwingHRight: return stdAc::swingh_t::kRight;
|
||||
case kHaierAcYrw02SwingHRightMax: return stdAc::swingh_t::kRightMax;
|
||||
case kHaierAcYrw02SwingHAuto: return stdAc::swingh_t::kAuto;
|
||||
default: return stdAc::swingh_t::kOff;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the current internal state into its stdAc::state_t equivalent.
|
||||
/// @return The stdAc equivalent of the native settings.
|
||||
stdAc::state_t IRHaierAC176::toCommon(void) const {
|
||||
stdAc::state_t result;
|
||||
result.protocol = decode_type_t::HAIER_AC_YRW02;
|
||||
result.model = -1; // No models used.
|
||||
result.model = getModel();
|
||||
result.power = _.Power;
|
||||
result.mode = toCommonMode(_.Mode);
|
||||
result.celsius = true;
|
||||
result.celsius = !_.UseFahrenheit;
|
||||
result.degrees = getTemp();
|
||||
result.fanspeed = toCommonFanSpeed(_.Fan);
|
||||
result.swingv = toCommonSwingV(_.Swing);
|
||||
result.swingv = toCommonSwingV(_.SwingV);
|
||||
result.swingh = toCommonSwingH(_.SwingH);
|
||||
result.filter = _.Health;
|
||||
result.sleep = _.Sleep ? 0 : -1;
|
||||
result.turbo = _.Turbo;
|
||||
result.quiet = _.Quiet;
|
||||
// Not supported.
|
||||
result.swingh = stdAc::swingh_t::kOff;
|
||||
result.quiet = false;
|
||||
result.turbo = false;
|
||||
result.econo = false;
|
||||
result.light = false;
|
||||
result.clean = false;
|
||||
result.beep = false;
|
||||
result.beep = true;
|
||||
result.clock = -1;
|
||||
return result;
|
||||
}
|
||||
|
@ -978,8 +1154,9 @@ stdAc::state_t IRHaierAC176::toCommon(void) const {
|
|||
/// @return A human readable string.
|
||||
String IRHaierAC176::toString(void) const {
|
||||
String result = "";
|
||||
result.reserve(130); // Reserve some heap for the string to reduce fragging.
|
||||
result += addBoolToString(_.Power, kPowerStr, false);
|
||||
result.reserve(280); // Reserve some heap for the string to reduce fragging.
|
||||
result += addModelToString(decode_type_t::HAIER_AC176, getModel(), false);
|
||||
result += addBoolToString(_.Power, kPowerStr);
|
||||
uint8_t cmd = _.Button;
|
||||
result += addIntToString(cmd, kButtonStr);
|
||||
result += kSpaceLBraceStr;
|
||||
|
@ -1005,12 +1182,24 @@ String IRHaierAC176::toString(void) const {
|
|||
case kHaierAcYrw02ButtonHealth:
|
||||
result += kHealthStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonSwing:
|
||||
result += kSwingStr;
|
||||
case kHaierAcYrw02ButtonSwingV:
|
||||
result += kSwingVStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonSwingH:
|
||||
result += kSwingHStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonTurbo:
|
||||
result += kTurboStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonTimer:
|
||||
result += kTimerStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonLock:
|
||||
result += kLockStr;
|
||||
break;
|
||||
case kHaierAcYrw02ButtonCFAB:
|
||||
result += kCelsiusFahrenheitStr;
|
||||
break;
|
||||
default:
|
||||
result += kUnknownStr;
|
||||
}
|
||||
|
@ -1018,51 +1207,49 @@ String IRHaierAC176::toString(void) const {
|
|||
result += addModeToString(_.Mode, kHaierAcYrw02Auto, kHaierAcYrw02Cool,
|
||||
kHaierAcYrw02Heat, kHaierAcYrw02Dry,
|
||||
kHaierAcYrw02Fan);
|
||||
result += addTempToString(getTemp());
|
||||
result += addTempToString(getTemp(), !_.UseFahrenheit);
|
||||
result += addFanToString(_.Fan, kHaierAcYrw02FanHigh, kHaierAcYrw02FanLow,
|
||||
kHaierAcYrw02FanAuto, kHaierAcYrw02FanAuto,
|
||||
kHaierAcYrw02FanMed);
|
||||
result += addIntToString(_.Turbo, kTurboStr);
|
||||
result += addBoolToString(_.Turbo, kTurboStr);
|
||||
result += addBoolToString(_.Quiet, kQuietStr);
|
||||
result += addIntToString(_.SwingV, kSwingVStr);
|
||||
result += kSpaceLBraceStr;
|
||||
switch (_.Turbo) {
|
||||
case kHaierAcYrw02TurboOff:
|
||||
switch (_.SwingV) {
|
||||
case kHaierAcYrw02SwingVOff:
|
||||
result += kOffStr;
|
||||
break;
|
||||
case kHaierAcYrw02TurboLow:
|
||||
result += kLowStr;
|
||||
break;
|
||||
case kHaierAcYrw02TurboHigh:
|
||||
result += kHighStr;
|
||||
break;
|
||||
default:
|
||||
result += kUnknownStr;
|
||||
}
|
||||
result += ')';
|
||||
result += addIntToString(_.Swing, kSwingStr);
|
||||
result += kSpaceLBraceStr;
|
||||
switch (_.Swing) {
|
||||
case kHaierAcYrw02SwingOff:
|
||||
result += kOffStr;
|
||||
break;
|
||||
case kHaierAcYrw02SwingAuto:
|
||||
case kHaierAcYrw02SwingVAuto:
|
||||
result += kAutoStr;
|
||||
break;
|
||||
case kHaierAcYrw02SwingBottom:
|
||||
case kHaierAcYrw02SwingVBottom:
|
||||
result += kLowestStr;
|
||||
break;
|
||||
case kHaierAcYrw02SwingDown:
|
||||
case kHaierAcYrw02SwingVDown:
|
||||
result += kLowStr;
|
||||
break;
|
||||
case kHaierAcYrw02SwingTop:
|
||||
case kHaierAcYrw02SwingVTop:
|
||||
result += kHighestStr;
|
||||
break;
|
||||
case kHaierAcYrw02SwingMiddle:
|
||||
case kHaierAcYrw02SwingVMiddle:
|
||||
result += kMiddleStr;
|
||||
break;
|
||||
default:
|
||||
result += kUnknownStr;
|
||||
}
|
||||
result += ')';
|
||||
result += addSwingHToString(_.SwingH, kHaierAcYrw02SwingHAuto,
|
||||
kHaierAcYrw02SwingHLeftMax,
|
||||
kHaierAcYrw02SwingHLeft,
|
||||
kHaierAcYrw02SwingHMiddle,
|
||||
kHaierAcYrw02SwingHRight,
|
||||
kHaierAcYrw02SwingHRightMax,
|
||||
// Below are unused.
|
||||
kHaierAcYrw02SwingHMiddle,
|
||||
kHaierAcYrw02SwingHMiddle,
|
||||
kHaierAcYrw02SwingHMiddle,
|
||||
kHaierAcYrw02SwingHMiddle,
|
||||
kHaierAcYrw02SwingHMiddle);
|
||||
result += addBoolToString(_.Sleep, kSleepStr);
|
||||
result += addBoolToString(_.Health, kHealthStr);
|
||||
const uint8_t tmode = getTimerMode();
|
||||
|
@ -1098,6 +1285,7 @@ String IRHaierAC176::toString(void) const {
|
|||
result += addLabeledString((tmode != kHaierAcYrw02NoTimers &&
|
||||
tmode != kHaierAcYrw02OnTimer) ?
|
||||
minsToString(getOffTimer()) : kOffStr, kOffTimerStr);
|
||||
result += addBoolToString(_.Lock, kLockStr);
|
||||
return result;
|
||||
}
|
||||
// End of IRHaierAC176 class.
|
||||
|
@ -1203,7 +1391,7 @@ bool IRrecv::decodeHaierACYRW02(decode_results* results, uint16_t offset,
|
|||
|
||||
// Compliance
|
||||
if (strict) {
|
||||
if (results->state[0] != kHaierAcYrw02Prefix) return false;
|
||||
if (results->state[0] != kHaierAcYrw02ModelA) return false;
|
||||
if (!IRHaierACYRW02::validChecksum(results->state, nbits / 8)) return false;
|
||||
}
|
||||
|
||||
|
@ -1236,7 +1424,8 @@ bool IRrecv::decodeHaierAC176(decode_results* results, uint16_t offset,
|
|||
|
||||
// Compliance
|
||||
if (strict) {
|
||||
if (results->state[0] != kHaierAcYrw02Prefix) return false;
|
||||
if ((results->state[0] != kHaierAcYrw02ModelA) &&
|
||||
(results->state[0] != kHaierAcYrw02ModelB)) return false;
|
||||
if (!IRHaierAC176::validChecksum(results->state, nbits / 8)) return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2018 crankyoldgit
|
||||
// Copyright 2018-2021 crankyoldgit
|
||||
/// @file
|
||||
/// @brief Support for Haier A/C protocols.
|
||||
/// The specifics of reverse engineering the protocols details:
|
||||
|
@ -13,8 +13,10 @@
|
|||
// Brand: Haier, Model: HSU07-HEA03 remote (HAIER_AC)
|
||||
// Brand: Haier, Model: YR-W02 remote (HAIER_AC_YRW02)
|
||||
// Brand: Haier, Model: HSU-09HMC203 A/C (HAIER_AC_YRW02)
|
||||
// Brand: Haier, Model: V9014557 M47 8D remote (HAIER_AC176)
|
||||
// Brand: Mabe, Model: MMI18HDBWCA6MI8 A/C (HAIER_AC176)
|
||||
// Brand: Mabe, Model: V12843 HJ200223 remote (HAIER_AC176)
|
||||
// Brand: Daichi, Model: D-H A/C (HAIER_AC176)
|
||||
|
||||
#ifndef IR_HAIER_H_
|
||||
#define IR_HAIER_H_
|
||||
|
@ -41,7 +43,7 @@ union HaierProtocol{
|
|||
// Byte 2
|
||||
uint8_t CurrHours:5;
|
||||
uint8_t unknown :1; // value=1
|
||||
uint8_t Swing :2;
|
||||
uint8_t SwingV :2;
|
||||
// Byte 3
|
||||
uint8_t CurrMins:6;
|
||||
uint8_t OffTimer:1;
|
||||
|
@ -84,10 +86,10 @@ const uint8_t kHaierAcCmdTimerCancel = 0b1010;
|
|||
const uint8_t kHaierAcCmdHealth = 0b1100;
|
||||
const uint8_t kHaierAcCmdSwing = 0b1101;
|
||||
|
||||
const uint8_t kHaierAcSwingOff = 0b00;
|
||||
const uint8_t kHaierAcSwingUp = 0b01;
|
||||
const uint8_t kHaierAcSwingDown = 0b10;
|
||||
const uint8_t kHaierAcSwingChg = 0b11;
|
||||
const uint8_t kHaierAcSwingVOff = 0b00;
|
||||
const uint8_t kHaierAcSwingVUp = 0b01;
|
||||
const uint8_t kHaierAcSwingVDown = 0b10;
|
||||
const uint8_t kHaierAcSwingVChg = 0b11;
|
||||
|
||||
const uint8_t kHaierAcAuto = 0;
|
||||
const uint8_t kHaierAcCool = 1;
|
||||
|
@ -118,11 +120,11 @@ const uint8_t kHaierAcSleepBit = 0b01000000;
|
|||
#define HAIER_AC_CMD_TIMER_SET kHaierAcCmdTimerSet
|
||||
#define HAIER_AC_CMD_TIMER_CANCEL kHaierAcCmdTimerCancel
|
||||
#define HAIER_AC_CMD_HEALTH kHaierAcCmdHealth
|
||||
#define HAIER_AC_CMD_SWING kHaierAcCmdSwing
|
||||
#define HAIER_AC_SWING_OFF kHaierAcSwingOff
|
||||
#define HAIER_AC_SWING_UP kHaierAcSwingUp
|
||||
#define HAIER_AC_SWING_DOWN kHaierAcSwingDown
|
||||
#define HAIER_AC_SWING_CHG kHaierAcSwingChg
|
||||
#define HAIER_AC_CMD_SWINGV kHaierAcCmdSwing
|
||||
#define HAIER_AC_SWINGV_OFF kHaierAcSwingVOff
|
||||
#define HAIER_AC_SWINGV_UP kHaierAcSwingVUp
|
||||
#define HAIER_AC_SWINGV_DOWN kHaierAcSwingVDown
|
||||
#define HAIER_AC_SWINGV_CHG kHaierAcSwingVChg
|
||||
#define HAIER_AC_AUTO kHaierAcAuto
|
||||
#define HAIER_AC_COOL kHaierAcCool
|
||||
#define HAIER_AC_DRY kHaierAcDry
|
||||
|
@ -133,85 +135,54 @@ const uint8_t kHaierAcSleepBit = 0b01000000;
|
|||
#define HAIER_AC_FAN_MED kHaierAcFanMed
|
||||
#define HAIER_AC_FAN_HIGH kHaierAcFanHigh
|
||||
|
||||
/// Native representation of a Haier YRW02 A/C message.
|
||||
union HaierYRW02Protocol{
|
||||
uint8_t raw[kHaierACYRW02StateLength]; ///< The state in native form
|
||||
struct {
|
||||
// Byte 0
|
||||
uint8_t Prefix;
|
||||
// Byte 1
|
||||
uint8_t Swing:4;
|
||||
uint8_t Temp :4; // 16C~30C
|
||||
// Byte 2
|
||||
uint8_t :8;
|
||||
// Byte 3
|
||||
uint8_t :1;
|
||||
uint8_t Health:1;
|
||||
uint8_t :6;
|
||||
// Byte 4
|
||||
uint8_t :6;
|
||||
uint8_t Power:1;
|
||||
uint8_t :1;
|
||||
// Byte 5
|
||||
uint8_t :5;
|
||||
uint8_t Fan:3;
|
||||
// Byte 6
|
||||
uint8_t :6;
|
||||
uint8_t Turbo:2;
|
||||
// Byte 7
|
||||
uint8_t :5;
|
||||
uint8_t Mode:3;
|
||||
// Byte 8
|
||||
uint8_t :7;
|
||||
uint8_t Sleep:1;
|
||||
// Byte 9
|
||||
uint8_t :8;
|
||||
// Byte 10
|
||||
uint8_t :8;
|
||||
// Byte 11
|
||||
uint8_t :8;
|
||||
// Byte 12
|
||||
uint8_t Button:4;
|
||||
uint8_t :4;
|
||||
// Byte 13
|
||||
uint8_t Sum;
|
||||
};
|
||||
};
|
||||
const uint8_t kHaierAcYrw02MinTempC = 16;
|
||||
const uint8_t kHaierAcYrw02MaxTempC = 30;
|
||||
const uint8_t kHaierAcYrw02MinTempF = 60;
|
||||
const uint8_t kHaierAcYrw02MaxTempF = 86;
|
||||
const uint8_t kHaierAcYrw02DefTempC = 25;
|
||||
|
||||
const uint8_t kHaierAcYrw02Prefix = 0xA6;
|
||||
const uint8_t kHaierAcYrw02ModelA = 0xA6;
|
||||
const uint8_t kHaierAcYrw02ModelB = 0x59;
|
||||
const uint8_t kHaierAc176Prefix = 0xB7;
|
||||
|
||||
const uint8_t kHaierAcYrw02SwingOff = 0x0;
|
||||
const uint8_t kHaierAcYrw02SwingTop = 0x1;
|
||||
const uint8_t kHaierAcYrw02SwingMiddle = 0x2; // Not available in heat mode.
|
||||
const uint8_t kHaierAcYrw02SwingBottom = 0x3; // Only available in heat mode.
|
||||
const uint8_t kHaierAcYrw02SwingDown = 0xA;
|
||||
const uint8_t kHaierAcYrw02SwingAuto = 0xC; // Airflow
|
||||
const uint8_t kHaierAcYrw02SwingVOff = 0x0;
|
||||
const uint8_t kHaierAcYrw02SwingVTop = 0x1;
|
||||
const uint8_t kHaierAcYrw02SwingVMiddle = 0x2; // Not available in heat mode.
|
||||
const uint8_t kHaierAcYrw02SwingVBottom = 0x3; // Only available in heat mode.
|
||||
const uint8_t kHaierAcYrw02SwingVDown = 0xA;
|
||||
const uint8_t kHaierAcYrw02SwingVAuto = 0xC; // Airflow
|
||||
|
||||
const uint8_t kHaierAcYrw02SwingHMiddle = 0x0;
|
||||
const uint8_t kHaierAcYrw02SwingHLeftMax = 0x3;
|
||||
const uint8_t kHaierAcYrw02SwingHLeft = 0x4;
|
||||
const uint8_t kHaierAcYrw02SwingHRight = 0x5;
|
||||
const uint8_t kHaierAcYrw02SwingHRightMax = 0x6;
|
||||
const uint8_t kHaierAcYrw02SwingHAuto = 0x7;
|
||||
|
||||
const uint8_t kHaierAcYrw02FanHigh = 0b001;
|
||||
const uint8_t kHaierAcYrw02FanMed = 0b010;
|
||||
const uint8_t kHaierAcYrw02FanLow = 0b011;
|
||||
const uint8_t kHaierAcYrw02FanAuto = 0b101; // HAIER_AC176 uses `0` in Fan2
|
||||
|
||||
const uint8_t kHaierAcYrw02TurboOff = 0x0;
|
||||
const uint8_t kHaierAcYrw02TurboHigh = 0x1;
|
||||
const uint8_t kHaierAcYrw02TurboLow = 0x2;
|
||||
|
||||
const uint8_t kHaierAcYrw02Auto = 0b000; // 0
|
||||
const uint8_t kHaierAcYrw02Cool = 0b001; // 1
|
||||
const uint8_t kHaierAcYrw02Dry = 0b010; // 2
|
||||
const uint8_t kHaierAcYrw02Heat = 0b100; // 4
|
||||
const uint8_t kHaierAcYrw02Fan = 0b110; // 5
|
||||
|
||||
const uint8_t kHaierAcYrw02ButtonTempUp = 0x0;
|
||||
const uint8_t kHaierAcYrw02ButtonTempDown = 0x1;
|
||||
const uint8_t kHaierAcYrw02ButtonSwing = 0x2;
|
||||
const uint8_t kHaierAcYrw02ButtonFan = 0x4;
|
||||
const uint8_t kHaierAcYrw02ButtonPower = 0x5;
|
||||
const uint8_t kHaierAcYrw02ButtonMode = 0x6;
|
||||
const uint8_t kHaierAcYrw02ButtonHealth = 0x7;
|
||||
const uint8_t kHaierAcYrw02ButtonTurbo = 0x8;
|
||||
const uint8_t kHaierAcYrw02ButtonSleep = 0xB;
|
||||
const uint8_t kHaierAcYrw02ButtonTempUp = 0b00000;
|
||||
const uint8_t kHaierAcYrw02ButtonTempDown = 0b00001;
|
||||
const uint8_t kHaierAcYrw02ButtonSwingV = 0b00010;
|
||||
const uint8_t kHaierAcYrw02ButtonSwingH = 0b00011;
|
||||
const uint8_t kHaierAcYrw02ButtonFan = 0b00100;
|
||||
const uint8_t kHaierAcYrw02ButtonPower = 0b00101;
|
||||
const uint8_t kHaierAcYrw02ButtonMode = 0b00110;
|
||||
const uint8_t kHaierAcYrw02ButtonHealth = 0b00111;
|
||||
const uint8_t kHaierAcYrw02ButtonTurbo = 0b01000;
|
||||
const uint8_t kHaierAcYrw02ButtonSleep = 0b01011;
|
||||
const uint8_t kHaierAcYrw02ButtonTimer = 0b10000;
|
||||
const uint8_t kHaierAcYrw02ButtonLock = 0b10100;
|
||||
const uint8_t kHaierAcYrw02ButtonCFAB = 0b11010;
|
||||
|
||||
const uint8_t kHaierAcYrw02NoTimers = 0b000;
|
||||
const uint8_t kHaierAcYrw02OffTimer = 0b001;
|
||||
|
@ -224,12 +195,13 @@ union HaierAc176Protocol{
|
|||
uint8_t raw[kHaierAC176StateLength]; ///< The state in native form
|
||||
struct {
|
||||
// Byte 0
|
||||
uint8_t Prefix :8;
|
||||
uint8_t Model :8;
|
||||
// Byte 1
|
||||
uint8_t Swing :4;
|
||||
uint8_t SwingV :4;
|
||||
uint8_t Temp :4; // 16C~30C
|
||||
// Byte 2
|
||||
uint8_t :8;
|
||||
uint8_t :5;
|
||||
uint8_t SwingH :3;
|
||||
// Byte 3
|
||||
uint8_t :1;
|
||||
uint8_t Health :1;
|
||||
|
@ -244,7 +216,8 @@ union HaierAc176Protocol{
|
|||
uint8_t Fan :3;
|
||||
// Byte 6
|
||||
uint8_t OffTimerMins:6;
|
||||
uint8_t Turbo:2;
|
||||
uint8_t Turbo :1;
|
||||
uint8_t Quiet :1;
|
||||
// Byte 7
|
||||
uint8_t OnTimerHrs :5;
|
||||
uint8_t Mode :3;
|
||||
|
@ -255,12 +228,16 @@ union HaierAc176Protocol{
|
|||
// Byte 9
|
||||
uint8_t :8;
|
||||
// Byte 10
|
||||
uint8_t :8;
|
||||
uint8_t ExtraDegreeF :1;
|
||||
uint8_t :4;
|
||||
uint8_t UseFahrenheit:1;
|
||||
uint8_t :2;
|
||||
// Byte 11
|
||||
uint8_t :8;
|
||||
// Byte 12
|
||||
uint8_t Button :4;
|
||||
uint8_t :4;
|
||||
uint8_t Button :5;
|
||||
uint8_t Lock :1;
|
||||
uint8_t :2;
|
||||
// Byte 13
|
||||
uint8_t Sum :8;
|
||||
// Byte 14
|
||||
|
@ -295,8 +272,6 @@ union HaierAc176Protocol{
|
|||
#define HAIER_AC_YRW02_FAN_LOW kHaierAcYrw02FanLow
|
||||
#define HAIER_AC_YRW02_FAN_AUTO kHaierAcYrw02FanAuto
|
||||
#define HAIER_AC_YRW02_TURBO_OFF kHaierAcYrw02TurboOff
|
||||
#define HAIER_AC_YRW02_TURBO_HIGH kHaierAcYrw02TurboHigh
|
||||
#define HAIER_AC_YRW02_TURBO_LOW kHaierAcYrw02TurboLow
|
||||
#define HAIER_AC_YRW02_AUTO kHaierAcYrw02Auto
|
||||
#define HAIER_AC_YRW02_COOL kHaierAcYrw02Cool
|
||||
#define HAIER_AC_YRW02_DRY kHaierAcYrw02Dry
|
||||
|
@ -355,8 +330,8 @@ class IRHaierAC {
|
|||
uint16_t getCurrTime(void) const;
|
||||
void setCurrTime(const uint16_t mins);
|
||||
|
||||
uint8_t getSwing(void) const;
|
||||
void setSwing(const uint8_t state);
|
||||
uint8_t getSwingV(void) const;
|
||||
void setSwingV(const uint8_t state);
|
||||
|
||||
uint8_t* getRaw(void);
|
||||
void setRaw(const uint8_t new_code[]);
|
||||
|
@ -400,10 +375,15 @@ class IRHaierAC176 {
|
|||
void begin(void);
|
||||
void stateReset(void);
|
||||
|
||||
void setModel(const haier_ac176_remote_model_t model);
|
||||
haier_ac176_remote_model_t getModel(void) const;
|
||||
|
||||
void setButton(const uint8_t button);
|
||||
uint8_t getButton(void) const;
|
||||
|
||||
void setTemp(const uint8_t temp);
|
||||
void setUseFahrenheit(const bool on);
|
||||
bool getUseFahrenheit(void) const;
|
||||
void setTemp(const uint8_t temp, const bool fahrenheit = false);
|
||||
uint8_t getTemp(void) const;
|
||||
|
||||
void setFan(const uint8_t speed);
|
||||
|
@ -422,9 +402,18 @@ class IRHaierAC176 {
|
|||
bool getHealth(void) const;
|
||||
void setHealth(const bool on);
|
||||
|
||||
uint8_t getTurbo(void) const;
|
||||
void setTurbo(const uint8_t speed);
|
||||
bool getTurbo(void) const;
|
||||
void setTurbo(const bool on);
|
||||
bool getQuiet(void) const;
|
||||
void setQuiet(const bool on);
|
||||
|
||||
uint8_t getSwingV(void) const;
|
||||
void setSwingV(const uint8_t pos);
|
||||
uint8_t getSwingH(void) const;
|
||||
void setSwingH(const uint8_t pos);
|
||||
|
||||
/// These functions are for backward compatibility.
|
||||
/// Use getSwingV() and setSwingV() instead.
|
||||
uint8_t getSwing(void) const;
|
||||
void setSwing(const uint8_t pos);
|
||||
|
||||
|
@ -435,6 +424,9 @@ class IRHaierAC176 {
|
|||
void setOffTimer(const uint16_t mins);
|
||||
uint16_t getOffTimer(void) const;
|
||||
|
||||
bool getLock(void) const;
|
||||
void setLock(const bool on);
|
||||
|
||||
uint8_t* getRaw(void);
|
||||
virtual void setRaw(const uint8_t new_code[]);
|
||||
static bool validChecksum(const uint8_t state[],
|
||||
|
@ -442,9 +434,13 @@ class IRHaierAC176 {
|
|||
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 uint8_t convertSwingH(const stdAc::swingh_t position);
|
||||
static stdAc::opmode_t toCommonMode(const uint8_t mode);
|
||||
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
|
||||
static stdAc::swingv_t toCommonSwingV(const uint8_t pos);
|
||||
static stdAc::swingh_t toCommonSwingH(const uint8_t pos);
|
||||
static bool toCommonTurbo(const uint8_t speed);
|
||||
static bool toCommonQuiet(const uint8_t speed);
|
||||
stdAc::state_t toCommon(void) const;
|
||||
String toString(void) const;
|
||||
#ifndef UNIT_TEST
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
// Brand: LG, Model: AMNW09GSJA0 A/C (LG2 - AKB74955603)
|
||||
// Brand: LG, Model: AMNW24GTPA1 A/C (LG2 - AKB73757604)
|
||||
// Brand: LG, Model: AKB73757604 remote (LG2 - AKB73757604)
|
||||
// Brand: LG, Model: AKB73315611 remote (LG2 - AKB74955603)
|
||||
// Brand: LG, Model: MS05SQ NW0 A/C (LG2 - AKB74955603)
|
||||
// Brand: General Electric, Model: AG1BH09AW101 Split A/C (LG)
|
||||
// Brand: General Electric, Model: 6711AR2853M A/C Remote (LG)
|
||||
|
||||
|
|
|
@ -1,15 +1,35 @@
|
|||
// Copyright 2020 David Conran (crankyoldgit)
|
||||
// Copyright 2020-2021 David Conran (crankyoldgit)
|
||||
/// @file
|
||||
/// @brief Support for Mirage protocol
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1289
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1573
|
||||
|
||||
// Supports:
|
||||
// Brand: Mirage, Model: VLU series A/C
|
||||
|
||||
#include "ir_Mirage.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#ifndef ARDUINO
|
||||
#include <string>
|
||||
#endif
|
||||
#include "IRrecv.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRtext.h"
|
||||
#include "IRutils.h"
|
||||
|
||||
using irutils::addBoolToString;
|
||||
using irutils::addFanToString;
|
||||
using irutils::addIntToString;
|
||||
using irutils::addLabeledString;
|
||||
using irutils::addModeToString;
|
||||
using irutils::addModelToString;
|
||||
using irutils::addSwingHToString;
|
||||
using irutils::addSwingVToString;
|
||||
using irutils::addTempToString;
|
||||
using irutils::addToggleToString;
|
||||
using irutils::minsToString;
|
||||
using irutils::bcdToUint8;
|
||||
using irutils::uint8ToBcd;
|
||||
using irutils::sumNibbles;
|
||||
|
||||
// Constants
|
||||
const uint16_t kMirageHdrMark = 8360; ///< uSeconds
|
||||
|
@ -20,6 +40,9 @@ const uint16_t kMirageZeroSpace = 545; ///< uSeconds
|
|||
const uint32_t kMirageGap = kDefaultMessageGap; ///< uSeconds (just a guess)
|
||||
const uint16_t kMirageFreq = 38000; ///< Hz. (Just a guess)
|
||||
|
||||
const uint8_t kMirageAcKKG29AC1PowerOn = 0b00; // 0
|
||||
const uint8_t kMirageAcKKG29AC1PowerOff = 0b11; // 3
|
||||
|
||||
|
||||
#if SEND_MIRAGE
|
||||
/// Send a Mirage formatted message.
|
||||
|
@ -58,6 +81,8 @@ bool IRrecv::decodeMirage(decode_results *results, uint16_t offset,
|
|||
kMirageBitMark, kMirageZeroSpace,
|
||||
kMirageBitMark, kMirageGap, true,
|
||||
kUseDefTol, kMarkExcess, false)) return false;
|
||||
// Compliance
|
||||
if (strict && !IRMirageAc::validChecksum(results->state)) return false;
|
||||
|
||||
// Success
|
||||
results->decode_type = decode_type_t::MIRAGE;
|
||||
|
@ -67,4 +92,756 @@ bool IRrecv::decodeMirage(decode_results *results, uint16_t offset,
|
|||
// is a union data type.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Code to emulate Mirage A/C IR remote control unit.
|
||||
|
||||
/// 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?
|
||||
IRMirageAc::IRMirageAc(const uint16_t pin, const bool inverted,
|
||||
const bool use_modulation)
|
||||
: _irsend(pin, inverted, use_modulation) { stateReset(); }
|
||||
|
||||
/// Reset the state of the remote to a known good state/sequence.
|
||||
void IRMirageAc::stateReset(void) {
|
||||
// The state of the IR remote in IR code form.
|
||||
static const uint8_t kReset[kMirageStateLength] = {
|
||||
0x56, 0x6C, 0x00, 0x00, 0x20, 0x1A, 0x00, 0x00,
|
||||
0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x42};
|
||||
setRaw(kReset);
|
||||
_model = mirage_ac_remote_model_t::KKG9AC1;
|
||||
}
|
||||
|
||||
/// Set up hardware to be able to send a message.
|
||||
void IRMirageAc::begin(void) { _irsend.begin(); }
|
||||
|
||||
#if SEND_MITSUBISHI_AC
|
||||
/// Send the current internal state as an IR message.
|
||||
/// @param[in] repeat Nr. of times the message will be repeated.
|
||||
void IRMirageAc::send(const uint16_t repeat) {
|
||||
_irsend.sendMirage(getRaw(), kMirageStateLength, repeat);
|
||||
// Reset any toggles after a send.
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
setCleanToggle(false);
|
||||
setLight(false); // For this model (only), Light is a toggle.
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // SEND_MITSUBISHI_AC
|
||||
|
||||
/// Get a PTR to the internal state/code for this protocol.
|
||||
/// @return PTR to a code for this protocol based on the current internal state.
|
||||
uint8_t *IRMirageAc::getRaw(void) {
|
||||
checksum();
|
||||
return _.raw;
|
||||
}
|
||||
|
||||
/// Set the internal state from a valid code for this protocol.
|
||||
/// @param[in] data A valid code for this protocol.
|
||||
void IRMirageAc::setRaw(const uint8_t *data) {
|
||||
std::memcpy(_.raw, data, kMirageStateLength);
|
||||
_model = getModel(true);
|
||||
}
|
||||
|
||||
/// Guess the Mirage remote model from the supplied state code.
|
||||
/// @param[in] state A valid state code for this protocol.
|
||||
/// @return The model code.
|
||||
/// @note This result isn't perfect. Both protocols can look the same but have
|
||||
/// wildly different settings.
|
||||
mirage_ac_remote_model_t IRMirageAc::getModel(const uint8_t *state) {
|
||||
Mirage120Protocol p;
|
||||
std::memcpy(p.raw, state, kMirageStateLength);
|
||||
// Check for KKG29AC1 specific settings.
|
||||
if (p.RecycleHeat || p.Filter || p.Sleep_Kkg29ac1 || p.CleanToggle ||
|
||||
p.IFeel || p.OffTimerEnable || p.OnTimerEnable)
|
||||
return mirage_ac_remote_model_t::KKG29AC1;
|
||||
// Check for things specific to KKG9AC1
|
||||
if ((p.Minutes || p.Seconds) || // Is part of the clock set?
|
||||
// Are the timer times set, but not enabled? (enable check filtered above)
|
||||
(p.OffTimerHours || p.OffTimerMins) ||
|
||||
(p.OnTimerHours || p.OnTimerMins))
|
||||
return mirage_ac_remote_model_t::KKG9AC1;
|
||||
// As the above test has a 1 in 3600+ (for 1 second an hour) chance of a false
|
||||
// negative in theory, we are going assume that anything left should be a
|
||||
// KKG29AC1 model.
|
||||
return mirage_ac_remote_model_t::KKG29AC1; // Default.
|
||||
}
|
||||
|
||||
/// Get the model code of the interal message state.
|
||||
/// @param[in] useRaw If set, we try to get the model info from just the state.
|
||||
/// @return The model code.
|
||||
mirage_ac_remote_model_t IRMirageAc::getModel(const bool useRaw) const {
|
||||
return useRaw ? getModel(_.raw) : _model;
|
||||
}
|
||||
|
||||
/// Set the model code of the interal message state.
|
||||
/// @param[in] model The desired model to use for the settings.
|
||||
void IRMirageAc::setModel(const mirage_ac_remote_model_t model) {
|
||||
if (model != _model) { // Only change things if we need to.
|
||||
// Save the old settings.
|
||||
stdAc::state_t state = toCommon();
|
||||
const uint16_t ontimer = getOnTimer();
|
||||
const uint16_t offtimer = getOffTimer();
|
||||
const bool ifeel = getIFeel();
|
||||
const uint8_t sensor = getSensorTemp();
|
||||
// Change the model.
|
||||
state.model = model;
|
||||
// Restore/Convert the settings.
|
||||
fromCommon(state);
|
||||
setOnTimer(ontimer);
|
||||
setOffTimer(offtimer);
|
||||
setIFeel(ifeel);
|
||||
setSensorTemp(sensor);
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate and set the checksum values for the internal state.
|
||||
void IRMirageAc::checksum(void) { _.Sum = calculateChecksum(_.raw); }
|
||||
|
||||
/// Verify the checksum is valid for a given state.
|
||||
/// @param[in] data The array to verify the checksum of.
|
||||
/// @return true, if the state has a valid checksum. Otherwise, false.
|
||||
bool IRMirageAc::validChecksum(const uint8_t *data) {
|
||||
return calculateChecksum(data) == data[kMirageStateLength - 1];
|
||||
}
|
||||
|
||||
/// Calculate the checksum for a given state.
|
||||
/// @param[in] data The value to calc the checksum of.
|
||||
/// @return The calculated checksum value.
|
||||
uint8_t IRMirageAc::calculateChecksum(const uint8_t *data) {
|
||||
return sumNibbles(data, kMirageStateLength - 1);
|
||||
}
|
||||
|
||||
/// Set the requested power state of the A/C to on.
|
||||
void IRMirageAc::on(void) { setPower(true); }
|
||||
|
||||
/// Set the requested power state of the A/C to off.
|
||||
void IRMirageAc::off(void) { setPower(false); }
|
||||
|
||||
/// Change the power setting.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRMirageAc::setPower(bool on) {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.Power = on ? kMirageAcKKG29AC1PowerOn : kMirageAcKKG29AC1PowerOff;
|
||||
break;
|
||||
default:
|
||||
// In order to change the power setting, it seems must be less than
|
||||
// kMirageAcPowerOff. kMirageAcPowerOff is larger than half of the
|
||||
// possible value stored in the allocated bit space.
|
||||
// Thus if the value is larger than kMirageAcPowerOff the power is off.
|
||||
// Less than, then power is on.
|
||||
// We can't just aribitarily add or subtract the value (which analysis
|
||||
// indicates is how the power status changes. Very weird, I know!) as that
|
||||
// is not an idempotent action, we must check if the addition or
|
||||
// substraction is needed first. e.g. via getPower()
|
||||
// i.e. If we added or subtracted twice, we would cause a wrap of the
|
||||
// integer and not get the desired result.
|
||||
if (on)
|
||||
_.SwingAndPower -= getPower() ? 0 : kMirageAcPowerOff;
|
||||
else
|
||||
_.SwingAndPower += getPower() ? kMirageAcPowerOff : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the value of the current power setting.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRMirageAc::getPower(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
return _.Power == kMirageAcKKG29AC1PowerOn;
|
||||
default:
|
||||
return _.SwingAndPower < kMirageAcPowerOff;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the operating mode setting of the A/C.
|
||||
/// @return The current operating mode setting.
|
||||
uint8_t IRMirageAc::getMode(void) const { return _.Mode; }
|
||||
|
||||
/// Set the operating mode of the A/C.
|
||||
/// @param[in] mode The desired operating mode.
|
||||
void IRMirageAc::setMode(const uint8_t mode) {
|
||||
switch (mode) {
|
||||
case kMirageAcCool:
|
||||
case kMirageAcDry:
|
||||
case kMirageAcHeat:
|
||||
case kMirageAcFan:
|
||||
case kMirageAcRecycle:
|
||||
_.Mode = mode;
|
||||
// Reset turbo if we have to.
|
||||
setTurbo(getTurbo());
|
||||
break;
|
||||
default: // Default to cool mode for anything else.
|
||||
setMode(kMirageAcCool);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the temperature.
|
||||
/// @param[in] degrees The temperature in degrees celsius.
|
||||
void IRMirageAc::setTemp(const uint8_t degrees) {
|
||||
// Make sure we have desired temp in the correct range.
|
||||
uint8_t celsius = std::max(degrees, kMirageAcMinTemp);
|
||||
_.Temp = std::min(celsius, kMirageAcMaxTemp) + kMirageAcTempOffset;
|
||||
}
|
||||
|
||||
/// Get the current temperature setting.
|
||||
/// @return The current setting for temp. in degrees celsius.
|
||||
uint8_t IRMirageAc::getTemp(void) const { return _.Temp - kMirageAcTempOffset; }
|
||||
|
||||
/// Set the speed of the fan.
|
||||
/// @param[in] speed The desired setting.
|
||||
void IRMirageAc::setFan(const uint8_t speed) {
|
||||
_.Fan = (speed <= kMirageAcFanLow) ? speed : kMirageAcFanAuto;
|
||||
}
|
||||
|
||||
/// Get the current fan speed setting.
|
||||
/// @return The current fan speed/mode.
|
||||
uint8_t IRMirageAc::getFan(void) const { return _.Fan; }
|
||||
|
||||
/// Change the Turbo setting.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRMirageAc::setTurbo(bool on) {
|
||||
const bool value = (on && (getMode() == kMirageAcCool));
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.Turbo_Kkg29ac1 = value;
|
||||
break;
|
||||
default:
|
||||
_.Turbo_Kkg9ac1 = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the value of the current Turbo setting.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRMirageAc::getTurbo(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1: return _.Turbo_Kkg29ac1;
|
||||
default: return _.Turbo_Kkg9ac1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Change the Sleep setting.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRMirageAc::setSleep(bool on) {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.Sleep_Kkg29ac1 = on;
|
||||
break;
|
||||
default:
|
||||
_.Sleep_Kkg9ac1 = on;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the value of the current Sleep setting.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRMirageAc::getSleep(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1: return _.Sleep_Kkg29ac1;
|
||||
default: return _.Sleep_Kkg9ac1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Change the Light/Display setting.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
/// @note Light is a toggle on the KKG29AC1 model.
|
||||
void IRMirageAc::setLight(bool on) {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.LightToggle_Kkg29ac1 = on;
|
||||
break;
|
||||
default:
|
||||
_.Light_Kkg9ac1 = on;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the value of the current Light/Display setting.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
/// @note Light is a toggle on the KKG29AC1 model.
|
||||
bool IRMirageAc::getLight(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1: return _.LightToggle_Kkg29ac1;
|
||||
default: return _.Light_Kkg9ac1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the clock time of the A/C unit.
|
||||
/// @return Nr. of seconds past midnight.
|
||||
uint32_t IRMirageAc::getClock(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
return 0;
|
||||
default:
|
||||
return ((bcdToUint8(_.Hours) * 60) + bcdToUint8(_.Minutes)) * 60 +
|
||||
bcdToUint8(_.Seconds);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the clock time on the A/C unit.
|
||||
/// @param[in] nr_of_seconds Nr. of seconds past midnight.
|
||||
void IRMirageAc::setClock(const uint32_t nr_of_seconds) {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.Minutes = _.Seconds = 0; // No clock setting. Clear it just in case.
|
||||
break;
|
||||
default:
|
||||
uint32_t remaining = std::min(
|
||||
nr_of_seconds, (uint32_t)(24 * 60 * 60 - 1)); // Limit to 23:59:59.
|
||||
_.Seconds = uint8ToBcd(remaining % 60);
|
||||
remaining /= 60;
|
||||
_.Minutes = uint8ToBcd(remaining % 60);
|
||||
remaining /= 60;
|
||||
_.Hours = uint8ToBcd(remaining);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the Vertical Swing setting/position of the A/C.
|
||||
/// @param[in] position The desired swing setting.
|
||||
void IRMirageAc::setSwingV(const uint8_t position) {
|
||||
switch (position) {
|
||||
case kMirageAcSwingVOff:
|
||||
case kMirageAcSwingVLowest:
|
||||
case kMirageAcSwingVLow:
|
||||
case kMirageAcSwingVMiddle:
|
||||
case kMirageAcSwingVHigh:
|
||||
case kMirageAcSwingVHighest:
|
||||
case kMirageAcSwingVAuto:
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.SwingV = (position != kMirageAcSwingVOff);
|
||||
break;
|
||||
default:
|
||||
const bool power = getPower();
|
||||
_.SwingAndPower = position;
|
||||
// Power needs to be reapplied after overwriting SwingAndPower
|
||||
setPower(power);
|
||||
}
|
||||
break;
|
||||
default: // Default to Auto for anything else.
|
||||
setSwingV(kMirageAcSwingVAuto);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Vertical Swing setting/position of the A/C.
|
||||
/// @return The desired Vertical Swing setting/position.
|
||||
uint8_t IRMirageAc::getSwingV(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
return _.SwingV ? kMirageAcSwingVAuto : kMirageAcSwingVOff;
|
||||
default:
|
||||
return _.SwingAndPower - (getPower() ? 0 : kMirageAcPowerOff);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the Horizontal Swing setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRMirageAc::setSwingH(const bool on) {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.SwingH = on;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Horizontal Swing setting of the A/C.
|
||||
/// @return on true, the setting is on. false, the setting is off.
|
||||
bool IRMirageAc::getSwingH(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1: return _.SwingH;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the Quiet setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRMirageAc::setQuiet(const bool on) {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.Quiet = on;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Quiet setting of the A/C.
|
||||
/// @return on true, the setting is on. false, the setting is off.
|
||||
bool IRMirageAc::getQuiet(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1: return _.Quiet;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the CleanToggle setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRMirageAc::setCleanToggle(const bool on) {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.CleanToggle = on;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Clean Toggle setting of the A/C.
|
||||
/// @return on true, the setting is on. false, the setting is off.
|
||||
bool IRMirageAc::getCleanToggle(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1: return _.CleanToggle;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the Filter setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRMirageAc::setFilter(const bool on) {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.Filter = on;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Filter setting of the A/C.
|
||||
/// @return on true, the setting is on. false, the setting is off.
|
||||
bool IRMirageAc::getFilter(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1: return _.Filter;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the IFeel setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRMirageAc::setIFeel(const bool on) {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.IFeel = on;
|
||||
if (on) {
|
||||
// If no previous sensor temp, default to currently desired temp.
|
||||
if (!_.SensorTemp) _.SensorTemp = getTemp();
|
||||
} else {
|
||||
_.SensorTemp = 0; // When turning it off, clear the Sensor Temp.
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the IFeel setting of the A/C.
|
||||
/// @return on true, the setting is on. false, the setting is off.
|
||||
bool IRMirageAc::getIFeel(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1: return _.IFeel;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the Sensor Temp setting of the A/C's remote.
|
||||
/// @param[in] degrees The desired sensor temp. in degrees celsius.
|
||||
void IRMirageAc::setSensorTemp(const uint8_t degrees) {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.SensorTemp = std::min(kMirageAcSensorTempMax, degrees) +
|
||||
kMirageAcSensorTempOffset;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Sensor Temp setting of the A/C's remote.
|
||||
/// @return The current setting for the sensor temp. in degrees celsius.
|
||||
uint16_t IRMirageAc::getSensorTemp(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
return _.SensorTemp - kMirageAcSensorTempOffset;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the number of minutes the On Timer is currently set for.
|
||||
/// @return Nr. of Minutes the timer is set for. 0, is the timer is not in use.
|
||||
uint16_t IRMirageAc::getOnTimer(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
return _.OnTimerEnable ? _.OnTimerHours * 60 + _.OnTimerMins : 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the number of minutes for the On Timer.
|
||||
/// @param[in] nr_of_mins How long to set the timer for. 0 disables the timer.
|
||||
void IRMirageAc::setOnTimer(const uint16_t nr_of_mins) {
|
||||
uint16_t mins = std::min(nr_of_mins, (uint16_t)(24 * 60));
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.OnTimerEnable = (mins > 0);
|
||||
_.OnTimerHours = mins / 60;
|
||||
_.OnTimerMins = mins % 60;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the number of minutes the Off Timer is currently set for.
|
||||
/// @return Nr. of Minutes the timer is set for. 0, is the timer is not in use.
|
||||
uint16_t IRMirageAc::getOffTimer(void) const {
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
return _.OffTimerEnable ? _.OffTimerHours * 60 + _.OffTimerMins : 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the number of minutes for the Off Timer.
|
||||
/// @param[in] nr_of_mins How long to set the timer for. 0 disables the timer.
|
||||
void IRMirageAc::setOffTimer(const uint16_t nr_of_mins) {
|
||||
uint16_t mins = std::min(nr_of_mins, (uint16_t)(24 * 60));
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
_.OffTimerEnable = (mins > 0);
|
||||
_.OffTimerHours = mins / 60;
|
||||
_.OffTimerMins = mins % 60;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 IRMirageAc::toCommonMode(const uint8_t mode) {
|
||||
switch (mode) {
|
||||
case kMirageAcHeat: return stdAc::opmode_t::kHeat;
|
||||
case kMirageAcDry: return stdAc::opmode_t::kDry;
|
||||
case kMirageAcFan: return stdAc::opmode_t::kFan;
|
||||
default: return stdAc::opmode_t::kCool;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a native fan speed into its stdAc equivalent.
|
||||
/// @param[in] speed The native setting to be converted.
|
||||
/// @param[in] model The model type to use to influence the conversion.
|
||||
/// @return The stdAc equivalent of the native setting.
|
||||
stdAc::fanspeed_t IRMirageAc::toCommonFanSpeed(const uint8_t speed,
|
||||
const mirage_ac_remote_model_t model) {
|
||||
switch (model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
switch (speed) {
|
||||
case kMirageAcKKG29AC1FanHigh: return stdAc::fanspeed_t::kHigh;
|
||||
case kMirageAcKKG29AC1FanMed: return stdAc::fanspeed_t::kMedium;
|
||||
case kMirageAcKKG29AC1FanLow: return stdAc::fanspeed_t::kLow;
|
||||
default: return stdAc::fanspeed_t::kAuto;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch (speed) {
|
||||
case kMirageAcFanHigh: return stdAc::fanspeed_t::kHigh;
|
||||
case kMirageAcFanMed: return stdAc::fanspeed_t::kMedium;
|
||||
case kMirageAcFanLow: return stdAc::fanspeed_t::kLow;
|
||||
default: return stdAc::fanspeed_t::kAuto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 IRMirageAc::convertMode(const stdAc::opmode_t mode) {
|
||||
switch (mode) {
|
||||
case stdAc::opmode_t::kHeat: return kMirageAcHeat;
|
||||
case stdAc::opmode_t::kDry: return kMirageAcDry;
|
||||
case stdAc::opmode_t::kFan: return kMirageAcFan;
|
||||
default: return kMirageAcCool;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a stdAc::fanspeed_t enum into it's native speed.
|
||||
/// @param[in] speed The enum to be converted.
|
||||
/// @param[in] model The model type to use to influence the conversion.
|
||||
/// @return The native equivalent of the enum.
|
||||
uint8_t IRMirageAc::convertFan(const stdAc::fanspeed_t speed,
|
||||
const mirage_ac_remote_model_t model) {
|
||||
uint8_t low;
|
||||
uint8_t med;
|
||||
switch (model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
low = kMirageAcKKG29AC1FanLow;
|
||||
med = kMirageAcKKG29AC1FanMed;
|
||||
break;
|
||||
default:
|
||||
low = kMirageAcFanLow;
|
||||
med = kMirageAcFanMed;
|
||||
}
|
||||
switch (speed) {
|
||||
case stdAc::fanspeed_t::kMin:
|
||||
case stdAc::fanspeed_t::kLow: return low;
|
||||
case stdAc::fanspeed_t::kMedium: return med;
|
||||
case stdAc::fanspeed_t::kHigh:
|
||||
case stdAc::fanspeed_t::kMax: return kMirageAcFanHigh;
|
||||
default: return kMirageAcFanAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a stdAc::swingv_t enum into it's native setting.
|
||||
/// @param[in] position The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
uint8_t IRMirageAc::convertSwingV(const stdAc::swingv_t position) {
|
||||
switch (position) {
|
||||
case stdAc::swingv_t::kHighest: return kMirageAcSwingVHighest;
|
||||
case stdAc::swingv_t::kHigh: return kMirageAcSwingVHigh;
|
||||
case stdAc::swingv_t::kMiddle: return kMirageAcSwingVMiddle;
|
||||
case stdAc::swingv_t::kLow: return kMirageAcSwingVLow;
|
||||
case stdAc::swingv_t::kLowest: return kMirageAcSwingVLowest;
|
||||
case stdAc::swingv_t::kOff: return kMirageAcSwingVOff;
|
||||
default: return kMirageAcSwingVAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a native vertical swing postion to it's common equivalent.
|
||||
/// @param[in] pos A native position to convert.
|
||||
/// @return The common vertical swing position.
|
||||
stdAc::swingv_t IRMirageAc::toCommonSwingV(const uint8_t pos) {
|
||||
switch (pos) {
|
||||
case kMirageAcSwingVHighest: return stdAc::swingv_t::kHighest;
|
||||
case kMirageAcSwingVHigh: return stdAc::swingv_t::kHigh;
|
||||
case kMirageAcSwingVMiddle: return stdAc::swingv_t::kMiddle;
|
||||
case kMirageAcSwingVLow: return stdAc::swingv_t::kLow;
|
||||
case kMirageAcSwingVLowest: return stdAc::swingv_t::kLowest;
|
||||
case kMirageAcSwingVAuto: return stdAc::swingv_t::kAuto;
|
||||
default: return stdAc::swingv_t::kOff;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the current internal state into its stdAc::state_t equivalent.
|
||||
/// @return The stdAc equivalent of the native settings.
|
||||
stdAc::state_t IRMirageAc::toCommon(void) const {
|
||||
stdAc::state_t result;
|
||||
result.protocol = decode_type_t::MIRAGE;
|
||||
result.model = _model;
|
||||
result.power = getPower();
|
||||
result.mode = toCommonMode(_.Mode);
|
||||
result.celsius = true;
|
||||
result.degrees = getTemp();
|
||||
result.fanspeed = toCommonFanSpeed(getFan(), _model);
|
||||
result.swingv = toCommonSwingV(getSwingV());
|
||||
result.swingh = getSwingH() ? stdAc::swingh_t::kAuto : stdAc::swingh_t::kOff;
|
||||
result.turbo = getTurbo();
|
||||
result.light = getLight();
|
||||
result.clean = getCleanToggle();
|
||||
result.filter = getFilter();
|
||||
result.sleep = getSleep() ? 0 : -1;
|
||||
result.quiet = getQuiet();
|
||||
result.clock = getClock() / 60;
|
||||
// Not supported.
|
||||
result.econo = false;
|
||||
result.beep = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Convert & set a stdAc::state_t to its equivalent internal settings.
|
||||
/// @param[in] state The desired state in stdAc::state_t form.
|
||||
void IRMirageAc::fromCommon(const stdAc::state_t state) {
|
||||
stateReset();
|
||||
_model = (mirage_ac_remote_model_t)state.model; // Set directly to avoid loop
|
||||
setPower(state.power);
|
||||
setTemp(state.celsius ? state.degrees : fahrenheitToCelsius(state.degrees));
|
||||
setMode(convertMode(state.mode));
|
||||
setFan(convertFan(state.fanspeed, _model));
|
||||
setTurbo(state.turbo);
|
||||
setSleep(state.sleep >= 0);
|
||||
setLight(state.light);
|
||||
setSwingV(convertSwingV(state.swingv));
|
||||
setSwingH(state.swingh != stdAc::swingh_t::kOff);
|
||||
setQuiet(state.quiet);
|
||||
setCleanToggle(state.clean);
|
||||
setFilter(state.filter);
|
||||
// setClock() expects seconds, not minutes.
|
||||
setClock((state.clock > 0) ? state.clock * 60 : 0);
|
||||
// Non-common settings.
|
||||
setOnTimer(0);
|
||||
setOffTimer(0);
|
||||
setIFeel(false);
|
||||
}
|
||||
|
||||
/// Convert the internal state into a human readable string.
|
||||
/// @return A string containing the settings in human-readable form.
|
||||
String IRMirageAc::toString(void) const {
|
||||
String result = "";
|
||||
result.reserve(240); // Reserve some heap for the string to reduce fragging.
|
||||
result += addModelToString(decode_type_t::MIRAGE, _model, false);
|
||||
result += addBoolToString(getPower(), kPowerStr);
|
||||
result += addModeToString(_.Mode, 0xFF, kMirageAcCool,
|
||||
kMirageAcHeat, kMirageAcDry,
|
||||
kMirageAcFan);
|
||||
result += addTempToString(getTemp());
|
||||
uint8_t fanlow;
|
||||
uint8_t fanmed;
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
fanlow = kMirageAcKKG29AC1FanLow;
|
||||
fanmed = kMirageAcKKG29AC1FanMed;
|
||||
break;
|
||||
default: // e.g. Model KKG9AC1
|
||||
fanlow = kMirageAcFanLow;
|
||||
fanmed = kMirageAcFanMed;
|
||||
}
|
||||
result += addFanToString(_.Fan, kMirageAcFanHigh, fanlow, kMirageAcFanAuto,
|
||||
kMirageAcFanAuto, fanmed);
|
||||
result += addBoolToString(getTurbo(), kTurboStr);
|
||||
result += addBoolToString(getSleep(), kSleepStr);
|
||||
switch (_model) {
|
||||
case mirage_ac_remote_model_t::KKG29AC1:
|
||||
result += addBoolToString(_.Quiet, kQuietStr);
|
||||
result += addToggleToString(getLight(), kLightStr);
|
||||
result += addBoolToString(_.SwingV, kSwingVStr);
|
||||
result += addBoolToString(_.SwingH, kSwingHStr);
|
||||
result += addBoolToString(_.Filter, kFilterStr);
|
||||
result += addToggleToString(_.CleanToggle, kCleanStr);
|
||||
result += addLabeledString(getOnTimer() ? minsToString(getOnTimer())
|
||||
: kOffStr,
|
||||
kOnTimerStr);
|
||||
result += addLabeledString(getOffTimer() ? minsToString(getOffTimer())
|
||||
: kOffStr,
|
||||
kOffTimerStr);
|
||||
result += addBoolToString(_.IFeel, kIFeelStr);
|
||||
if (_.IFeel) {
|
||||
result += addIntToString(getSensorTemp(), kSensorTempStr);
|
||||
result += 'C';
|
||||
}
|
||||
break;
|
||||
default: // e.g. Model KKG9AC1
|
||||
result += addBoolToString(getLight(), kLightStr);
|
||||
result += addSwingVToString(getSwingV(),
|
||||
kMirageAcSwingVAuto,
|
||||
kMirageAcSwingVHighest,
|
||||
kMirageAcSwingVHigh,
|
||||
0xFF, // Unused.
|
||||
kMirageAcSwingVMiddle,
|
||||
0xFF, // Unused.
|
||||
kMirageAcSwingVLow,
|
||||
kMirageAcSwingVLowest,
|
||||
kMirageAcSwingVOff,
|
||||
0xFF, 0xFF, 0xFF); // Unused.
|
||||
result += addLabeledString(minsToString(getClock() / 60), kClockStr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif // DECODE_MIRAGE
|
||||
|
|
|
@ -0,0 +1,277 @@
|
|||
// Copyright 2020-2021 David Conran (crankyoldgit)
|
||||
/// @file
|
||||
/// @brief Support for Mirage protocol
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1289
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1573
|
||||
|
||||
|
||||
// Supports:
|
||||
// Brand: Mirage, Model: VLU series A/C
|
||||
// Brand: Maxell, Model: MX-CH18CF A/C
|
||||
// Brand: Maxell, Model: KKG9A-C1 remote
|
||||
// Brand: Tronitechnik, Model: Reykir 9000 A/C
|
||||
// Brand: Tronitechnik, Model: KKG29A-C1 remote
|
||||
|
||||
#ifndef IR_MIRAGE_H_
|
||||
#define IR_MIRAGE_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 Mirage 120-bit A/C message.
|
||||
/// @see https://docs.google.com/spreadsheets/d/1Ucu9mOOIIJoWQjUJq_VCvwgV3EwKaRk8K2AuZgccYEk/edit#gid=0
|
||||
union Mirage120Protocol{
|
||||
uint8_t raw[kMirageStateLength]; ///< The state in code form.
|
||||
struct { // Common
|
||||
// Byte 0
|
||||
uint8_t Header :8; // Header. (0x56)
|
||||
// Byte 1
|
||||
uint8_t Temp :8; // Celsius minus 0x5C.
|
||||
// Byte 2
|
||||
uint8_t :8; // Unknown / Unused.
|
||||
// Byte 3
|
||||
uint8_t :8; // Unknown / Unused.
|
||||
// Byte 4
|
||||
uint8_t Fan :2; // Fan Speed.
|
||||
uint8_t :2; // Unknown / Unused.
|
||||
uint8_t Mode :4; // Cool, Heat, Dry, Fan, Recycle
|
||||
// Byte 5
|
||||
uint8_t :8;
|
||||
// Byte 6
|
||||
uint8_t :8;
|
||||
// Byte 7
|
||||
uint8_t :8;
|
||||
// Byte 8
|
||||
uint8_t :8;
|
||||
// Byte 9
|
||||
uint8_t :8;
|
||||
// Byte 10
|
||||
uint8_t :8;
|
||||
// Byte 11
|
||||
uint8_t :8;
|
||||
// Byte 12
|
||||
uint8_t :8;
|
||||
// Byte 13
|
||||
uint8_t :8;
|
||||
// Byte 14
|
||||
uint8_t Sum :8; // Sum of all the previous nibbles.
|
||||
};
|
||||
struct { // KKG9AC1 remote
|
||||
// Byte 0
|
||||
uint8_t :8; // Header
|
||||
// Byte 1
|
||||
uint8_t :8; // Temp
|
||||
// Byte 2
|
||||
uint8_t :8; // Unknown / Unused.
|
||||
// Byte 3
|
||||
uint8_t :3; // Unknown / Unused.
|
||||
uint8_t Light_Kkg9ac1 :1; // Aka. Display. Seems linked to Sleep mode.
|
||||
uint8_t :4; // Unknown / Unused.
|
||||
// Byte 4
|
||||
uint8_t :8; // Fan & Mode
|
||||
// Byte 5
|
||||
uint8_t :1; // Unknown
|
||||
uint8_t SwingAndPower :7;
|
||||
// Byte 6
|
||||
uint8_t :7; // Unknown / Unused.
|
||||
uint8_t Sleep_Kkg9ac1 :1; // Sleep mode on or off.
|
||||
// Byte 7
|
||||
uint8_t :3; // Unknown / Unused.
|
||||
uint8_t Turbo_Kkg9ac1 :1; // Turbo mode on or off. Only works in Cool mode.
|
||||
uint8_t :4; // Unknown / Unused.
|
||||
// Byte 8
|
||||
uint8_t :8; // Unknown / Unused.
|
||||
// Byte 9
|
||||
uint8_t :8; // Unknown / Unused.
|
||||
// Byte 10
|
||||
uint8_t :8; // Unknown / Unused.
|
||||
// Byte 11
|
||||
uint8_t Seconds :8; // Nr. of Seconds in BCD.
|
||||
// Byte 12
|
||||
uint8_t Minutes :8; // Nr. of Minutes in BCD.
|
||||
// Byte 13
|
||||
uint8_t Hours :8; // Nr. of Hours in BCD.
|
||||
// Byte 14
|
||||
uint8_t :8; // Sum
|
||||
};
|
||||
struct { // KKG29A-C1 remote
|
||||
// Byte 0
|
||||
uint8_t :8; // Header
|
||||
// Byte 1
|
||||
uint8_t :8; // Temp
|
||||
// Byte 2
|
||||
uint8_t :8;
|
||||
// Byte 3
|
||||
uint8_t Quiet :1;
|
||||
uint8_t :7;
|
||||
// Byte 4
|
||||
uint8_t :2; // Fan
|
||||
uint8_t OffTimerEnable :1;
|
||||
uint8_t OnTimerEnable :1;
|
||||
uint8_t :3; // Mode
|
||||
uint8_t :1;
|
||||
// Byte 5
|
||||
uint8_t SwingH :1;
|
||||
uint8_t SwingV :1;
|
||||
uint8_t LightToggle_Kkg29ac1 :1; // Aka. Display Toggle.
|
||||
uint8_t :3;
|
||||
uint8_t Power :2;
|
||||
// Byte 6
|
||||
uint8_t :1;
|
||||
uint8_t Filter :1; // Aka. UVC
|
||||
uint8_t :1;
|
||||
uint8_t Sleep_Kkg29ac1 :1; // Sleep mode on or off.
|
||||
uint8_t :2;
|
||||
uint8_t RecycleHeat :1;
|
||||
uint8_t :1;
|
||||
// Byte 7
|
||||
uint8_t SensorTemp :6; // Temperature at the remote
|
||||
uint8_t CleanToggle :1;
|
||||
uint8_t IFeel :1;
|
||||
// Byte 8
|
||||
uint8_t OnTimerHours :5;
|
||||
uint8_t :2;
|
||||
uint8_t Turbo_Kkg29ac1 :1; // Turbo mode on or off.
|
||||
// Byte 9
|
||||
uint8_t OnTimerMins :6;
|
||||
uint8_t :2;
|
||||
// Byte 10
|
||||
uint8_t OffTimerHours :5;
|
||||
uint8_t :3;
|
||||
// Byte 11
|
||||
uint8_t OffTimerMins :6;
|
||||
uint8_t :2;
|
||||
// Byte 12
|
||||
uint8_t :8;
|
||||
// Byte 13
|
||||
uint8_t :8;
|
||||
// Byte 14
|
||||
uint8_t :8; // Sum
|
||||
};
|
||||
};
|
||||
|
||||
// Constants
|
||||
const uint8_t kMirageAcHeat = 0b001; // 1
|
||||
const uint8_t kMirageAcCool = 0b010; // 2
|
||||
const uint8_t kMirageAcDry = 0b011; // 3
|
||||
const uint8_t kMirageAcRecycle = 0b100; // 4
|
||||
const uint8_t kMirageAcFan = 0b101; // 5
|
||||
|
||||
const uint8_t kMirageAcFanAuto = 0b00; // 0
|
||||
const uint8_t kMirageAcFanHigh = 0b01; // 1
|
||||
const uint8_t kMirageAcFanMed = 0b10; // 2
|
||||
const uint8_t kMirageAcFanLow = 0b11; // 3
|
||||
const uint8_t kMirageAcKKG29AC1FanAuto = 0b00; // 0
|
||||
const uint8_t kMirageAcKKG29AC1FanHigh = 0b01; // 1
|
||||
const uint8_t kMirageAcKKG29AC1FanLow = 0b10; // 2
|
||||
const uint8_t kMirageAcKKG29AC1FanMed = 0b11; // 3
|
||||
|
||||
const uint8_t kMirageAcMinTemp = 16; // 16C
|
||||
const uint8_t kMirageAcMaxTemp = 32; // 32C
|
||||
const uint8_t kMirageAcTempOffset = 0x5C;
|
||||
const uint8_t kMirageAcSensorTempOffset = 20;
|
||||
const uint8_t kMirageAcSensorTempMax = 43; // Celsius
|
||||
|
||||
const uint8_t kMirageAcPowerOff = 0x5F;
|
||||
const uint8_t kMirageAcSwingVOff = 0b0000; // 0
|
||||
const uint8_t kMirageAcSwingVLowest = 0b0011; // 3
|
||||
const uint8_t kMirageAcSwingVLow = 0b0101; // 5
|
||||
const uint8_t kMirageAcSwingVMiddle = 0b0111; // 7
|
||||
const uint8_t kMirageAcSwingVHigh = 0b1001; // 9
|
||||
const uint8_t kMirageAcSwingVHighest = 0b1011; // 11
|
||||
const uint8_t kMirageAcSwingVAuto = 0b1101; // 13
|
||||
|
||||
|
||||
/// Class for handling detailed Mirage 120-bit A/C messages.
|
||||
/// @note Inspired and derived from the work done at: https://github.com/r45635/HVAC-IR-Control
|
||||
/// @warning Consider this very alpha code. Seems to work, but not validated.
|
||||
class IRMirageAc {
|
||||
public:
|
||||
explicit IRMirageAc(const uint16_t pin, const bool inverted = false,
|
||||
const bool use_modulation = true);
|
||||
void stateReset(void);
|
||||
#if SEND_MIRAGE
|
||||
void send(const uint16_t repeat = kMirageMinRepeat);
|
||||
/// 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_MIRAGE
|
||||
void begin(void);
|
||||
void on(void);
|
||||
void off(void);
|
||||
void setPower(const bool on);
|
||||
bool getPower(void) const;
|
||||
void setTemp(const uint8_t degrees);
|
||||
uint8_t getTemp(void) const;
|
||||
void setFan(const uint8_t speed);
|
||||
uint8_t getFan(void) const;
|
||||
void setMode(const uint8_t mode);
|
||||
uint8_t getMode(void) const;
|
||||
uint8_t* getRaw(void);
|
||||
void setRaw(const uint8_t* data);
|
||||
uint32_t getClock(void) const;
|
||||
void setClock(const uint32_t nr_of_seconds);
|
||||
void setTurbo(const bool on);
|
||||
bool getTurbo(void) const;
|
||||
void setLight(const bool on);
|
||||
bool getLight(void) const;
|
||||
void setSleep(const bool on);
|
||||
bool getSleep(void) const;
|
||||
void setSwingV(const uint8_t position);
|
||||
uint8_t getSwingV(void) const;
|
||||
void setSwingH(const bool on);
|
||||
bool getSwingH(void) const;
|
||||
void setQuiet(const bool on);
|
||||
bool getQuiet(void) const;
|
||||
void setCleanToggle(const bool on);
|
||||
bool getCleanToggle(void) const;
|
||||
void setFilter(const bool on);
|
||||
bool getFilter(void) const;
|
||||
void setIFeel(const bool on);
|
||||
bool getIFeel(void) const;
|
||||
void setSensorTemp(const uint8_t degrees);
|
||||
uint16_t getSensorTemp(void) const;
|
||||
uint16_t getOnTimer(void) const;
|
||||
uint16_t getOffTimer(void) const;
|
||||
void setOnTimer(const uint16_t nr_of_mins);
|
||||
void setOffTimer(const uint16_t nr_of_mins);
|
||||
mirage_ac_remote_model_t getModel(const bool useRaw = false) const;
|
||||
void setModel(const mirage_ac_remote_model_t model);
|
||||
static mirage_ac_remote_model_t getModel(const uint8_t *state);
|
||||
static bool validChecksum(const uint8_t* data);
|
||||
static uint8_t calculateChecksum(const uint8_t* data);
|
||||
static uint8_t convertMode(const stdAc::opmode_t mode);
|
||||
static uint8_t convertFan(const stdAc::fanspeed_t speed,
|
||||
const mirage_ac_remote_model_t model = mirage_ac_remote_model_t::KKG9AC1);
|
||||
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,
|
||||
const mirage_ac_remote_model_t model = mirage_ac_remote_model_t::KKG9AC1);
|
||||
static stdAc::swingv_t toCommonSwingV(const uint8_t pos);
|
||||
stdAc::state_t toCommon(void) const;
|
||||
void fromCommon(const stdAc::state_t state);
|
||||
String toString(void) const;
|
||||
#ifndef UNIT_TEST
|
||||
|
||||
private:
|
||||
IRsend _irsend; ///< Instance of the IR send class
|
||||
#else // UNIT_TEST
|
||||
/// @cond IGNORE
|
||||
IRsendTest _irsend; ///< Instance of the testing IR send class
|
||||
/// @endcond
|
||||
#endif // UNIT_TEST
|
||||
Mirage120Protocol _;
|
||||
mirage_ac_remote_model_t _model;
|
||||
void checksum(void);
|
||||
};
|
||||
#endif // IR_MIRAGE_H_
|
|
@ -1166,7 +1166,7 @@ void IRsend::sendMitsubishi112(const unsigned char data[],
|
|||
}
|
||||
#endif // SEND_MITSUBISHI112
|
||||
|
||||
#if DECODE_MITSUBISHI112 || DECODE_TCL112AC
|
||||
#if (DECODE_MITSUBISHI112 || DECODE_TCL112AC)
|
||||
/// Decode the supplied Mitsubishi/TCL 112-bit A/C message.
|
||||
/// (MITSUBISHI112, TCL112AC)
|
||||
/// Status: STABLE / Reported as working.
|
||||
|
@ -1212,7 +1212,7 @@ bool IRrecv::decodeMitsubishi112(decode_results *results, uint16_t offset,
|
|||
gap = kMitsubishi112Gap;
|
||||
}
|
||||
#endif // DECODE_MITSUBISHI112
|
||||
#if DECODE_TCL112AC
|
||||
#if (DECODE_TCL112AC || DECODE_TEKNOPOINT)
|
||||
if (typeguess == decode_type_t::UNKNOWN && // We didn't match Mitsubishi112
|
||||
matchMark(results->rawbuf[offset], kTcl112AcHdrMark,
|
||||
kTcl112AcHdrMarkTolerance, 0)) {
|
||||
|
@ -1224,7 +1224,7 @@ bool IRrecv::decodeMitsubishi112(decode_results *results, uint16_t offset,
|
|||
gap = kTcl112AcGap;
|
||||
tolerance += kTcl112AcTolerance;
|
||||
}
|
||||
#endif // DECODE_TCL112AC
|
||||
#endif // (DECODE_TCL112AC || DECODE_TEKNOPOINT)
|
||||
if (typeguess == decode_type_t::UNKNOWN) return false; // No header matched.
|
||||
offset++;
|
||||
|
||||
|
|
|
@ -0,0 +1,364 @@
|
|||
// Copyright 2021 Tom Rosenback
|
||||
|
||||
/// @file
|
||||
/// @brief Support for Rhoss protocols.
|
||||
|
||||
#include "ir_Rhoss.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "IRrecv.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRtext.h"
|
||||
#include "IRutils.h"
|
||||
|
||||
const uint16_t kRhossHdrMark = 3042;
|
||||
const uint16_t kRhossHdrSpace = 4248;
|
||||
const uint16_t kRhossBitMark = 648;
|
||||
const uint16_t kRhossOneSpace = 1545;
|
||||
const uint16_t kRhossZeroSpace = 457;
|
||||
const uint32_t kRhossGap = kDefaultMessageGap;
|
||||
const uint16_t kRhossFreq = 38;
|
||||
|
||||
using irutils::addBoolToString;
|
||||
using irutils::addModeToString;
|
||||
using irutils::addFanToString;
|
||||
using irutils::addTempToString;
|
||||
|
||||
#if SEND_RHOSS
|
||||
/// Send a Rhoss HVAC formatted message.
|
||||
/// Status: STABLE / Reported as working.
|
||||
/// @param[in] data The message to be sent.
|
||||
/// @param[in] nbytes The number of bytes of message to be sent.
|
||||
/// @param[in] repeat The number of times the command is to be repeated.
|
||||
void IRsend::sendRhoss(const unsigned char data[], const uint16_t nbytes,
|
||||
const uint16_t repeat) {
|
||||
// Check if we have enough bytes to send a proper message.
|
||||
if (nbytes < kRhossStateLength) return;
|
||||
|
||||
// We always send a message, even for repeat=0, hence '<= repeat'.
|
||||
for (uint16_t r = 0; r <= repeat; r++) {
|
||||
sendGeneric(kRhossHdrMark, kRhossHdrSpace, kRhossBitMark,
|
||||
kRhossOneSpace, kRhossBitMark, kRhossZeroSpace,
|
||||
kRhossBitMark, kRhossZeroSpace,
|
||||
data, nbytes, kRhossFreq, false, 0, kDutyDefault);
|
||||
mark(kRhossBitMark);
|
||||
// Gap
|
||||
space(kRhossGap);
|
||||
}
|
||||
}
|
||||
#endif // SEND_RHOSS
|
||||
|
||||
#if DECODE_RHOSS
|
||||
/// Decode the supplied Rhoss formatted message.
|
||||
/// Status: STABLE / Known working.
|
||||
/// @param[in,out] results Ptr to the data to decode & where to store the result
|
||||
/// @param[in] offset The starting index to use when attempting to decode the
|
||||
/// raw data. Typically/Defaults to kStartOffset.
|
||||
/// @param[in] nbits The number of data bits to expect.
|
||||
/// @param[in] strict Flag indicating if we should perform strict matching.
|
||||
bool IRrecv::decodeRhoss(decode_results *results, uint16_t offset,
|
||||
const uint16_t nbits, const bool strict) {
|
||||
if (strict && nbits != kRhossBits) return false;
|
||||
|
||||
if (results->rawlen <= 2 * nbits + kHeader + kFooter - 1 + offset) {
|
||||
return false; // Can't possibly be a valid Rhoss message.
|
||||
}
|
||||
|
||||
uint16_t used;
|
||||
// Header + Data Block (96 bits) + Footer
|
||||
used = matchGeneric(results->rawbuf + offset, results->state,
|
||||
results->rawlen - offset, kRhossBits,
|
||||
kRhossHdrMark, kRhossHdrSpace,
|
||||
kRhossBitMark, kRhossOneSpace,
|
||||
kRhossBitMark, kRhossZeroSpace,
|
||||
kRhossBitMark, kRhossZeroSpace,
|
||||
false, kUseDefTol, kMarkExcess, false);
|
||||
|
||||
if (!used) return false;
|
||||
offset += used;
|
||||
|
||||
// Footer (Part 2)
|
||||
if (!matchMark(results->rawbuf[offset++], kRhossBitMark)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset < results->rawlen &&
|
||||
!matchAtLeast(results->rawbuf[offset], kRhossGap)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strict && !IRRhossAc::validChecksum(results->state)) return false;
|
||||
|
||||
// Success
|
||||
results->decode_type = decode_type_t::RHOSS;
|
||||
results->bits = nbits;
|
||||
// No need to record the state as we stored it as we decoded it.
|
||||
// As we use result->state, we don't record value, address, or command as it
|
||||
// is a union data type.
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // DECODE_RHOSS
|
||||
|
||||
/// 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?
|
||||
IRRhossAc::IRRhossAc(const uint16_t pin, const bool inverted,
|
||||
const bool use_modulation)
|
||||
: _irsend(pin, inverted, use_modulation) { this->stateReset(); }
|
||||
|
||||
/// Set up hardware to be able to send a message.
|
||||
void IRRhossAc::begin(void) { _irsend.begin(); }
|
||||
|
||||
#if SEND_RHOSS
|
||||
/// Send the current internal state as an IR message.
|
||||
/// @param[in] repeat Nr. of times the message will be repeated.
|
||||
void IRRhossAc::send(const uint16_t repeat) {
|
||||
_irsend.sendRhoss(getRaw(), kRhossStateLength, repeat);
|
||||
}
|
||||
#endif // SEND_RHOSS
|
||||
|
||||
/// Calculate the checksum for the supplied state.
|
||||
/// @param[in] state The source state to generate the checksum from.
|
||||
/// @param[in] length Length of the supplied state to checksum.
|
||||
/// @return The checksum value.
|
||||
uint8_t IRRhossAc::calcChecksum(const uint8_t state[], const uint16_t length) {
|
||||
return sumBytes(state, length - 1);
|
||||
}
|
||||
|
||||
/// Verify the checksum is valid for a given state.
|
||||
/// @param[in] state The array to verify the checksum of.
|
||||
/// @param[in] length The size of the state.
|
||||
/// @return A boolean indicating if it's checksum is valid.
|
||||
bool IRRhossAc::validChecksum(const uint8_t state[], const uint16_t length) {
|
||||
return (state[length - 1] == IRRhossAc::calcChecksum(state, length));
|
||||
}
|
||||
|
||||
/// Update the checksum value for the internal state.
|
||||
void IRRhossAc::checksum(void) {
|
||||
_.Sum = IRRhossAc::calcChecksum(_.raw, kRhossStateLength);
|
||||
_.raw[kRhossStateLength - 1] = _.Sum;
|
||||
}
|
||||
|
||||
/// Reset the internals of the object to a known good state.
|
||||
void IRRhossAc::stateReset(void) {
|
||||
for (uint8_t i = 1; i < kRhossStateLength; i++) _.raw[i] = 0x0;
|
||||
_.raw[0] = 0xAA;
|
||||
_.raw[2] = 0x60;
|
||||
_.raw[6] = 0x54;
|
||||
_.Power = kRhossDefaultPower;
|
||||
_.Fan = kRhossDefaultFan;
|
||||
_.Mode = kRhossDefaultMode;
|
||||
_.Swing = kRhossDefaultSwing;
|
||||
_.Temp = kRhossDefaultTemp - kRhossTempMin;
|
||||
}
|
||||
|
||||
/// Get the raw state of the object, suitable to be sent with the appropriate
|
||||
/// IRsend object method.
|
||||
/// @return A PTR to the internal state.
|
||||
uint8_t* IRRhossAc::getRaw(void) {
|
||||
checksum(); // Ensure correct bit array before returning
|
||||
return _.raw;
|
||||
}
|
||||
|
||||
/// Set the raw state of the object.
|
||||
/// @param[state] state The raw state from the native IR message.
|
||||
void IRRhossAc::setRaw(const uint8_t state[]) {
|
||||
std::memcpy(_.raw, state, kRhossStateLength);
|
||||
}
|
||||
|
||||
/// Set the internal state to have the power on.
|
||||
void IRRhossAc::on(void) { setPower(true); }
|
||||
|
||||
/// Set the internal state to have the power off.
|
||||
void IRRhossAc::off(void) { setPower(false); }
|
||||
|
||||
/// Set the internal state to have the desired power.
|
||||
/// @param[in] on The desired power state.
|
||||
void IRRhossAc::setPower(const bool on) {
|
||||
_.Power = (on ? kRhossPowerOn : kRhossPowerOff);
|
||||
}
|
||||
|
||||
/// Get the power setting from the internal state.
|
||||
/// @return A boolean indicating the power setting.
|
||||
bool IRRhossAc::getPower(void) const {
|
||||
return _.Power == kRhossPowerOn;
|
||||
}
|
||||
|
||||
/// Set the temperature.
|
||||
/// @param[in] degrees The temperature in degrees celsius.
|
||||
void IRRhossAc::setTemp(const uint8_t degrees) {
|
||||
uint8_t temp = std::max(kRhossTempMin, degrees);
|
||||
_.Temp = std::min(kRhossTempMax, temp) - kRhossTempMin;
|
||||
}
|
||||
|
||||
/// Get the current temperature setting.
|
||||
/// @return Get current setting for temp. in degrees celsius.
|
||||
uint8_t IRRhossAc::getTemp(void) const {
|
||||
return _.Temp + kRhossTempMin;
|
||||
}
|
||||
|
||||
/// Set the speed of the fan.
|
||||
/// @param[in] speed The desired setting.
|
||||
void IRRhossAc::setFan(const uint8_t speed) {
|
||||
switch (speed) {
|
||||
case kRhossFanAuto:
|
||||
case kRhossFanMin:
|
||||
case kRhossFanMed:
|
||||
case kRhossFanMax:
|
||||
_.Fan = speed;
|
||||
break;
|
||||
default:
|
||||
_.Fan = kRhossFanAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current fan speed setting.
|
||||
/// @return The current fan speed.
|
||||
uint8_t IRRhossAc::getFan(void) const {
|
||||
return _.Fan;
|
||||
}
|
||||
|
||||
/// Set the Vertical Swing mode of the A/C.
|
||||
/// @param[in] state true, the Swing is on. false, the Swing is off.
|
||||
void IRRhossAc::setSwing(const bool state) {
|
||||
_.Swing = state;
|
||||
}
|
||||
|
||||
/// Get the Vertical Swing speed of the A/C.
|
||||
/// @return The native swing speed setting.
|
||||
uint8_t IRRhossAc::getSwing(void) const {
|
||||
return _.Swing;
|
||||
}
|
||||
|
||||
/// Get the current operation mode setting.
|
||||
/// @return The current operation mode.
|
||||
uint8_t IRRhossAc::getMode(void) const {
|
||||
return _.Mode;
|
||||
}
|
||||
|
||||
/// Set the desired operation mode.
|
||||
/// @param[in] mode The desired operation mode.
|
||||
void IRRhossAc::setMode(const uint8_t mode) {
|
||||
switch (mode) {
|
||||
case kRhossModeFan:
|
||||
case kRhossModeCool:
|
||||
case kRhossModeDry:
|
||||
case kRhossModeHeat:
|
||||
case kRhossModeAuto:
|
||||
_.Mode = mode;
|
||||
return;
|
||||
default:
|
||||
_.Mode = kRhossDefaultMode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 IRRhossAc::convertMode(const stdAc::opmode_t mode) {
|
||||
switch (mode) {
|
||||
case stdAc::opmode_t::kCool:
|
||||
return kRhossModeCool;
|
||||
case stdAc::opmode_t::kHeat:
|
||||
return kRhossModeHeat;
|
||||
case stdAc::opmode_t::kDry:
|
||||
return kRhossModeDry;
|
||||
case stdAc::opmode_t::kFan:
|
||||
return kRhossModeFan;
|
||||
case stdAc::opmode_t::kAuto:
|
||||
return kRhossModeAuto;
|
||||
default:
|
||||
return kRhossDefaultMode;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 IRRhossAc::convertFan(const stdAc::fanspeed_t speed) {
|
||||
switch (speed) {
|
||||
case stdAc::fanspeed_t::kMin:
|
||||
case stdAc::fanspeed_t::kLow:
|
||||
return kRhossFanMin;
|
||||
case stdAc::fanspeed_t::kMedium:
|
||||
return kRhossFanMed;
|
||||
case stdAc::fanspeed_t::kHigh:
|
||||
case stdAc::fanspeed_t::kMax:
|
||||
return kRhossFanMax;
|
||||
default:
|
||||
return kRhossDefaultFan;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 IRRhossAc::toCommonMode(const uint8_t mode) {
|
||||
switch (mode) {
|
||||
case kRhossModeCool: return stdAc::opmode_t::kCool;
|
||||
case kRhossModeHeat: return stdAc::opmode_t::kHeat;
|
||||
case kRhossModeDry: return stdAc::opmode_t::kDry;
|
||||
case kRhossModeFan: return stdAc::opmode_t::kFan;
|
||||
case kRhossModeAuto: return stdAc::opmode_t::kAuto;
|
||||
default: return stdAc::opmode_t::kAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a native fan speed into its stdAc equivalent.
|
||||
/// @param[in] speed The native setting to be converted.
|
||||
/// @return The stdAc equivalent of the native setting.
|
||||
stdAc::fanspeed_t IRRhossAc::toCommonFanSpeed(const uint8_t speed) {
|
||||
switch (speed) {
|
||||
case kRhossFanMax: return stdAc::fanspeed_t::kMax;
|
||||
case kRhossFanMed: return stdAc::fanspeed_t::kMedium;
|
||||
case kRhossFanMin: return stdAc::fanspeed_t::kMin;
|
||||
case kRhossFanAuto:
|
||||
default:
|
||||
return stdAc::fanspeed_t::kAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the current internal state into its stdAc::state_t equivalent.
|
||||
/// @return The stdAc equivalent of the native settings.
|
||||
stdAc::state_t IRRhossAc::toCommon(void) const {
|
||||
stdAc::state_t result;
|
||||
result.protocol = decode_type_t::RHOSS;
|
||||
result.power = getPower();
|
||||
result.mode = toCommonMode(_.Mode);
|
||||
result.celsius = true;
|
||||
result.degrees = _.Temp;
|
||||
result.fanspeed = toCommonFanSpeed(_.Fan);
|
||||
result.swingv = _.Swing ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff;
|
||||
// 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.sleep = -1;
|
||||
result.clock = -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Convert the current internal state into a human readable string.
|
||||
/// @return A human readable string.
|
||||
String IRRhossAc::toString(void) const {
|
||||
String result = "";
|
||||
result.reserve(70); // Reserve some heap for the string to reduce fragging.
|
||||
result += addBoolToString(getPower(), kPowerStr, false);
|
||||
result += addModeToString(getMode(), kRhossModeAuto, kRhossModeCool,
|
||||
kRhossModeHeat, kRhossModeDry, kRhossModeFan);
|
||||
result += addTempToString(getTemp());
|
||||
result += addFanToString(getFan(), kRhossFanMax, kRhossFanMin,
|
||||
kRhossFanAuto, kRhossFanAuto,
|
||||
kRhossFanMed);
|
||||
result += addBoolToString(getSwing(), kSwingVStr);
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
// Copyright 2021 Tom Rosenback
|
||||
|
||||
/// @file
|
||||
/// @brief Support for Rhoss A/C protocol
|
||||
// Supports:
|
||||
// Brand: Rhoss, Model: Idrowall MPCV 20-30-35-40
|
||||
|
||||
#ifndef IR_RHOSS_H_
|
||||
#define IR_RHOSS_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 Rhoss A/C message.
|
||||
union RhossProtocol{
|
||||
uint8_t raw[kRhossStateLength]; // The state of the IR remote.
|
||||
struct {
|
||||
// Byte 0
|
||||
uint8_t :8; // Typically 0xAA
|
||||
// Byte 1
|
||||
uint8_t Temp :4;
|
||||
uint8_t :4; // Typically 0x0
|
||||
// Byte 2
|
||||
uint8_t :8; // Typically 0x60
|
||||
// Byte 3
|
||||
uint8_t :8; // Typically 0x0
|
||||
// Byte 4
|
||||
uint8_t Fan :2;
|
||||
uint8_t :2; // Typically 0x0
|
||||
uint8_t Mode :4;
|
||||
// Byte 5
|
||||
uint8_t Swing :1;
|
||||
uint8_t :5; // Typically 0x0
|
||||
uint8_t Power :2;
|
||||
// Byte 6
|
||||
uint8_t :8; // Typically 0x54
|
||||
// Byte 7
|
||||
uint8_t :8; // Typically 0x0
|
||||
// Byte 8
|
||||
uint8_t :8; // Typically 0x0
|
||||
// Byte 9
|
||||
uint8_t :8; // Typically 0x0
|
||||
// Byte 10
|
||||
uint8_t :8; // Typically 0x0
|
||||
// Byte 11
|
||||
uint8_t Sum :8;
|
||||
};
|
||||
};
|
||||
|
||||
// Constants
|
||||
|
||||
// Fan Control
|
||||
const uint8_t kRhossFanAuto = 0b00;
|
||||
const uint8_t kRhossFanMin = 0b01;
|
||||
const uint8_t kRhossFanMed = 0b10;
|
||||
const uint8_t kRhossFanMax = 0b11;
|
||||
// Modes
|
||||
const uint8_t kRhossModeHeat = 0b0001;
|
||||
const uint8_t kRhossModeCool = 0b0010;
|
||||
const uint8_t kRhossModeDry = 0b0011;
|
||||
const uint8_t kRhossModeFan = 0b0100;
|
||||
const uint8_t kRhossModeAuto = 0b0101;
|
||||
|
||||
// Temperature
|
||||
const uint8_t kRhossTempMin = 16; // Celsius
|
||||
const uint8_t kRhossTempMax = 30; // Celsius
|
||||
|
||||
// Power
|
||||
const uint8_t kRhossPowerOn = 0b10; // 0x2
|
||||
const uint8_t kRhossPowerOff = 0b01; // 0x1
|
||||
|
||||
// Swing
|
||||
const uint8_t kRhossSwingOn = 0b1; // 0x1
|
||||
const uint8_t kRhossSwingOff = 0b0; // 0x0
|
||||
|
||||
const uint8_t kRhossDefaultFan = kRhossFanAuto;
|
||||
const uint8_t kRhossDefaultMode = kRhossModeCool;
|
||||
const uint8_t kRhossDefaultTemp = 21; // Celsius
|
||||
const bool kRhossDefaultPower = false;
|
||||
const bool kRhossDefaultSwing = false;
|
||||
|
||||
// Classes
|
||||
|
||||
/// Class for handling detailed Rhoss A/C messages.
|
||||
class IRRhossAc {
|
||||
public:
|
||||
explicit IRRhossAc(const uint16_t pin, const bool inverted = false,
|
||||
const bool use_modulation = true);
|
||||
|
||||
void stateReset();
|
||||
#if SEND_RHOSS
|
||||
void send(const uint16_t repeat = kRhossDefaultRepeat);
|
||||
/// 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_RHOSS
|
||||
void begin();
|
||||
static uint8_t calcChecksum(const uint8_t state[],
|
||||
const uint16_t length = kRhossStateLength);
|
||||
static bool validChecksum(const uint8_t state[],
|
||||
const uint16_t length = kRhossStateLength);
|
||||
void setPower(const bool state);
|
||||
bool getPower(void) const;
|
||||
void on(void);
|
||||
void off(void);
|
||||
void setTemp(const uint8_t temp);
|
||||
uint8_t getTemp(void) const;
|
||||
void setFan(const uint8_t speed);
|
||||
uint8_t getFan(void) const;
|
||||
void setSwing(const bool state);
|
||||
uint8_t getSwing(void) const;
|
||||
void setMode(const uint8_t mode);
|
||||
uint8_t getMode(void) const;
|
||||
uint8_t* getRaw(void);
|
||||
void setRaw(const uint8_t state[]);
|
||||
static uint8_t convertMode(const stdAc::opmode_t mode);
|
||||
static uint8_t convertFan(const stdAc::fanspeed_t speed);
|
||||
static stdAc::opmode_t toCommonMode(const uint8_t mode);
|
||||
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
|
||||
stdAc::state_t toCommon(void) const;
|
||||
String toString(void) const;
|
||||
#ifndef UNIT_TEST
|
||||
|
||||
private:
|
||||
IRsend _irsend;
|
||||
#else
|
||||
/// @cond IGNORE
|
||||
IRsendTest _irsend;
|
||||
/// @endcond
|
||||
#endif
|
||||
RhossProtocol _;
|
||||
void checksum(void);
|
||||
};
|
||||
#endif // IR_RHOSS_H_
|
|
@ -1,5 +1,5 @@
|
|||
// Copyright 2009 Ken Shirriff
|
||||
// Copyright 2017, 2018, 2019 David Conran
|
||||
// Copyright 2017-2021 David Conran
|
||||
/// @file
|
||||
/// @brief Support for Samsung protocols.
|
||||
/// Samsung originally added from https://github.com/shirriff/Arduino-IRremote/
|
||||
|
@ -62,12 +62,25 @@ const uint16_t kSamsung36BitMark = 512; /// < uSeconds
|
|||
const uint16_t kSamsung36OneSpace = 1468; /// < uSeconds
|
||||
const uint16_t kSamsung36ZeroSpace = 490; /// < uSeconds
|
||||
|
||||
// _.Swing
|
||||
const uint8_t kSamsungAcSwingV = 0b010;
|
||||
const uint8_t kSamsungAcSwingH = 0b011;
|
||||
const uint8_t kSamsungAcSwingBoth = 0b100;
|
||||
const uint8_t kSamsungAcSwingOff = 0b111;
|
||||
// _.FanSpecial
|
||||
const uint8_t kSamsungAcFanSpecialOff = 0b000;
|
||||
const uint8_t kSamsungAcPowerfulOn = 0b011;
|
||||
const uint8_t kSamsungAcBreezeOn = 0b101;
|
||||
const uint8_t kSamsungAcEconoOn = 0b111;
|
||||
|
||||
using irutils::addBoolToString;
|
||||
using irutils::addFanToString;
|
||||
using irutils::addIntToString;
|
||||
using irutils::addLabeledString;
|
||||
using irutils::addModeToString;
|
||||
using irutils::addTempToString;
|
||||
using irutils::addToggleToString;
|
||||
using irutils::minsToString;
|
||||
|
||||
#if SEND_SAMSUNG
|
||||
/// Send a 32-bit Samsung formatted message.
|
||||
|
@ -275,17 +288,22 @@ IRSamsungAc::IRSamsungAc(const uint16_t pin, const bool inverted,
|
|||
}
|
||||
|
||||
/// Reset the internal state of the emulation.
|
||||
/// @param[in] forcepower A flag indicating if force sending a special power
|
||||
/// @param[in] extended A flag indicating if force sending a special extended
|
||||
/// message with the first `send()` call.
|
||||
/// @param[in] initialPower Set the initial power state. True, on. False, off.
|
||||
void IRSamsungAc::stateReset(const bool forcepower, const bool initialPower) {
|
||||
void IRSamsungAc::stateReset(const bool extended, const bool initialPower) {
|
||||
static const uint8_t kReset[kSamsungAcExtendedStateLength] = {
|
||||
0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
|
||||
0x01, 0x02, 0xAE, 0x71, 0x00, 0x15, 0xF0};
|
||||
std::memcpy(_.raw, kReset, kSamsungAcExtendedStateLength);
|
||||
_forcepower = forcepower;
|
||||
_forceextended = extended;
|
||||
_lastsentpowerstate = initialPower;
|
||||
setPower(initialPower);
|
||||
_OnTimerEnable = false;
|
||||
_OffTimerEnable = false;
|
||||
_Sleep = false;
|
||||
_lastSleep = false;
|
||||
_OnTimer = _OffTimer = _lastOnTimer = _lastOffTimer = 0;
|
||||
}
|
||||
|
||||
/// Set up hardware to be able to send a message.
|
||||
|
@ -351,30 +369,28 @@ void IRSamsungAc::checksum(void) {
|
|||
#if SEND_SAMSUNG_AC
|
||||
/// Send the current internal state as an IR message.
|
||||
/// @param[in] repeat Nr. of times the message will be repeated.
|
||||
/// @param[in] calcchecksum Do we update the checksum before sending?
|
||||
/// @note Use for most function/mode/settings changes to the unit.
|
||||
/// i.e. When the device is already running.
|
||||
void IRSamsungAc::send(const uint16_t repeat, const bool calcchecksum) {
|
||||
// Do we need to send a the special power on/off message? i.e. An Extended Msg
|
||||
if (getPower() != _lastsentpowerstate || _forcepower) { // We do.
|
||||
sendExtended(repeat, calcchecksum);
|
||||
_forcepower = false; // It has now been sent, so clear the flag if set.
|
||||
} else { // No, it's just a normal message.
|
||||
if (calcchecksum) checksum();
|
||||
_irsend.sendSamsungAC(_.raw, kSamsungAcStateLength, repeat);
|
||||
}
|
||||
void IRSamsungAc::send(const uint16_t repeat) {
|
||||
// Do we need to send a special (extended) message?
|
||||
if (getPower() != _lastsentpowerstate || _forceextended ||
|
||||
(_lastOnTimer != _OnTimer) || (_lastOffTimer != _OffTimer) ||
|
||||
(_Sleep != _lastSleep)) // We do.
|
||||
sendExtended(repeat);
|
||||
else // No, it's just a normal message.
|
||||
_irsend.sendSamsungAC(getRaw(), kSamsungAcStateLength, repeat);
|
||||
}
|
||||
|
||||
/// Send the extended current internal state as an IR message.
|
||||
/// @param[in] repeat Nr. of times the message will be repeated.
|
||||
/// @param[in] calcchecksum Do we update the checksum before sending?
|
||||
/// @note Use this for when you need to power on/off the device.
|
||||
/// Samsung A/C requires an extended length message when you want to
|
||||
/// change the power operating mode of the A/C unit.
|
||||
void IRSamsungAc::sendExtended(const uint16_t repeat, const bool calcchecksum) {
|
||||
/// @note Samsung A/C requires an extended length message when you want to
|
||||
/// change the power operating mode, Timers, or Sleep setting of the A/C unit.
|
||||
void IRSamsungAc::sendExtended(const uint16_t repeat) {
|
||||
_lastsentpowerstate = getPower(); // Remember the last power state sent.
|
||||
_lastOnTimer = _OnTimer;
|
||||
_lastOffTimer = _OffTimer;
|
||||
static const uint8_t extended_middle_section[kSamsungAcSectionLength] = {
|
||||
0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00};
|
||||
if (calcchecksum) checksum();
|
||||
// Copy/convert the internal state to an extended state by
|
||||
// copying the second section to the third section, and inserting the extended
|
||||
// middle (second) section.
|
||||
|
@ -383,13 +399,16 @@ void IRSamsungAc::sendExtended(const uint16_t repeat, const bool calcchecksum) {
|
|||
kSamsungAcSectionLength);
|
||||
std::memcpy(_.raw + kSamsungAcSectionLength, extended_middle_section,
|
||||
kSamsungAcSectionLength);
|
||||
_setOnTimer();
|
||||
_setSleepTimer(); // This also sets any Off Timer if needed too.
|
||||
// Send it.
|
||||
_irsend.sendSamsungAC(_.raw, kSamsungAcExtendedStateLength, repeat);
|
||||
_irsend.sendSamsungAC(getRaw(), kSamsungAcExtendedStateLength, repeat);
|
||||
// Now revert it by copying the third section over the second section.
|
||||
std::memcpy(_.raw + kSamsungAcSectionLength,
|
||||
_.raw + 2* kSamsungAcSectionLength,
|
||||
_.raw + 2 * kSamsungAcSectionLength,
|
||||
kSamsungAcSectionLength);
|
||||
_lastsentpowerstate = getPower(); // Remember the last power state sent.
|
||||
|
||||
_forceextended = false; // It has now been sent, so clear the flag if set.
|
||||
}
|
||||
|
||||
/// Send the special extended "On" message as the library can't seem to
|
||||
|
@ -434,6 +453,11 @@ void IRSamsungAc::setRaw(const uint8_t new_code[], const uint16_t length) {
|
|||
kSamsungAcExtendedStateLength));
|
||||
// Shrink the extended state into a normal state.
|
||||
if (length > kSamsungAcStateLength) {
|
||||
_OnTimerEnable = _.OnTimerEnable;
|
||||
_OffTimerEnable = _.OffTimerEnable;
|
||||
_Sleep = _.Sleep5 && _.Sleep12;
|
||||
_OnTimer = _getOnTimer();
|
||||
_OffTimer = _getOffTimer();
|
||||
for (uint8_t i = kSamsungAcStateLength; i < length; i++)
|
||||
_.raw[i - kSamsungAcSectionLength] = _.raw[i];
|
||||
}
|
||||
|
@ -448,14 +472,13 @@ void IRSamsungAc::off(void) { setPower(false); }
|
|||
/// Change the power setting.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRSamsungAc::setPower(const bool on) {
|
||||
_.Power1 = !on; // Cleared when on.
|
||||
_.Power6 = (on ? 0b11 : 0b00);
|
||||
_.Power1 = _.Power2 = (on ? 0b11 : 0b00);
|
||||
}
|
||||
|
||||
/// Get the value of the current power setting.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSamsungAc::getPower(void) const {
|
||||
return (_.Power6 == 0b11) && !_.Power1;
|
||||
return _.Power1 == 0b11 && _.Power2 == 0b11;
|
||||
}
|
||||
|
||||
/// Set the temperature.
|
||||
|
@ -524,56 +547,79 @@ uint8_t IRSamsungAc::getFan(void) const {
|
|||
|
||||
/// Get the vertical swing setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
/// @todo (Hollako) Explain why sometimes the LSB of remote_state[9] is a 1.
|
||||
/// e.g. 0xAE or 0XAF for swing move.
|
||||
bool IRSamsungAc::getSwing(void) const {
|
||||
return _.Swing == kSamsungAcSwingMove;
|
||||
switch (_.Swing) {
|
||||
case kSamsungAcSwingV:
|
||||
case kSamsungAcSwingBoth: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the vertical swing setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
/// @todo (Hollako) Explain why sometimes the LSB of remote_state[9] is a 1.
|
||||
/// e.g. 0xAE or 0XAF for swing move.
|
||||
void IRSamsungAc::setSwing(const bool on) {
|
||||
_.Swing = (on ? kSamsungAcSwingMove : kSamsungAcSwingStop);
|
||||
switch (_.Swing) {
|
||||
case kSamsungAcSwingBoth:
|
||||
case kSamsungAcSwingH:
|
||||
_.Swing = on ? kSamsungAcSwingBoth : kSamsungAcSwingH;
|
||||
break;
|
||||
default:
|
||||
_.Swing = on ? kSamsungAcSwingV : kSamsungAcSwingOff;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Beep setting of the A/C.
|
||||
/// Get the horizontal swing setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSamsungAc::getBeep(void) const {
|
||||
return _.Beep;
|
||||
bool IRSamsungAc::getSwingH(void) const {
|
||||
switch (_.Swing) {
|
||||
case kSamsungAcSwingH:
|
||||
case kSamsungAcSwingBoth: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the Beep setting of the A/C.
|
||||
/// Set the horizontal swing setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRSamsungAc::setBeep(const bool on) {
|
||||
_.Beep = on;
|
||||
void IRSamsungAc::setSwingH(const bool on) {
|
||||
switch (_.Swing) {
|
||||
case kSamsungAcSwingV:
|
||||
case kSamsungAcSwingBoth:
|
||||
_.Swing = on ? kSamsungAcSwingBoth : kSamsungAcSwingV;
|
||||
break;
|
||||
default:
|
||||
_.Swing = on ? kSamsungAcSwingH : kSamsungAcSwingOff;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Clean setting of the A/C.
|
||||
/// Get the Beep toggle setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSamsungAc::getBeep(void) const { return _.BeepToggle; }
|
||||
|
||||
/// Set the Beep toggle setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRSamsungAc::setBeep(const bool on) { _.BeepToggle = on; }
|
||||
|
||||
/// Get the Clean toggle setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSamsungAc::getClean(void) const {
|
||||
return _.Clean10 && _.Clean11;
|
||||
return _.CleanToggle10 && _.CleanToggle11;
|
||||
}
|
||||
|
||||
/// Set the Clean setting of the A/C.
|
||||
/// Set the Clean toggle setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRSamsungAc::setClean(const bool on) {
|
||||
_.Clean10 = on;
|
||||
_.Clean11 = on;
|
||||
_.CleanToggle10 = on;
|
||||
_.CleanToggle11 = on;
|
||||
}
|
||||
|
||||
/// Get the Quiet setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSamsungAc::getQuiet(void) const {
|
||||
return !_.Quiet1 && _.Quiet5;
|
||||
}
|
||||
bool IRSamsungAc::getQuiet(void) const { return _.Quiet; }
|
||||
|
||||
/// Set the Quiet setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRSamsungAc::setQuiet(const bool on) {
|
||||
_.Quiet1 = !on; // Cleared when on.
|
||||
_.Quiet5 = on;
|
||||
_.Quiet = on;
|
||||
if (on) {
|
||||
// Quiet mode seems to set fan speed to auto.
|
||||
setFan(kSamsungAcFanAuto);
|
||||
|
@ -584,25 +630,20 @@ void IRSamsungAc::setQuiet(const bool on) {
|
|||
/// Get the Powerful (Turbo) setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSamsungAc::getPowerful(void) const {
|
||||
return !(_.Powerful8 & kSamsungAcPowerfulMask8) &&
|
||||
(_.Powerful10 == kSamsungAcPowerful10On) &&
|
||||
return (_.FanSpecial == kSamsungAcPowerfulOn) &&
|
||||
(_.Fan == kSamsungAcFanTurbo);
|
||||
}
|
||||
|
||||
/// Set the Powerful (Turbo) setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRSamsungAc::setPowerful(const bool on) {
|
||||
uint8_t off_value = getBreeze() ? kSamsungAcBreezeOn : 0b000;
|
||||
_.Powerful10 = (on ? kSamsungAcPowerful10On : off_value);
|
||||
uint8_t off_value = (getBreeze() || getEcono()) ? _.FanSpecial
|
||||
: kSamsungAcFanSpecialOff;
|
||||
_.FanSpecial = (on ? kSamsungAcPowerfulOn : off_value);
|
||||
if (on) {
|
||||
_.Powerful8 &= ~kSamsungAcPowerfulMask8; // Bit needs to be cleared.
|
||||
// Powerful mode sets fan speed to Turbo.
|
||||
setFan(kSamsungAcFanTurbo);
|
||||
setQuiet(false); // Powerful 'on' is mutually exclusive to Quiet.
|
||||
} else {
|
||||
_.Powerful8 |= kSamsungAcPowerfulMask8; // Bit needs to be set.
|
||||
// Turning off Powerful mode sets fan speed to Auto if we were in Turbo mode
|
||||
if (_.Fan == kSamsungAcFanTurbo) setFan(kSamsungAcFanAuto);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -610,7 +651,7 @@ void IRSamsungAc::setPowerful(const bool on) {
|
|||
/// @return true, the setting is on. false, the setting is off.
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1062
|
||||
bool IRSamsungAc::getBreeze(void) const {
|
||||
return (_.Breeze == kSamsungAcBreezeOn) &&
|
||||
return (_.FanSpecial == kSamsungAcBreezeOn) &&
|
||||
(_.Fan == kSamsungAcFanAuto && !getSwing());
|
||||
}
|
||||
|
||||
|
@ -618,36 +659,155 @@ bool IRSamsungAc::getBreeze(void) const {
|
|||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1062
|
||||
void IRSamsungAc::setBreeze(const bool on) {
|
||||
uint8_t off_value = getPowerful() ? kSamsungAcPowerful10On : 0b000;
|
||||
_.Breeze = (on ? kSamsungAcBreezeOn : off_value);
|
||||
const uint8_t off_value = (getPowerful() ||
|
||||
getEcono()) ? _.FanSpecial
|
||||
: kSamsungAcFanSpecialOff;
|
||||
_.FanSpecial = (on ? kSamsungAcBreezeOn : off_value);
|
||||
if (on) {
|
||||
setFan(kSamsungAcFanAuto);
|
||||
setSwing(false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current Economy (Eco) setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSamsungAc::getEcono(void) const {
|
||||
return (_.FanSpecial == kSamsungAcEconoOn) &&
|
||||
(_.Fan == kSamsungAcFanAuto && getSwing());
|
||||
}
|
||||
|
||||
/// Set the current Economy (Eco) setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRSamsungAc::setEcono(const bool on) {
|
||||
const uint8_t off_value = (getBreeze() ||
|
||||
getPowerful()) ? _.FanSpecial
|
||||
: kSamsungAcFanSpecialOff;
|
||||
_.FanSpecial = (on ? kSamsungAcEconoOn : off_value);
|
||||
if (on) {
|
||||
setFan(kSamsungAcFanAuto);
|
||||
setSwing(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the Display (Light/LED) setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSamsungAc::getDisplay(void) const {
|
||||
return _.Display;
|
||||
}
|
||||
bool IRSamsungAc::getDisplay(void) const { return _.Display; }
|
||||
|
||||
/// Set the Display (Light/LED) setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRSamsungAc::setDisplay(const bool on) {
|
||||
_.Display = on;
|
||||
}
|
||||
void IRSamsungAc::setDisplay(const bool on) { _.Display = on; }
|
||||
|
||||
/// Get the Ion (Filter) setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSamsungAc::getIon(void) const {
|
||||
return _.Ion;
|
||||
}
|
||||
bool IRSamsungAc::getIon(void) const { return _.Ion; }
|
||||
|
||||
/// Set the Ion (Filter) setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRSamsungAc::setIon(const bool on) {
|
||||
_.Ion = on;
|
||||
void IRSamsungAc::setIon(const bool on) { _.Ion = on; }
|
||||
|
||||
/// Get the On Timer setting of the A/C from a raw extended state.
|
||||
/// @return The Nr. of minutes the On Timer is set for.
|
||||
uint16_t IRSamsungAc::_getOnTimer(void) const {
|
||||
if (_.OnTimeDay) return 24 * 60;
|
||||
return (_.OnTimeHrs2 * 2 + _.OnTimeHrs1) * 60 + _.OnTimeMins * 10;
|
||||
}
|
||||
|
||||
/// Set the current On Timer value of the A/C into the raw extended state.
|
||||
void IRSamsungAc::_setOnTimer(void) {
|
||||
_.OnTimerEnable = _OnTimerEnable = (_OnTimer > 0);
|
||||
_.OnTimeDay = (_OnTimer >= 24 * 60);
|
||||
if (_.OnTimeDay) {
|
||||
_.OnTimeHrs2 = _.OnTimeHrs1 = _.OnTimeMins = 0;
|
||||
return;
|
||||
}
|
||||
_.OnTimeMins = (_OnTimer % 60) / 10;
|
||||
const uint8_t hours = _OnTimer / 60;
|
||||
_.OnTimeHrs1 = hours & 0b1;
|
||||
_.OnTimeHrs2 = hours >> 1;
|
||||
}
|
||||
|
||||
/// Get the Off Timer setting of the A/C from a raw extended state.
|
||||
/// @return The Nr. of minutes the Off Timer is set for.
|
||||
uint16_t IRSamsungAc::_getOffTimer(void) const {
|
||||
if (_.OffTimeDay) return 24 * 60;
|
||||
return (_.OffTimeHrs2 * 2 + _.OffTimeHrs1) * 60 + _.OffTimeMins * 10;
|
||||
}
|
||||
|
||||
/// Set the current Off Timer value of the A/C into the raw extended state.
|
||||
void IRSamsungAc::_setOffTimer(void) {
|
||||
_.OffTimerEnable = _OffTimerEnable = (_OffTimer > 0);
|
||||
_.OffTimeDay = (_OffTimer >= 24 * 60);
|
||||
if (_.OffTimeDay) {
|
||||
_.OffTimeHrs2 = _.OffTimeHrs1 = _.OffTimeMins = 0;
|
||||
return;
|
||||
}
|
||||
_.OffTimeMins = (_OffTimer % 60) / 10;
|
||||
const uint8_t hours = _OffTimer / 60;
|
||||
_.OffTimeHrs1 = hours & 0b1;
|
||||
_.OffTimeHrs2 = hours >> 1;
|
||||
}
|
||||
|
||||
// Set the current Sleep Timer value of the A/C into the raw extended state.
|
||||
void IRSamsungAc::_setSleepTimer(void) {
|
||||
_setOffTimer();
|
||||
// The Sleep mode/timer should only be engaged if an off time has been set.
|
||||
_.Sleep5 = _Sleep && _OffTimerEnable;
|
||||
_.Sleep12 = _.Sleep5;
|
||||
}
|
||||
|
||||
/// Get the On Timer setting of the A/C.
|
||||
/// @return The Nr. of minutes the On Timer is set for.
|
||||
uint16_t IRSamsungAc::getOnTimer(void) const { return _OnTimer; }
|
||||
|
||||
/// 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 IRSamsungAc::getOffTimer(void) const {
|
||||
return _Sleep ? 0 : _OffTimer;
|
||||
}
|
||||
|
||||
/// Get the Sleep 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 IRSamsungAc::getSleepTimer(void) const {
|
||||
return _Sleep ? _OffTimer : 0;
|
||||
}
|
||||
|
||||
#define TIMER_RESOLUTION(mins) \
|
||||
(((std::min((mins), (uint16_t)(24 * 60))) / 10) * 10)
|
||||
|
||||
/// Set the On Timer value of the A/C.
|
||||
/// @param[in] nr_of_mins The number of minutes the timer should be.
|
||||
/// @note The timer time only has a resolution of 10 mins.
|
||||
/// @note Setting the On Timer active will cancel the Sleep timer/setting.
|
||||
void IRSamsungAc::setOnTimer(const uint16_t nr_of_mins) {
|
||||
// Limit to one day, and round down to nearest 10 min increment.
|
||||
_OnTimer = TIMER_RESOLUTION(nr_of_mins);
|
||||
_OnTimerEnable = _OnTimer > 0;
|
||||
if (_OnTimer) _Sleep = false;
|
||||
}
|
||||
|
||||
/// 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 IRSamsungAc::setOffTimer(const uint16_t nr_of_mins) {
|
||||
// Limit to one day, and round down to nearest 10 min increment.
|
||||
_OffTimer = TIMER_RESOLUTION(nr_of_mins);
|
||||
_OffTimerEnable = _OffTimer > 0;
|
||||
if (_OffTimer) _Sleep = false;
|
||||
}
|
||||
|
||||
/// Set the Sleep 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 Sleep timer acts as an Off timer, and cancels any On Timer.
|
||||
void IRSamsungAc::setSleepTimer(const uint16_t nr_of_mins) {
|
||||
// Limit to one day, and round down to nearest 10 min increment.
|
||||
_OffTimer = TIMER_RESOLUTION(nr_of_mins);
|
||||
if (_OffTimer) setOnTimer(0); // Clear the on timer if set.
|
||||
_Sleep = _OffTimer > 0;
|
||||
_OffTimerEnable = _Sleep;
|
||||
}
|
||||
|
||||
/// Convert a stdAc::opmode_t enum into its native mode.
|
||||
|
@ -714,18 +874,17 @@ stdAc::state_t IRSamsungAc::toCommon(void) const {
|
|||
result.celsius = true;
|
||||
result.degrees = getTemp();
|
||||
result.fanspeed = toCommonFanSpeed(_.Fan);
|
||||
result.swingv = getSwing() ? stdAc::swingv_t::kAuto :
|
||||
stdAc::swingv_t::kOff;
|
||||
result.swingv = getSwing() ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff;
|
||||
result.swingh = getSwingH() ? stdAc::swingh_t::kAuto : stdAc::swingh_t::kOff;
|
||||
result.quiet = getQuiet();
|
||||
result.turbo = getPowerful();
|
||||
result.econo = getEcono();
|
||||
result.clean = getClean();
|
||||
result.beep = _.Beep;
|
||||
result.beep = _.BeepToggle;
|
||||
result.light = _.Display;
|
||||
result.filter = _.Ion;
|
||||
result.sleep = _Sleep ? getSleepTimer() : -1;
|
||||
// Not supported.
|
||||
result.swingh = stdAc::swingh_t::kOff;
|
||||
result.econo = false;
|
||||
result.sleep = -1;
|
||||
result.clock = -1;
|
||||
return result;
|
||||
}
|
||||
|
@ -734,7 +893,7 @@ stdAc::state_t IRSamsungAc::toCommon(void) const {
|
|||
/// @return A human readable string.
|
||||
String IRSamsungAc::toString(void) const {
|
||||
String result = "";
|
||||
result.reserve(115); // Reserve some heap for the string to reduce fragging.
|
||||
result.reserve(230); // Reserve some heap for the string to reduce fragging.
|
||||
result += addBoolToString(getPower(), kPowerStr, false);
|
||||
result += addModeToString(_.Mode, kSamsungAcAuto, kSamsungAcCool,
|
||||
kSamsungAcHeat, kSamsungAcDry,
|
||||
|
@ -764,14 +923,21 @@ String IRSamsungAc::toString(void) const {
|
|||
break;
|
||||
}
|
||||
result += ')';
|
||||
result += addBoolToString(getSwing(), kSwingStr);
|
||||
result += addBoolToString(_.Beep, kBeepStr);
|
||||
result += addBoolToString(getClean(), kCleanStr);
|
||||
result += addBoolToString(getSwing(), kSwingVStr);
|
||||
result += addBoolToString(getSwingH(), kSwingHStr);
|
||||
result += addToggleToString(_.BeepToggle, kBeepStr);
|
||||
result += addToggleToString(getClean(), kCleanStr);
|
||||
result += addBoolToString(getQuiet(), kQuietStr);
|
||||
result += addBoolToString(getPowerful(), kPowerfulStr);
|
||||
result += addBoolToString(getEcono(), kEconoStr);
|
||||
result += addBoolToString(getBreeze(), kBreezeStr);
|
||||
result += addBoolToString(_.Display, kLightStr);
|
||||
result += addBoolToString(_.Ion, kIonStr);
|
||||
if (_OnTimerEnable)
|
||||
result += addLabeledString(minsToString(_OnTimer), kOnTimerStr);
|
||||
if (_OffTimerEnable)
|
||||
result += addLabeledString(minsToString(_OffTimer),
|
||||
_Sleep ? kSleepTimerStr : kOffTimerStr);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -811,9 +977,6 @@ bool IRrecv::decodeSamsungAC(decode_results *results, uint16_t offset,
|
|||
offset += used;
|
||||
}
|
||||
// Compliance
|
||||
// Is the signature correct?
|
||||
DPRINTLN("DEBUG: Checking signature.");
|
||||
if (results->state[0] != 0x02 || results->state[2] != 0x0F) return false;
|
||||
if (strict) {
|
||||
// Is the checksum valid?
|
||||
if (!IRSamsungAc::validChecksum(results->state, nbits / 8)) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2018 David Conran
|
||||
// Copyright 2018-2021 David Conran
|
||||
/// @file
|
||||
/// @brief Support for Samsung protocols.
|
||||
/// Samsung originally added from https://github.com/shirriff/Arduino-IRremote/
|
||||
|
@ -7,6 +7,7 @@
|
|||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1062
|
||||
/// @see http://elektrolab.wz.cz/katalog/samsung_protocol.pdf
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1538 (Checksum)
|
||||
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1277 (Timers)
|
||||
|
||||
// Supports:
|
||||
// Brand: Samsung, Model: UA55H6300 TV (SAMSUNG)
|
||||
|
@ -18,11 +19,13 @@
|
|||
// Brand: Samsung, Model: AH59-02692E Soundbar remote (SAMSUNG36)
|
||||
// Brand: Samsung, Model: HW-J551 Soundbar (SAMSUNG36)
|
||||
// Brand: Samsung, Model: AR09FSSDAWKNFA A/C (SAMSUNG_AC)
|
||||
// Brand: Samsung, Model: AR09HSFSBWKN A/C (SAMSUNG_AC)
|
||||
// Brand: Samsung, Model: AR12KSFPEWQNET A/C (SAMSUNG_AC)
|
||||
// Brand: Samsung, Model: AR12HSSDBWKNEU A/C (SAMSUNG_AC)
|
||||
// Brand: Samsung, Model: AR12NXCXAWKXEU A/C (SAMSUNG_AC)
|
||||
// Brand: Samsung, Model: AR09HSFSBWKN A/C (SAMSUNG_AC)
|
||||
// Brand: Samsung, Model: AR12TXEAAWKNEU A/C (SAMSUNG_AC)
|
||||
// Brand: Samsung, Model: DB93-14195A remote (SAMSUNG_AC)
|
||||
// Brand: Samsung, Model: DB96-24901C remote (SAMSUNG_AC)
|
||||
|
||||
#ifndef IR_SAMSUNG_H_
|
||||
#define IR_SAMSUNG_H_
|
||||
|
@ -41,41 +44,46 @@
|
|||
/// Native representation of a Samsung A/C message.
|
||||
union SamsungProtocol{
|
||||
uint8_t raw[kSamsungAcExtendedStateLength]; ///< State in code form.
|
||||
struct {
|
||||
struct { // Standard message map
|
||||
// Byte 0
|
||||
uint8_t :8;
|
||||
// Byte 1
|
||||
uint8_t :4;
|
||||
uint8_t Quiet1 :1;
|
||||
uint8_t Power1 :1;
|
||||
uint8_t :2;
|
||||
// Byte 2~4
|
||||
uint8_t pad0[3];
|
||||
uint8_t :4; // Sum1Lower
|
||||
// Byte 2
|
||||
uint8_t :4; // Sum1Upper
|
||||
uint8_t :4;
|
||||
// Byte 3
|
||||
uint8_t :8;
|
||||
// Byte 4
|
||||
uint8_t :8;
|
||||
// Byte 5
|
||||
uint8_t :5;
|
||||
uint8_t Quiet5 :1;
|
||||
uint8_t :4;
|
||||
uint8_t Sleep5 :1;
|
||||
uint8_t Quiet :1;
|
||||
uint8_t :2;
|
||||
// Byte 6
|
||||
uint8_t :4;
|
||||
uint8_t Power6 :2;
|
||||
uint8_t Power1 :2;
|
||||
uint8_t :2;
|
||||
// Byte 7
|
||||
uint8_t :8;
|
||||
// Byte 8
|
||||
uint8_t Powerful8 :8;
|
||||
// Byte 9
|
||||
uint8_t :4;
|
||||
uint8_t :4; // Sum2Lower
|
||||
// Byte 9
|
||||
uint8_t :4; // Sum1Upper
|
||||
uint8_t Swing :3;
|
||||
uint8_t :1;
|
||||
// Byte 10
|
||||
uint8_t :1;
|
||||
uint8_t Powerful10 :3;
|
||||
uint8_t FanSpecial :3; // Powerful, Breeze/WindFree, Econo
|
||||
uint8_t Display :1;
|
||||
uint8_t :2;
|
||||
uint8_t Clean10 :1;
|
||||
uint8_t CleanToggle10 :1;
|
||||
// Byte 11
|
||||
uint8_t Ion :1;
|
||||
uint8_t Clean11 :1;
|
||||
uint8_t CleanToggle11 :1;
|
||||
uint8_t :2;
|
||||
uint8_t Temp :4;
|
||||
// Byte 12
|
||||
|
@ -84,11 +92,13 @@ union SamsungProtocol{
|
|||
uint8_t Mode :3;
|
||||
uint8_t :1;
|
||||
// Byte 13
|
||||
uint8_t :2;
|
||||
uint8_t BeepToggle :1;
|
||||
uint8_t :1;
|
||||
uint8_t Beep :1;
|
||||
uint8_t :6;
|
||||
uint8_t Power2 :2;
|
||||
uint8_t :2;
|
||||
};
|
||||
struct {
|
||||
struct { // Extended message map
|
||||
// 1st Section
|
||||
// Byte 0
|
||||
uint8_t :8;
|
||||
|
@ -114,15 +124,22 @@ union SamsungProtocol{
|
|||
uint8_t Sum2Lower :4;
|
||||
// Byte 9
|
||||
uint8_t Sum2Upper :4;
|
||||
uint8_t :4;
|
||||
uint8_t OffTimeMins :3; // In units of 10's of mins
|
||||
uint8_t OffTimeHrs1 :1; // LSB of the number of hours.
|
||||
// Byte 10
|
||||
uint8_t :1;
|
||||
uint8_t Breeze :3; // WindFree
|
||||
uint8_t :4;
|
||||
uint8_t OffTimeHrs2 :4; // MSBs of the number of hours.
|
||||
uint8_t OnTimeMins :3; // In units of 10's of mins
|
||||
uint8_t OnTimeHrs1 :1; // LSB of the number of hours.
|
||||
// Byte 11
|
||||
uint8_t :8;
|
||||
uint8_t OnTimeHrs2 :4; // MSBs of the number of hours.
|
||||
uint8_t :4;
|
||||
// Byte 12
|
||||
uint8_t :8;
|
||||
uint8_t OffTimeDay :1;
|
||||
uint8_t OnTimerEnable :1;
|
||||
uint8_t OffTimerEnable :1;
|
||||
uint8_t Sleep12 :1;
|
||||
uint8_t OnTimeDay :1;
|
||||
uint8_t :3;
|
||||
// Byte 13
|
||||
uint8_t :8;
|
||||
// 3rd Section
|
||||
|
@ -146,11 +163,6 @@ union SamsungProtocol{
|
|||
};
|
||||
|
||||
// Constants
|
||||
const uint8_t kSamsungAcPowerfulMask8 = 0b01010000;
|
||||
const uint8_t kSamsungAcSwingMove = 0b010;
|
||||
const uint8_t kSamsungAcSwingStop = 0b111;
|
||||
const uint8_t kSamsungAcPowerful10On = 0b011;
|
||||
const uint8_t kSamsungAcBreezeOn = 0b101;
|
||||
const uint8_t kSamsungAcMinTemp = 16; // C Mask 0b11110000
|
||||
const uint8_t kSamsungAcMaxTemp = 30; // C Mask 0b11110000
|
||||
const uint8_t kSamsungAcAutoTemp = 25; // C Mask 0b11110000
|
||||
|
@ -174,12 +186,10 @@ class IRSamsungAc {
|
|||
public:
|
||||
explicit IRSamsungAc(const uint16_t pin, const bool inverted = false,
|
||||
const bool use_modulation = true);
|
||||
void stateReset(const bool forcepower = true, const bool initialPower = true);
|
||||
void stateReset(const bool extended = true, const bool initialPower = true);
|
||||
#if SEND_SAMSUNG_AC
|
||||
void send(const uint16_t repeat = kSamsungAcDefaultRepeat,
|
||||
const bool calcchecksum = true);
|
||||
void sendExtended(const uint16_t repeat = kSamsungAcDefaultRepeat,
|
||||
const bool calcchecksum = true);
|
||||
void send(const uint16_t repeat = kSamsungAcDefaultRepeat);
|
||||
void sendExtended(const uint16_t repeat = kSamsungAcDefaultRepeat);
|
||||
void sendOn(const uint16_t repeat = kSamsungAcDefaultRepeat);
|
||||
void sendOff(const uint16_t repeat = kSamsungAcDefaultRepeat);
|
||||
/// Run the calibration to calculate uSec timing offsets for this platform.
|
||||
|
@ -201,6 +211,8 @@ class IRSamsungAc {
|
|||
uint8_t getMode(void) const;
|
||||
void setSwing(const bool on);
|
||||
bool getSwing(void) const;
|
||||
void setSwingH(const bool on);
|
||||
bool getSwingH(void) const;
|
||||
void setBeep(const bool on);
|
||||
bool getBeep(void) const;
|
||||
void setClean(const bool on);
|
||||
|
@ -211,10 +223,18 @@ class IRSamsungAc {
|
|||
bool getPowerful(void) const;
|
||||
void setBreeze(const bool on);
|
||||
bool getBreeze(void) const;
|
||||
void setEcono(const bool on);
|
||||
bool getEcono(void) const;
|
||||
void setDisplay(const bool on);
|
||||
bool getDisplay(void) const;
|
||||
void setIon(const bool on);
|
||||
bool getIon(void) const;
|
||||
uint16_t getOnTimer(void) const;
|
||||
void setOnTimer(const uint16_t nr_of_mins);
|
||||
uint16_t getOffTimer(void) const;
|
||||
void setOffTimer(const uint16_t nr_of_mins);
|
||||
uint16_t getSleepTimer(void) const;
|
||||
void setSleepTimer(const uint16_t nr_of_mins);
|
||||
uint8_t* getRaw(void);
|
||||
void setRaw(const uint8_t new_code[],
|
||||
const uint16_t length = kSamsungAcStateLength);
|
||||
|
@ -238,9 +258,22 @@ class IRSamsungAc {
|
|||
/// @endcond
|
||||
#endif // UNIT_TEST
|
||||
SamsungProtocol _;
|
||||
bool _forcepower; ///< Hack to know when we need to send a special power mesg
|
||||
bool _forceextended; ///< Flag to know when we need to send an extended mesg.
|
||||
bool _lastsentpowerstate;
|
||||
bool _OnTimerEnable;
|
||||
bool _OffTimerEnable;
|
||||
bool _Sleep;
|
||||
bool _lastSleep;
|
||||
uint16_t _OnTimer;
|
||||
uint16_t _OffTimer;
|
||||
uint16_t _lastOnTimer;
|
||||
uint16_t _lastOffTimer;
|
||||
void checksum(void);
|
||||
uint16_t _getOnTimer(void) const;
|
||||
uint16_t _getOffTimer(void) const;
|
||||
void _setOnTimer(void);
|
||||
void _setOffTimer(void);
|
||||
void _setSleepTimer(void);
|
||||
};
|
||||
|
||||
#endif // IR_SAMSUNG_H_
|
||||
|
|
|
@ -45,7 +45,9 @@ using irutils::addIntToString;
|
|||
using irutils::addLabeledString;
|
||||
using irutils::addModeToString;
|
||||
using irutils::addModelToString;
|
||||
using irutils::addSwingVToString;
|
||||
using irutils::addTempToString;
|
||||
using irutils::addToggleToString;
|
||||
using irutils::minsToString;
|
||||
|
||||
// Also used by Denon protocol
|
||||
|
@ -544,24 +546,73 @@ void IRSharpAc::setTurbo(const bool on) {
|
|||
_.Special = kSharpAcSpecialTurbo;
|
||||
}
|
||||
|
||||
/// Get the Vertical Swing setting of the A/C.
|
||||
/// @return The position of the Vertical Swing setting.
|
||||
uint8_t IRSharpAc::getSwingV(void) const { return _.Swing; }
|
||||
|
||||
/// Set the Vertical Swing setting of the A/C.
|
||||
/// @note Some positions may not work on all models.
|
||||
/// @param[in] position The desired position/setting.
|
||||
/// @note `setSwingV(kSharpAcSwingVLowest)` will only allow the Lowest setting
|
||||
/// in Heat mode, it will default to `kSharpAcSwingVLow` otherwise.
|
||||
/// If you want to set this value in other modes e.g. Cool, you must
|
||||
/// use `setSwingV`s optional `force` parameter.
|
||||
/// @param[in] force Do we override the safety checks and just do it?
|
||||
void IRSharpAc::setSwingV(const uint8_t position, const bool force) {
|
||||
switch (position) {
|
||||
case kSharpAcSwingVCoanda:
|
||||
// Only allowed in Heat mode.
|
||||
if (!force && getMode() != kSharpAcHeat) {
|
||||
setSwingV(kSharpAcSwingVLow); // Use the next lowest setting.
|
||||
return;
|
||||
}
|
||||
// FALLTHRU
|
||||
case kSharpAcSwingVHigh:
|
||||
case kSharpAcSwingVMid:
|
||||
case kSharpAcSwingVLow:
|
||||
case kSharpAcSwingVToggle:
|
||||
case kSharpAcSwingVOff:
|
||||
case kSharpAcSwingVLast: // Technically valid, but we don't use it.
|
||||
// All expected non-positions set the special bits.
|
||||
_.Special = kSharpAcSpecialSwing;
|
||||
// FALLTHRU
|
||||
case kSharpAcSwingVIgnore:
|
||||
_.Swing = position;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a standard A/C vertical swing into its native setting.
|
||||
/// @param[in] position A stdAc::swingv_t position to convert.
|
||||
/// @return The equivalent native horizontal swing position.
|
||||
uint8_t IRSharpAc::convertSwingV(const stdAc::swingv_t position) {
|
||||
switch (position) {
|
||||
case stdAc::swingv_t::kHighest:
|
||||
case stdAc::swingv_t::kHigh: return kSharpAcSwingVHigh;
|
||||
case stdAc::swingv_t::kMiddle: return kSharpAcSwingVMid;
|
||||
case stdAc::swingv_t::kLow: return kSharpAcSwingVLow;
|
||||
case stdAc::swingv_t::kLowest: return kSharpAcSwingVCoanda;
|
||||
case stdAc::swingv_t::kAuto: return kSharpAcSwingVToggle;
|
||||
case stdAc::swingv_t::kOff: return kSharpAcSwingVOff;
|
||||
default: return kSharpAcSwingVIgnore;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the (vertical) Swing Toggle setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSharpAc::getSwingToggle(void) const {
|
||||
return _.Swing == kSharpAcSwingToggle;
|
||||
return getSwingV() == kSharpAcSwingVToggle;
|
||||
}
|
||||
|
||||
/// Set the (vertical) Swing Toggle setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRSharpAc::setSwingToggle(const bool on) {
|
||||
_.Swing = (on ? kSharpAcSwingToggle : kSharpAcSwingNoToggle);
|
||||
setSwingV(on ? kSharpAcSwingVToggle : kSharpAcSwingVIgnore);
|
||||
if (on) _.Special = kSharpAcSpecialSwing;
|
||||
}
|
||||
|
||||
/// Get the Ion (Filter) setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSharpAc::getIon(void) const {
|
||||
return _.Ion;
|
||||
}
|
||||
bool IRSharpAc::getIon(void) const { return _.Ion; }
|
||||
|
||||
/// Set the Ion (Filter) setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
|
@ -628,15 +679,11 @@ uint16_t IRSharpAc::getTimerTime(void) const {
|
|||
|
||||
/// Is the Timer enabled?
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRSharpAc::getTimerEnabled(void) const {
|
||||
return _.TimerEnabled;
|
||||
}
|
||||
bool IRSharpAc::getTimerEnabled(void) const { return _.TimerEnabled; }
|
||||
|
||||
/// Get the current timer type.
|
||||
/// @return true, It's an "On" timer. false, It's an "Off" timer.
|
||||
bool IRSharpAc::getTimerType(void) const {
|
||||
return _.TimerType;
|
||||
}
|
||||
bool IRSharpAc::getTimerType(void) const { return _.TimerType; }
|
||||
|
||||
/// Set or cancel the timer function.
|
||||
/// @param[in] enable Is the timer to be enabled (true) or canceled(false)?
|
||||
|
@ -765,10 +812,34 @@ stdAc::fanspeed_t IRSharpAc::toCommonFanSpeed(const uint8_t speed) const {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert a native vertical swing postion to it's common equivalent.
|
||||
/// @param[in] pos A native position to convert.
|
||||
/// @param[in] mode What operating mode are we in?
|
||||
/// @return The common vertical swing position.
|
||||
stdAc::swingv_t IRSharpAc::toCommonSwingV(const uint8_t pos,
|
||||
const stdAc::opmode_t mode) const {
|
||||
switch (pos) {
|
||||
case kSharpAcSwingVHigh: return stdAc::swingv_t::kHighest;
|
||||
case kSharpAcSwingVMid: return stdAc::swingv_t::kMiddle;
|
||||
case kSharpAcSwingVLow: return stdAc::swingv_t::kLow;
|
||||
case kSharpAcSwingVCoanda: // Coanda has mode dependent positionss
|
||||
switch (mode) {
|
||||
case stdAc::opmode_t::kCool: return stdAc::swingv_t::kHighest;
|
||||
case stdAc::opmode_t::kHeat: return stdAc::swingv_t::kLowest;
|
||||
default: return stdAc::swingv_t::kOff;
|
||||
}
|
||||
case kSharpAcSwingVToggle: return stdAc::swingv_t::kAuto;
|
||||
default: return stdAc::swingv_t::kOff;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 IRSharpAc::toCommon(void) const {
|
||||
stdAc::state_t IRSharpAc::toCommon(const stdAc::state_t *prev) const {
|
||||
stdAc::state_t result;
|
||||
// Start with the previous state if given it.
|
||||
if (prev != NULL) result = *prev;
|
||||
result.protocol = decode_type_t::SHARP_AC;
|
||||
result.model = getModel();
|
||||
result.power = getPower();
|
||||
|
@ -777,8 +848,8 @@ stdAc::state_t IRSharpAc::toCommon(void) const {
|
|||
result.degrees = getTemp();
|
||||
result.fanspeed = toCommonFanSpeed(_.Fan);
|
||||
result.turbo = getTurbo();
|
||||
result.swingv = getSwingToggle() ? stdAc::swingv_t::kAuto
|
||||
: stdAc::swingv_t::kOff;
|
||||
if (getSwingV() != kSharpAcSwingVIgnore)
|
||||
result.swingv = toCommonSwingV(getSwingV(), result.mode);
|
||||
result.filter = _.Ion;
|
||||
result.econo = getEconoToggle();
|
||||
result.light = getLightToggle();
|
||||
|
@ -797,14 +868,16 @@ stdAc::state_t IRSharpAc::toCommon(void) const {
|
|||
String IRSharpAc::toString(void) const {
|
||||
String result = "";
|
||||
const sharp_ac_remote_model_t model = getModel();
|
||||
result.reserve(160); // Reserve some heap for the string to reduce fragging.
|
||||
result.reserve(170); // Reserve some heap for the string to reduce fragging.
|
||||
result += addModelToString(decode_type_t::SHARP_AC, getModel(), false);
|
||||
|
||||
result += addLabeledString(isPowerSpecial() ? "-"
|
||||
: (getPower() ? kOnStr : kOffStr),
|
||||
result += addLabeledString(isPowerSpecial() ? String("-")
|
||||
: String(getPower() ? kOnStr
|
||||
: kOffStr),
|
||||
kPowerStr);
|
||||
const uint8_t mode = _.Mode;
|
||||
result += addModeToString(
|
||||
_.Mode,
|
||||
mode,
|
||||
// Make the value invalid if the model doesn't support an Auto mode.
|
||||
(model == sharp_ac_remote_model_t::A907) ? kSharpAcAuto : 255,
|
||||
kSharpAcCool, kSharpAcHeat, kSharpAcDry, kSharpAcFan);
|
||||
|
@ -821,18 +894,37 @@ String IRSharpAc::toString(void) const {
|
|||
kSharpAcFanAuto, kSharpAcFanAuto,
|
||||
kSharpAcFanMed);
|
||||
}
|
||||
if (getSwingV() == kSharpAcSwingVIgnore) {
|
||||
result += addIntToString(kSharpAcSwingVIgnore, kSwingVStr);
|
||||
result += kSpaceLBraceStr;
|
||||
result += kNAStr;
|
||||
result += ')';
|
||||
} else {
|
||||
result += addSwingVToString(
|
||||
getSwingV(), 0xFF,
|
||||
// Coanda means Highest when in Cool mode.
|
||||
(mode == kSharpAcCool) ? kSharpAcSwingVCoanda : kSharpAcSwingVToggle,
|
||||
kSharpAcSwingVHigh,
|
||||
0xFF, // Upper Middle is unused
|
||||
kSharpAcSwingVMid,
|
||||
0xFF, // Lower Middle is unused
|
||||
kSharpAcSwingVLow,
|
||||
kSharpAcSwingVCoanda,
|
||||
kSharpAcSwingVOff,
|
||||
// Below are unused.
|
||||
kSharpAcSwingVToggle,
|
||||
0xFF,
|
||||
0xFF);
|
||||
}
|
||||
result += addBoolToString(getTurbo(), kTurboStr);
|
||||
result += addBoolToString(getSwingToggle(), kSwingVToggleStr);
|
||||
result += addBoolToString(_.Ion, kIonStr);
|
||||
switch (model) {
|
||||
case sharp_ac_remote_model_t::A705:
|
||||
case sharp_ac_remote_model_t::A903:
|
||||
result += addLabeledString(getLightToggle() ? kToggleStr : "-",
|
||||
kLightStr);
|
||||
result += addToggleToString(getLightToggle(), kLightStr);
|
||||
break;
|
||||
default:
|
||||
result += addLabeledString(getEconoToggle() ? kToggleStr : "-",
|
||||
kEconoStr);
|
||||
result += addToggleToString(getEconoToggle(), kEconoStr);
|
||||
}
|
||||
result += addBoolToString(_.Clean, kCleanStr);
|
||||
if (_.TimerEnabled)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
// Brand: Sharp, Model: AY-ZP40KR A/C (A907)
|
||||
// Brand: Sharp, Model: AH-AxSAY A/C (A907)
|
||||
// Brand: Sharp, Model: CRMC-A907 JBEZ remote (A907)
|
||||
// Brand: Sharp, Model: CRMC-A950 JBEZ (A907)
|
||||
// Brand: Sharp, Model: AH-PR13-GL A/C (A903)
|
||||
// Brand: Sharp, Model: CRMC-A903JBEZ remote (A903)
|
||||
// Brand: Sharp, Model: AH-XP10NRY A/C (A903)
|
||||
|
@ -121,8 +122,23 @@ const uint8_t kSharpAcTimerHoursMax = 0b1100; // 12
|
|||
const uint8_t kSharpAcOffTimerType = 0b0;
|
||||
const uint8_t kSharpAcOnTimerType = 0b1;
|
||||
|
||||
const uint8_t kSharpAcSwingToggle = 0b111;
|
||||
const uint8_t kSharpAcSwingNoToggle = 0b000;
|
||||
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/discussions/1590#discussioncomment-1260213
|
||||
const uint8_t kSharpAcSwingVIgnore = 0b000; // Don't change the swing setting.
|
||||
const uint8_t kSharpAcSwingVHigh = 0b001; // 0° down. Similar to Cool Coanda.
|
||||
const uint8_t kSharpAcSwingVOff = 0b010; // Stop & Go to last fixed pos.
|
||||
const uint8_t kSharpAcSwingVMid = 0b011; // 30° down
|
||||
const uint8_t kSharpAcSwingVLow = 0b100; // 45° down
|
||||
const uint8_t kSharpAcSwingVLast = 0b101; // Same as kSharpAcSwingVOff.
|
||||
// Toggles between last fixed pos & either 75° down (Heat) or 0° down (Cool)
|
||||
// i.e. alternate between last pos <-> 75° down if in Heat mode, AND
|
||||
// alternate between last pos <-> 0° down if in Cool mode.
|
||||
// Note: `setSwingV(kSharpAcSwingVLowest)` will only allow the Lowest setting in
|
||||
// Heat mode, it will default to `kSharpAcSwingVLow` otherwise.
|
||||
// If you want to set this value in other modes e.g. Cool, you must
|
||||
// use `setSwingV`s optional `force` parameter.
|
||||
const uint8_t kSharpAcSwingVLowest = 0b110;
|
||||
const uint8_t kSharpAcSwingVCoanda = kSharpAcSwingVLowest;
|
||||
const uint8_t kSharpAcSwingVToggle = 0b111; // Toggle Constant swinging on/off.
|
||||
|
||||
const uint8_t kSharpAcSpecialPower = 0x00;
|
||||
const uint8_t kSharpAcSpecialTurbo = 0x01;
|
||||
|
@ -166,6 +182,8 @@ class IRSharpAc {
|
|||
void setTurbo(const bool on);
|
||||
bool getSwingToggle(void) const;
|
||||
void setSwingToggle(const bool on);
|
||||
uint8_t getSwingV(void) const;
|
||||
void setSwingV(const uint8_t position, const bool force = false);
|
||||
bool getIon(void) const;
|
||||
void setIon(const bool on);
|
||||
bool getEconoToggle(void) const;
|
||||
|
@ -187,9 +205,13 @@ class IRSharpAc {
|
|||
static uint8_t convertFan(const stdAc::fanspeed_t speed,
|
||||
const sharp_ac_remote_model_t model =
|
||||
sharp_ac_remote_model_t::A907);
|
||||
static uint8_t convertSwingV(const stdAc::swingv_t position);
|
||||
stdAc::opmode_t toCommonMode(const uint8_t mode) const;
|
||||
stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed) const;
|
||||
stdAc::state_t toCommon(void) const;
|
||||
stdAc::swingv_t toCommonSwingV(
|
||||
const uint8_t pos,
|
||||
const stdAc::opmode_t mode = stdAc::opmode_t::kHeat) const;
|
||||
stdAc::state_t toCommon(const stdAc::state_t *prev = NULL) const;
|
||||
String toString(void) const;
|
||||
#ifndef UNIT_TEST
|
||||
|
||||
|
|
|
@ -18,6 +18,15 @@
|
|||
// Brand: Satellite Electronic, Model: ID6 Remote
|
||||
// Brand: Satellite Electronic, Model: JY199I Fan driver
|
||||
// Brand: Satellite Electronic, Model: JY199I-L Fan driver
|
||||
// Brand: SilverCrest, Model: SSVS 85 A1 Fan
|
||||
|
||||
// Known Codes:
|
||||
// SilverCrest SSVS 85 A1 Fan:
|
||||
// 0x581 - On/Off
|
||||
// 0x582 - Speed
|
||||
// 0x584 - Mist
|
||||
// 0x588 - Timer
|
||||
// 0x590 - OSC
|
||||
|
||||
#include <algorithm>
|
||||
#include "IRrecv.h"
|
||||
|
|
|
@ -15,12 +15,18 @@
|
|||
|
||||
// Constants
|
||||
|
||||
const uint8_t kTcl112AcTimerResolution = 20; // Minutes
|
||||
const uint16_t kTcl112AcTimerMax = 720; // Minutes (12 hrs)
|
||||
|
||||
using irutils::addBoolToString;
|
||||
using irutils::addFanToString;
|
||||
using irutils::addIntToString;
|
||||
using irutils::addLabeledString;
|
||||
using irutils::addModeToString;
|
||||
using irutils::addModelToString;
|
||||
using irutils::addSwingVToString;
|
||||
using irutils::addTempFloatToString;
|
||||
using irutils::minsToString;
|
||||
|
||||
#if SEND_TCL112AC
|
||||
/// Send a TCL 112-bit A/C message.
|
||||
|
@ -71,6 +77,8 @@ void IRTcl112Ac::send(const uint16_t repeat) {
|
|||
_quiet_prev = _quiet;
|
||||
// Restore the old state.
|
||||
setRaw(save);
|
||||
// Make sure it looks like a normal TCL mesg if needed.
|
||||
if (_.MsgType == kTcl112AcNormal) _.isTcl = true;
|
||||
}
|
||||
// Send the normal (type 1) state.
|
||||
_irsend.sendTcl112Ac(getRaw(), kTcl112AcStateLength, repeat);
|
||||
|
@ -109,6 +117,17 @@ bool IRTcl112Ac::validChecksum(uint8_t state[], const uint16_t length) {
|
|||
return (length > 1 && state[length - 1] == calcChecksum(state, length));
|
||||
}
|
||||
|
||||
/// Check the supplied state looks like a TCL112AC message.
|
||||
/// @param[in] state The array to verify the checksum of.
|
||||
/// @note Assumes the state is the correct size.
|
||||
/// @return true, if the state looks like a TCL112AC message. Otherwise, false.
|
||||
/// @warning This is just a guess.
|
||||
bool IRTcl112Ac::isTcl(const uint8_t state[]) {
|
||||
Tcl112Protocol mesg;
|
||||
std::memcpy(mesg.raw, state, kTcl112AcStateLength);
|
||||
return (mesg.MsgType != kTcl112AcNormal) || mesg.isTcl;
|
||||
}
|
||||
|
||||
/// Reset the internal state of the emulation. (On, Cool, 24C)
|
||||
void IRTcl112Ac::stateReset(void) {
|
||||
// A known good state. (On, Cool, 24C)
|
||||
|
@ -121,6 +140,19 @@ void IRTcl112Ac::stateReset(void) {
|
|||
_quiet_explictly_set = false;
|
||||
}
|
||||
|
||||
/// Get/Detect the model of the A/C.
|
||||
/// @return The enum of the compatible model.
|
||||
tcl_ac_remote_model_t IRTcl112Ac::getModel(void) const {
|
||||
return isTcl(_.raw) ? tcl_ac_remote_model_t::TAC09CHSD
|
||||
: tcl_ac_remote_model_t::GZ055BE1;
|
||||
}
|
||||
|
||||
/// Set the model of the A/C to emulate.
|
||||
/// @param[in] model The enum of the appropriate model.
|
||||
void IRTcl112Ac::setModel(const tcl_ac_remote_model_t model) {
|
||||
_.isTcl = (model != tcl_ac_remote_model_t::GZ055BE1);
|
||||
}
|
||||
|
||||
/// Get a PTR to the internal state/code for this protocol.
|
||||
/// @return PTR to a code for this protocol based on the current internal state.
|
||||
uint8_t* IRTcl112Ac::getRaw(void) {
|
||||
|
@ -203,6 +235,7 @@ float IRTcl112Ac::getTemp(void) const {
|
|||
void IRTcl112Ac::setFan(const uint8_t speed) {
|
||||
switch (speed) {
|
||||
case kTcl112AcFanAuto:
|
||||
case kTcl112AcFanMin:
|
||||
case kTcl112AcFanLow:
|
||||
case kTcl112AcFanMed:
|
||||
case kTcl112AcFanHigh:
|
||||
|
@ -250,14 +283,23 @@ void IRTcl112Ac::setSwingHorizontal(const bool on) { _.SwingH = on; }
|
|||
bool IRTcl112Ac::getSwingHorizontal(void) const { return _.SwingH; }
|
||||
|
||||
/// Set the vertical swing setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
void IRTcl112Ac::setSwingVertical(const bool on) {
|
||||
_.SwingV = (on ? kTcl112AcSwingVOn : kTcl112AcSwingVOff);
|
||||
/// @param[in] setting The value of the desired setting.
|
||||
void IRTcl112Ac::setSwingVertical(const uint8_t setting) {
|
||||
switch (setting) {
|
||||
case kTcl112AcSwingVOff:
|
||||
case kTcl112AcSwingVHighest:
|
||||
case kTcl112AcSwingVHigh:
|
||||
case kTcl112AcSwingVMiddle:
|
||||
case kTcl112AcSwingVLow:
|
||||
case kTcl112AcSwingVLowest:
|
||||
case kTcl112AcSwingVOn:
|
||||
_.SwingV = setting;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the vertical swing setting of the A/C.
|
||||
/// @return true, the setting is on. false, the setting is off.
|
||||
bool IRTcl112Ac::getSwingVertical(void) const { return _.SwingV; }
|
||||
/// @return The current setting.
|
||||
uint8_t IRTcl112Ac::getSwingVertical(void) const { return _.SwingV; }
|
||||
|
||||
/// Set the Turbo setting of the A/C.
|
||||
/// @param[in] on true, the setting is on. false, the setting is off.
|
||||
|
@ -291,6 +333,36 @@ bool IRTcl112Ac::getQuiet(const bool def) const {
|
|||
return _quiet_explictly_set ? _quiet : def;
|
||||
}
|
||||
|
||||
/// Get how long the On Timer is set for, in minutes.
|
||||
/// @return The time in nr of minutes.
|
||||
uint16_t IRTcl112Ac::getOnTimer(void) const {
|
||||
return _.OnTimer * kTcl112AcTimerResolution;
|
||||
}
|
||||
|
||||
/// Set or cancel the On Timer function.
|
||||
/// @param[in] mins Nr. of minutes the timer is to be set to.
|
||||
/// @note Rounds down to 20 min increments. (max: 720 mins (12h), 0 is Off)
|
||||
void IRTcl112Ac::setOnTimer(const uint16_t mins) {
|
||||
_.OnTimer = std::min(mins, kTcl112AcTimerMax) / kTcl112AcTimerResolution;
|
||||
_.OnTimerEnabled = _.OnTimer > 0;
|
||||
_.TimerIndicator = _.OnTimerEnabled || _.OffTimerEnabled;
|
||||
}
|
||||
|
||||
/// Get how long the Off Timer is set for, in minutes.
|
||||
/// @return The time in nr of minutes.
|
||||
uint16_t IRTcl112Ac::getOffTimer(void) const {
|
||||
return _.OffTimer * kTcl112AcTimerResolution;
|
||||
}
|
||||
|
||||
/// Set or cancel the Off Timer function.
|
||||
/// @param[in] mins Nr. of minutes the timer is to be set to.
|
||||
/// @note Rounds down to 20 min increments. (max: 720 mins (12h), 0 is Off)
|
||||
void IRTcl112Ac::setOffTimer(const uint16_t mins) {
|
||||
_.OffTimer = std::min(mins, kTcl112AcTimerMax) / kTcl112AcTimerResolution;
|
||||
_.OffTimerEnabled = _.OffTimer > 0;
|
||||
_.TimerIndicator = _.OnTimerEnabled || _.OffTimerEnabled;
|
||||
}
|
||||
|
||||
/// 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.
|
||||
|
@ -309,7 +381,7 @@ uint8_t IRTcl112Ac::convertMode(const stdAc::opmode_t mode) {
|
|||
/// @return The native equivalent of the enum.
|
||||
uint8_t IRTcl112Ac::convertFan(const stdAc::fanspeed_t speed) {
|
||||
switch (speed) {
|
||||
case stdAc::fanspeed_t::kMin:
|
||||
case stdAc::fanspeed_t::kMin: return kTcl112AcFanMin;
|
||||
case stdAc::fanspeed_t::kLow: return kTcl112AcFanLow;
|
||||
case stdAc::fanspeed_t::kMedium: return kTcl112AcFanMed;
|
||||
case stdAc::fanspeed_t::kHigh:
|
||||
|
@ -331,6 +403,21 @@ stdAc::opmode_t IRTcl112Ac::toCommonMode(const uint8_t mode) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Convert a stdAc::swingv_t enum into it's native setting.
|
||||
/// @param[in] position The enum to be converted.
|
||||
/// @return The native equivalent of the enum.
|
||||
uint8_t IRTcl112Ac::convertSwingV(const stdAc::swingv_t position) {
|
||||
switch (position) {
|
||||
case stdAc::swingv_t::kOff: return kTcl112AcSwingVOff;
|
||||
case stdAc::swingv_t::kHighest: return kTcl112AcSwingVHighest;
|
||||
case stdAc::swingv_t::kHigh: return kTcl112AcSwingVHigh;
|
||||
case stdAc::swingv_t::kMiddle: return kTcl112AcSwingVMiddle;
|
||||
case stdAc::swingv_t::kLow: return kTcl112AcSwingVLow;
|
||||
case stdAc::swingv_t::kLowest: return kTcl112AcSwingVLowest;
|
||||
default: return kTcl112AcSwingVOn;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a native fan speed into its stdAc equivalent.
|
||||
/// @param[in] spd The native setting to be converted.
|
||||
/// @return The stdAc equivalent of the native setting.
|
||||
|
@ -338,11 +425,21 @@ stdAc::fanspeed_t IRTcl112Ac::toCommonFanSpeed(const uint8_t spd) {
|
|||
switch (spd) {
|
||||
case kTcl112AcFanHigh: return stdAc::fanspeed_t::kMax;
|
||||
case kTcl112AcFanMed: return stdAc::fanspeed_t::kMedium;
|
||||
case kTcl112AcFanLow: return stdAc::fanspeed_t::kMin;
|
||||
case kTcl112AcFanLow: return stdAc::fanspeed_t::kLow;
|
||||
case kTcl112AcFanMin: return stdAc::fanspeed_t::kMin;
|
||||
default: return stdAc::fanspeed_t::kAuto;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a native vertical swing postion to it's common equivalent.
|
||||
/// @param[in] setting A native position to convert.
|
||||
/// @return The common vertical swing position.
|
||||
stdAc::swingv_t IRTcl112Ac::toCommonSwingV(const uint8_t setting) {
|
||||
switch (setting) {
|
||||
case kTcl112AcSwingVOff: return stdAc::swingv_t::kOff;
|
||||
default: return stdAc::swingv_t::kAuto;
|
||||
}
|
||||
}
|
||||
/// Convert the current internal state into its stdAc::state_t equivalent.
|
||||
/// @param[in] prev Ptr to the previous state if required.
|
||||
/// @return The stdAc equivalent of the native settings.
|
||||
|
@ -351,7 +448,7 @@ stdAc::state_t IRTcl112Ac::toCommon(const stdAc::state_t *prev) const {
|
|||
// Start with the previous state if given it.
|
||||
if (prev != NULL) result = *prev;
|
||||
result.protocol = decode_type_t::TCL112AC;
|
||||
result.model = -1; // Not supported.
|
||||
result.model = getModel();
|
||||
result.quiet = getQuiet(result.quiet);
|
||||
// The rest only get updated if it is a "normal" message.
|
||||
if (_.MsgType == kTcl112AcNormal) {
|
||||
|
@ -360,7 +457,7 @@ stdAc::state_t IRTcl112Ac::toCommon(const stdAc::state_t *prev) const {
|
|||
result.celsius = true;
|
||||
result.degrees = getTemp();
|
||||
result.fanspeed = toCommonFanSpeed(_.Fan);
|
||||
result.swingv = _.SwingV ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff;
|
||||
result.swingv = toCommonSwingV(_.SwingV);
|
||||
result.swingh = _.SwingH ? stdAc::swingh_t::kAuto : stdAc::swingh_t::kOff;
|
||||
result.turbo = _.Turbo;
|
||||
result.filter = _.Health;
|
||||
|
@ -379,8 +476,10 @@ stdAc::state_t IRTcl112Ac::toCommon(const stdAc::state_t *prev) const {
|
|||
/// @return A human readable string.
|
||||
String IRTcl112Ac::toString(void) const {
|
||||
String result = "";
|
||||
result.reserve(150); // Reserve some heap for the string to reduce fragging.
|
||||
result += addIntToString(_.MsgType, D_STR_TYPE, false);
|
||||
result.reserve(220); // Reserve some heap for the string to reduce fragging.
|
||||
tcl_ac_remote_model_t model = getModel();
|
||||
result += addModelToString(decode_type_t::TCL112AC, model, false);
|
||||
result += addIntToString(_.MsgType, D_STR_TYPE);
|
||||
switch (_.MsgType) {
|
||||
case kTcl112AcNormal:
|
||||
result += addBoolToString(_.Power, kPowerStr);
|
||||
|
@ -388,14 +487,32 @@ String IRTcl112Ac::toString(void) const {
|
|||
kTcl112AcHeat, kTcl112AcDry, kTcl112AcFan);
|
||||
result += addTempFloatToString(getTemp());
|
||||
result += addFanToString(_.Fan, kTcl112AcFanHigh, kTcl112AcFanLow,
|
||||
kTcl112AcFanAuto, kTcl112AcFanAuto,
|
||||
kTcl112AcFanAuto, kTcl112AcFanMin,
|
||||
kTcl112AcFanMed);
|
||||
result += addSwingVToString(_.SwingV, kTcl112AcSwingVOff,
|
||||
kTcl112AcSwingVHighest,
|
||||
kTcl112AcSwingVHigh,
|
||||
0xFF, // unused
|
||||
kTcl112AcSwingVMiddle,
|
||||
0xFF, // unused
|
||||
kTcl112AcSwingVLow,
|
||||
kTcl112AcSwingVLowest,
|
||||
kTcl112AcSwingVOff,
|
||||
kTcl112AcSwingVOn, // Swing
|
||||
0xFF, 0xFF); // Both Unused
|
||||
if (model != tcl_ac_remote_model_t::GZ055BE1) {
|
||||
result += addBoolToString(_.SwingH, kSwingHStr);
|
||||
result += addBoolToString(_.Econo, kEconoStr);
|
||||
result += addBoolToString(_.Health, kHealthStr);
|
||||
result += addBoolToString(_.Turbo, kTurboStr);
|
||||
result += addBoolToString(_.SwingH, kSwingHStr);
|
||||
result += addBoolToString(_.SwingV, kSwingVStr);
|
||||
result += addBoolToString(getLight(), kLightStr);
|
||||
}
|
||||
result += addLabeledString(
|
||||
_.OnTimerEnabled ? minsToString(getOnTimer()) : kOffStr,
|
||||
kOnTimerStr);
|
||||
result += addLabeledString(
|
||||
_.OffTimerEnabled ? minsToString(getOffTimer()) : kOffStr,
|
||||
kOffTimerStr);
|
||||
break;
|
||||
case kTcl112AcSpecial:
|
||||
result += addBoolToString(_.Quiet, kQuietStr);
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
/// @brief Support for TCL protocols.
|
||||
|
||||
// Supports:
|
||||
// Brand: Leberg, Model: LBS-TOR07 A/C
|
||||
// Brand: TCL, Model: TAC-09CHSD/XA31I A/C
|
||||
// Brand: Leberg, Model: LBS-TOR07 A/C (TAC09CHSD)
|
||||
// Brand: TCL, Model: TAC-09CHSD/XA31I A/C (TAC09CHSD)
|
||||
// Brand: Teknopoint, Model: Allegro SSA-09H A/C (GZ055BE1)
|
||||
// Brand: Teknopoint, Model: GZ-055B-E1 remote (GZ055BE1)
|
||||
|
||||
#ifndef IR_TCL_H_
|
||||
#define IR_TCL_H_
|
||||
|
@ -25,7 +27,9 @@ union Tcl112Protocol{
|
|||
uint8_t raw[kTcl112AcStateLength]; ///< The State in IR code form.
|
||||
struct {
|
||||
// Byte 0~2
|
||||
uint8_t pad0[3];
|
||||
uint8_t :8;
|
||||
uint8_t :8;
|
||||
uint8_t :8;
|
||||
// Byte 3
|
||||
uint8_t MsgType :2;
|
||||
uint8_t :6;
|
||||
|
@ -34,7 +38,8 @@ union Tcl112Protocol{
|
|||
// Byte 5
|
||||
uint8_t :2;
|
||||
uint8_t Power :1;
|
||||
uint8_t :2;
|
||||
uint8_t OffTimerEnabled :1;
|
||||
uint8_t OnTimerEnabled :1;
|
||||
uint8_t Quiet :1;
|
||||
uint8_t Light :1;
|
||||
uint8_t Econo :1;
|
||||
|
@ -49,15 +54,25 @@ union Tcl112Protocol{
|
|||
// Byte 8
|
||||
uint8_t Fan :3;
|
||||
uint8_t SwingV :3;
|
||||
uint8_t :2;
|
||||
// Byte 9~11
|
||||
uint8_t pad1[3];
|
||||
uint8_t TimerIndicator :1;
|
||||
uint8_t :1;
|
||||
// Byte 9
|
||||
uint8_t :1; // 0
|
||||
uint8_t OffTimer :6;
|
||||
uint8_t :1; // 0
|
||||
// Byte 10
|
||||
uint8_t :1; // 0
|
||||
uint8_t OnTimer :6;
|
||||
uint8_t :1; // 0
|
||||
// Byte 11
|
||||
uint8_t :8; // 00000000
|
||||
// Byte 12
|
||||
uint8_t :3;
|
||||
uint8_t SwingH :1;
|
||||
uint8_t :1;
|
||||
uint8_t HalfDegree :1;
|
||||
uint8_t :2;
|
||||
uint8_t :1;
|
||||
uint8_t isTcl :1;
|
||||
// Byte 13
|
||||
uint8_t Sum :8;
|
||||
};
|
||||
|
@ -81,15 +96,23 @@ const uint8_t kTcl112AcFan = 7;
|
|||
const uint8_t kTcl112AcAuto = 8;
|
||||
|
||||
const uint8_t kTcl112AcFanAuto = 0b000;
|
||||
const uint8_t kTcl112AcFanMin = 0b001; // Aka. "Night"
|
||||
const uint8_t kTcl112AcFanLow = 0b010;
|
||||
const uint8_t kTcl112AcFanMed = 0b011;
|
||||
const uint8_t kTcl112AcFanHigh = 0b101;
|
||||
const uint8_t kTcl112AcFanNight = kTcl112AcFanMin;
|
||||
const uint8_t kTcl112AcFanQuiet = kTcl112AcFanMin;
|
||||
|
||||
const float kTcl112AcTempMax = 31.0;
|
||||
const float kTcl112AcTempMin = 16.0;
|
||||
|
||||
const uint8_t kTcl112AcSwingVOn = 0b111;
|
||||
const uint8_t kTcl112AcSwingVOff = 0b000;
|
||||
const uint8_t kTcl112AcSwingVHighest = 0b001;
|
||||
const uint8_t kTcl112AcSwingVHigh = 0b010;
|
||||
const uint8_t kTcl112AcSwingVMiddle = 0b011;
|
||||
const uint8_t kTcl112AcSwingVLow = 0b100;
|
||||
const uint8_t kTcl112AcSwingVLowest = 0b101;
|
||||
const uint8_t kTcl112AcSwingVOn = 0b111;
|
||||
// MsgType
|
||||
const uint8_t kTcl112AcNormal = 0b01;
|
||||
const uint8_t kTcl112AcSpecial = 0b10;
|
||||
|
@ -113,6 +136,8 @@ class IRTcl112Ac {
|
|||
uint8_t* getRaw(void);
|
||||
void setRaw(const uint8_t new_code[],
|
||||
const uint16_t length = kTcl112AcStateLength);
|
||||
tcl_ac_remote_model_t getModel(void) const;
|
||||
void setModel(const tcl_ac_remote_model_t model);
|
||||
void on(void);
|
||||
void off(void);
|
||||
void setPower(const bool on);
|
||||
|
@ -135,16 +160,23 @@ class IRTcl112Ac {
|
|||
bool getLight(void) const;
|
||||
void setSwingHorizontal(const bool on);
|
||||
bool getSwingHorizontal(void) const;
|
||||
void setSwingVertical(const bool on);
|
||||
bool getSwingVertical(void) const;
|
||||
void setSwingVertical(const uint8_t setting);
|
||||
uint8_t getSwingVertical(void) const;
|
||||
void setTurbo(const bool on);
|
||||
bool getTurbo(void) const;
|
||||
void setQuiet(const bool on);
|
||||
bool getQuiet(const bool def = false) const;
|
||||
uint16_t getOnTimer(void) const;
|
||||
void setOnTimer(const uint16_t mins);
|
||||
uint16_t getOffTimer(void) const;
|
||||
void setOffTimer(const uint16_t mins);
|
||||
static bool isTcl(const uint8_t state[]);
|
||||
static uint8_t convertMode(const stdAc::opmode_t mode);
|
||||
static uint8_t convertFan(const stdAc::fanspeed_t speed);
|
||||
static uint8_t convertSwingV(const stdAc::swingv_t position);
|
||||
static stdAc::opmode_t toCommonMode(const uint8_t mode);
|
||||
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
|
||||
static stdAc::swingv_t toCommonSwingV(const uint8_t setting);
|
||||
stdAc::state_t toCommon(const stdAc::state_t *prev = NULL) const;
|
||||
String toString(void) const;
|
||||
#ifndef UNIT_TEST
|
||||
|
|
|
@ -29,7 +29,7 @@ using irutils::addIntToString;
|
|||
using irutils::addLabeledString;
|
||||
using irutils::addModeToString;
|
||||
using irutils::addTempToString;
|
||||
|
||||
using irutils::addToggleToString;
|
||||
|
||||
#if SEND_TRANSCOLD
|
||||
/// Send a Transcold message
|
||||
|
@ -391,13 +391,7 @@ String IRTranscoldAc::toString(void) const {
|
|||
result += addBoolToString(getPower(), kPowerStr, false);
|
||||
if (!getPower()) return result; // If it's off, there is no other info.
|
||||
// Special modes.
|
||||
if (getSwing()) {
|
||||
result += kCommaSpaceStr;
|
||||
result += kSwingStr;
|
||||
result += kColonSpaceStr;
|
||||
result += kToggleStr;
|
||||
return result;
|
||||
}
|
||||
if (getSwing()) return result + addToggleToString(true, kSwingStr);
|
||||
result += addModeToString(getMode(), kTranscoldAuto, kTranscoldCool,
|
||||
kTranscoldHeat, kTranscoldDry, kTranscoldFan);
|
||||
result += addIntToString(_.Fan, kFanStr);
|
||||
|
|
|
@ -30,9 +30,15 @@
|
|||
#ifndef D_STR_ON
|
||||
#define D_STR_ON "On"
|
||||
#endif // D_STR_ON
|
||||
#ifndef D_STR_1
|
||||
#define D_STR_1 "1"
|
||||
#endif // D_STR_1
|
||||
#ifndef D_STR_OFF
|
||||
#define D_STR_OFF "Off"
|
||||
#endif // D_STR_OFF
|
||||
#ifndef D_STR_0
|
||||
#define D_STR_0 "0"
|
||||
#endif // D_STR_0
|
||||
#ifndef D_STR_MODE
|
||||
#define D_STR_MODE "Mode"
|
||||
#endif // D_STR_MODE
|
||||
|
@ -285,6 +291,9 @@
|
|||
#ifndef D_STR_VANE
|
||||
#define D_STR_VANE "Vane"
|
||||
#endif // D_STR_VANE
|
||||
#ifndef D_STR_LOCK
|
||||
#define D_STR_LOCK "Lock"
|
||||
#endif // D_STR_LOCK
|
||||
|
||||
#ifndef D_STR_AUTO
|
||||
#define D_STR_AUTO "Auto"
|
||||
|
@ -298,18 +307,42 @@
|
|||
#ifndef D_STR_COOL
|
||||
#define D_STR_COOL "Cool"
|
||||
#endif // D_STR_COOL
|
||||
#ifndef D_STR_COOLING
|
||||
#define D_STR_COOLING "Cooling"
|
||||
#endif // D_STR_COOLING
|
||||
#ifndef D_STR_HEAT
|
||||
#define D_STR_HEAT "Heat"
|
||||
#endif // D_STR_HEAT
|
||||
#ifndef D_STR_HEATING
|
||||
#define D_STR_HEATING "Heating"
|
||||
#endif // D_STR_HEATING
|
||||
#ifndef D_STR_FAN
|
||||
#define D_STR_FAN "Fan"
|
||||
#endif // D_STR_FAN
|
||||
#ifndef D_STR_FANONLY
|
||||
#define D_STR_FANONLY "fan_only"
|
||||
#define D_STR_FANONLY "fan-only"
|
||||
#endif // D_STR_FANONLY
|
||||
#ifndef D_STR_FAN_ONLY
|
||||
#define D_STR_FAN_ONLY "fan_only"
|
||||
#endif // D_STR_FAN_ONLY
|
||||
#ifndef D_STR_ONLY
|
||||
#define D_STR_ONLY "Only"
|
||||
#endif // D_STR_ONLY
|
||||
#ifndef D_STR_FANSPACEONLY
|
||||
#define D_STR_FANSPACEONLY D_STR_FAN " " D_STR_ONLY
|
||||
#endif // D_STR_FANSPACEONLY
|
||||
#ifndef D_STR_FANONLYNOSPACE
|
||||
#define D_STR_FANONLYNOSPACE D_STR_FAN D_STR_ONLY
|
||||
#endif // D_STR_FANONLYNOSPACE
|
||||
#ifndef D_STR_DRY
|
||||
#define D_STR_DRY "Dry"
|
||||
#endif // D_STR_DRY
|
||||
#ifndef D_STR_DRYING
|
||||
#define D_STR_DRYING "Drying"
|
||||
#endif // D_STR_DRYING
|
||||
#ifndef D_STR_DEHUMIDIFY
|
||||
#define D_STR_DEHUMIDIFY "Dehumidify"
|
||||
#endif // D_STR_DEHUMIDIFY
|
||||
|
||||
#ifndef D_STR_MAX
|
||||
#define D_STR_MAX "Max"
|
||||
|
@ -360,6 +393,12 @@
|
|||
#ifndef D_STR_MAXRIGHT
|
||||
#define D_STR_MAXRIGHT D_STR_MAX " " D_STR_RIGHT // Set `D_STR_MAX` first!
|
||||
#endif // D_STR_MAXRIGHT
|
||||
#ifndef D_STR_MAXRIGHT_NOSPACE
|
||||
#define D_STR_MAXRIGHT_NOSPACE D_STR_MAX D_STR_RIGHT // Set `D_STR_MAX` first!
|
||||
#endif // D_STR_MAXRIGHT_NOSPACE
|
||||
#ifndef D_STR_RIGHTMAX
|
||||
#define D_STR_RIGHTMAX D_STR_RIGHT " " D_STR_MAX // Set `D_STR_MAX` first!
|
||||
#endif // D_STR_RIGHTMAX
|
||||
#ifndef D_STR_RIGHTMAX_NOSPACE
|
||||
#define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX // Set `D_STR_MAX` first!
|
||||
#endif // D_STR_RIGHTMAX_NOSPACE
|
||||
|
@ -369,6 +408,12 @@
|
|||
#ifndef D_STR_MAXLEFT
|
||||
#define D_STR_MAXLEFT D_STR_MAX " " D_STR_LEFT // Set `D_STR_MAX` first!
|
||||
#endif // D_STR_MAXLEFT
|
||||
#ifndef D_STR_MAXLEFT_NOSPACE
|
||||
#define D_STR_MAXLEFT_NOSPACE D_STR_MAX D_STR_LEFT // Set `D_STR_MAX` first!
|
||||
#endif // D_STR_MAXLEFT_NOSPACE
|
||||
#ifndef D_STR_LEFTMAX
|
||||
#define D_STR_LEFTMAX D_STR_LEFT " " D_STR_MAX // Set `D_STR_MAX` first!
|
||||
#endif // D_STR_LEFTMAX
|
||||
#ifndef D_STR_LEFTMAX_NOSPACE
|
||||
#define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX // Set `D_STR_MAX` first!
|
||||
#endif // D_STR_LEFTMAX_NOSPACE
|
||||
|
@ -440,6 +485,9 @@
|
|||
#ifndef D_STR_COLONSPACE
|
||||
#define D_STR_COLONSPACE ": "
|
||||
#endif // D_STR_COLONSPACE
|
||||
#ifndef D_STR_DASH
|
||||
#define D_STR_DASH "-"
|
||||
#endif // D_STR_DASH
|
||||
|
||||
#ifndef D_STR_DAY
|
||||
#define D_STR_DAY "Day"
|
||||
|
@ -495,7 +543,135 @@
|
|||
#define D_STR_BITS "Bits"
|
||||
#endif // D_STR_BITS
|
||||
|
||||
// Model Names
|
||||
#ifndef D_STR_YAW1F
|
||||
#define D_STR_YAW1F "YAW1F"
|
||||
#endif // D_STR_YAW1F
|
||||
#ifndef D_STR_YBOFB
|
||||
#define D_STR_YBOFB "YBOFB"
|
||||
#endif // D_STR_YBOFB
|
||||
#ifndef D_STR_V9014557_A
|
||||
#define D_STR_V9014557_A "V9014557-A"
|
||||
#endif // D_STR_V9014557_A
|
||||
#ifndef D_STR_V9014557_B
|
||||
#define D_STR_V9014557_B "V9014557-B"
|
||||
#endif // D_STR_V9014557_B
|
||||
#ifndef D_STR_RLT0541HTA_A
|
||||
#define D_STR_RLT0541HTA_A "R-LT0541-HTA-A"
|
||||
#endif // D_STR_RLT0541HTA_A
|
||||
#ifndef D_STR_RLT0541HTA_B
|
||||
#define D_STR_RLT0541HTA_B "R-LT0541-HTA-B"
|
||||
#endif // D_STR_RLT0541HTA_B
|
||||
#ifndef D_STR_ARRAH2E
|
||||
#define D_STR_ARRAH2E "ARRAH2E"
|
||||
#endif // D_STR_ARRAH2E
|
||||
#ifndef D_STR_ARDB1
|
||||
#define D_STR_ARDB1 "ARDB1"
|
||||
#endif // D_STR_ARDB1
|
||||
#ifndef D_STR_ARREB1E
|
||||
#define D_STR_ARREB1E "ARREB1E"
|
||||
#endif // D_STR_ARREB1E
|
||||
#ifndef D_STR_ARJW2
|
||||
#define D_STR_ARJW2 "ARJW2"
|
||||
#endif // D_STR_ARJW2
|
||||
#ifndef D_STR_ARRY4
|
||||
#define D_STR_ARRY4 "ARRY4"
|
||||
#endif // D_STR_ARRY4
|
||||
#ifndef D_STR_ARREW4E
|
||||
#define D_STR_ARREW4E "ARREW4E"
|
||||
#endif // D_STR_ARREW4E
|
||||
#ifndef D_STR_GE6711AR2853M
|
||||
#define D_STR_GE6711AR2853M "GE6711AR2853M"
|
||||
#endif // D_STR_GE6711AR2853M
|
||||
#ifndef D_STR_AKB75215403
|
||||
#define D_STR_AKB75215403 "AKB75215403"
|
||||
#endif // D_STR_AKB75215403
|
||||
#ifndef D_STR_AKB74955603
|
||||
#define D_STR_AKB74955603 "AKB74955603"
|
||||
#endif // D_STR_AKB74955603
|
||||
#ifndef D_STR_AKB73757604
|
||||
#define D_STR_AKB73757604 "AKB73757604"
|
||||
#endif // D_STR_AKB73757604
|
||||
#ifndef D_STR_KKG9AC1
|
||||
#define D_STR_KKG9AC1 "KKG9AC1"
|
||||
#endif // D_STR_KKG9AC1
|
||||
#ifndef D_STR_KKG29AC1
|
||||
#define D_STR_KKG29AC1 "KKG29AC1"
|
||||
#endif // D_STR_KKG9AC1
|
||||
#ifndef D_STR_LKE
|
||||
#define D_STR_LKE "LKE"
|
||||
#endif // D_STR_LKE
|
||||
#ifndef D_STR_NKE
|
||||
#define D_STR_NKE "NKE"
|
||||
#endif // D_STR_NKE
|
||||
#ifndef D_STR_DKE
|
||||
#define D_STR_DKE "DKE"
|
||||
#endif // D_STR_DKE
|
||||
#ifndef D_STR_PKR
|
||||
#define D_STR_PKR "PKR"
|
||||
#endif // D_STR_PKR
|
||||
#ifndef D_STR_JKE
|
||||
#define D_STR_JKE "JKE"
|
||||
#endif // D_STR_JKE
|
||||
#ifndef D_STR_CKP
|
||||
#define D_STR_CKP "CKP"
|
||||
#endif // D_STR_CKP
|
||||
#ifndef D_STR_RKR
|
||||
#define D_STR_RKR "RKR"
|
||||
#endif // D_STR_RKR
|
||||
#ifndef D_STR_PANASONICLKE
|
||||
#define D_STR_PANASONICLKE "PANASONICLKE"
|
||||
#endif // D_STR_PANASONICLKE
|
||||
#ifndef D_STR_PANASONICNKE
|
||||
#define D_STR_PANASONICNKE "PANASONICNKE"
|
||||
#endif // D_STR_PANASONICNKE
|
||||
#ifndef D_STR_PANASONICDKE
|
||||
#define D_STR_PANASONICDKE "PANASONICDKE"
|
||||
#endif // D_STR_PANASONICDKE
|
||||
#ifndef D_STR_PANASONICPKR
|
||||
#define D_STR_PANASONICPKR "PANASONICPKR"
|
||||
#endif // D_STR_PANASONICPKR
|
||||
#ifndef D_STR_PANASONICJKE
|
||||
#define D_STR_PANASONICJKE "PANASONICJKE"
|
||||
#endif // D_STR_PANASONICJKE
|
||||
#ifndef D_STR_PANASONICCKP
|
||||
#define D_STR_PANASONICCKP "PANASONICCKP"
|
||||
#endif // D_STR_PANASONICCKP
|
||||
#ifndef D_STR_PANASONICRKR
|
||||
#define D_STR_PANASONICRKR "PANASONICRKR"
|
||||
#endif // D_STR_PANASONICRKR
|
||||
#ifndef D_STR_A907
|
||||
#define D_STR_A907 "A907"
|
||||
#endif // D_STR_A907
|
||||
#ifndef D_STR_A705
|
||||
#define D_STR_A705 "A705"
|
||||
#endif // D_STR_A705
|
||||
#ifndef D_STR_A903
|
||||
#define D_STR_A903 "A903"
|
||||
#endif // D_STR_A903
|
||||
#ifndef D_STR_TAC09CHSD
|
||||
#define D_STR_TAC09CHSD "TAC09CHSD"
|
||||
#endif // D_STR_TAC09CHSD
|
||||
#ifndef D_STR_GZ055BE1
|
||||
#define D_STR_GZ055BE1 "GZ055BE1"
|
||||
#endif // D_STR_GZ055BE1
|
||||
#ifndef D_STR_122LZF
|
||||
#define D_STR_122LZF "122LZF"
|
||||
#endif // D_STR_122LZF
|
||||
#ifndef D_STR_DG11J13A
|
||||
#define D_STR_DG11J13A "DG11J13A"
|
||||
#endif // D_STR_DG11J13A
|
||||
#ifndef D_STR_DG11J104
|
||||
#define D_STR_DG11J104 "DG11J104"
|
||||
#endif // D_STR_DG11J104
|
||||
#ifndef D_STR_DG11J191
|
||||
#define D_STR_DG11J191 "DG11J191"
|
||||
#endif // D_STR_DG11J191
|
||||
|
||||
// Protocols Names
|
||||
#ifndef D_STR_AIRTON
|
||||
#define D_STR_AIRTON "AIRTON"
|
||||
#endif // D_STR_AIRTON
|
||||
#ifndef D_STR_AIRWELL
|
||||
#define D_STR_AIRWELL "AIRWELL"
|
||||
#endif // D_STR_AIRWELL
|
||||
|
@ -508,6 +684,9 @@
|
|||
#ifndef D_STR_ARGO
|
||||
#define D_STR_ARGO "ARGO"
|
||||
#endif // D_STR_ARGO
|
||||
#ifndef D_STR_ARRIS
|
||||
#define D_STR_ARRIS "ARRIS"
|
||||
#endif // D_STR_ARRIS
|
||||
#ifndef D_STR_BOSE
|
||||
#define D_STR_BOSE "BOSE"
|
||||
#endif // D_STR_BOSE
|
||||
|
@ -733,6 +912,9 @@
|
|||
#ifndef D_STR_RCMM
|
||||
#define D_STR_RCMM "RCMM"
|
||||
#endif // D_STR_RCMM
|
||||
#ifndef D_STR_RHOSS
|
||||
#define D_STR_RHOSS "RHOSS"
|
||||
#endif // D_STR_RHOSS
|
||||
#ifndef D_STR_SAMSUNG
|
||||
#define D_STR_SAMSUNG "SAMSUNG"
|
||||
#endif // D_STR_SAMSUNG
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#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_TIMERMODE D_STR_MODE " " D_STR_TIMER
|
||||
#define D_STR_CLOCK "Relógio"
|
||||
#define D_STR_COMMAND "Comando"
|
||||
#define D_STR_HEALTH "Saúde"
|
||||
|
@ -84,6 +85,11 @@
|
|||
#define D_STR_6THSENSE "Sexto sentido"
|
||||
#define D_STR_ZONEFOLLOW "Acompanhar ambiente"
|
||||
#define D_STR_FIXED "Fixo"
|
||||
#define D_STR_TYPE "Tipo"
|
||||
#define D_STR_SPECIAL "Especial"
|
||||
#define D_STR_RECYCLE "Reciclar"
|
||||
#define D_STR_ID "Id"
|
||||
#define D_STR_VANE "Vane"
|
||||
|
||||
#define D_STR_AUTO "Auto"
|
||||
#define D_STR_AUTOMATIC "Automático"
|
||||
|
@ -91,7 +97,11 @@
|
|||
#define D_STR_COOL "Esfriar"
|
||||
#define D_STR_HEAT "Aquecer"
|
||||
#define D_STR_FAN "Ventilar"
|
||||
#define D_STR_FANONLY "Apenas ventilar"
|
||||
#define D_STR_FANONLY "Apenas-ventilar"
|
||||
#define D_STR_FAN_ONLY "Apenas_ventilar"
|
||||
#define D_STR_ONLY "Apenas"
|
||||
#define D_STR_FANSPACEONLY D_STR_ONLY " " D_STR_FAN
|
||||
#define D_STR_FANONLYNOSPACE D_STR_ONLY D_STR_FAN
|
||||
#define D_STR_DRY "Secar"
|
||||
#define D_STR_8C_HEAT D_STR_HEAT " 8C"
|
||||
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
// Copyright 2021 - PtilopsisLeucotis (@PtilopsisLeucotis)
|
||||
// Locale/language file for Russian / Russia.
|
||||
// This file will override the default values located in `defaults.h`.
|
||||
#ifndef LOCALE_RU_RU_H_
|
||||
#define LOCALE_RU_RU_H_
|
||||
|
||||
#define D_STR_UNKNOWN "НЕИЗВЕСТНО"
|
||||
#define D_STR_PROTOCOL "Протокол"
|
||||
#define D_STR_POWER "Питание"
|
||||
#define D_STR_PREVIOUS "Предыдущий"
|
||||
#define D_STR_ON "Вкл"
|
||||
#define D_STR_OFF "Выкл"
|
||||
#define D_STR_MODE "Режим"
|
||||
#define D_STR_TOGGLE "Переключить"
|
||||
#define D_STR_TURBO "Турбо"
|
||||
#define D_STR_SUPER "Супер"
|
||||
#define D_STR_SLEEP "Сон"
|
||||
#define D_STR_LIGHT "Свет"
|
||||
#define D_STR_POWERFUL "Мощный"
|
||||
#define D_STR_QUIET "Тихий"
|
||||
#define D_STR_ECONO "Экономичный"
|
||||
#define D_STR_SWING "Качание"
|
||||
#define D_STR_SWINGH D_STR_SWING"(Г)"
|
||||
#define D_STR_SWINGV D_STR_SWING"(В)"
|
||||
#define D_STR_BEEP "Звук"
|
||||
#define D_STR_MOULD "Плесень"
|
||||
#define D_STR_CLEAN "Чистый"
|
||||
#define D_STR_PURIFY "Очистка"
|
||||
#define D_STR_TIMER "Таймер"
|
||||
#define D_STR_ONTIMER "Таймер Включения"
|
||||
#define D_STR_OFFTIMER "Таймер Выключения"
|
||||
#define D_STR_TIMERMODE "Режим Таймера"
|
||||
#define D_STR_CLOCK "Часы"
|
||||
#define D_STR_COMMAND "Команда"
|
||||
#define D_STR_HEALTH "Здоровье"
|
||||
#define D_STR_MODEL "Модель"
|
||||
#define D_STR_TEMP "Температура"
|
||||
#define D_STR_HUMID "Влажность"
|
||||
#define D_STR_SAVE "Сохранить"
|
||||
#define D_STR_EYE "Глаз"
|
||||
#define D_STR_FOLLOW "Следовать"
|
||||
#define D_STR_ION "Ион"
|
||||
#define D_STR_FRESH "Свежесть"
|
||||
#define D_STR_HOLD "Удержать"
|
||||
#define D_STR_BUTTON "Кнопка"
|
||||
#define D_STR_NIGHT "Ночь"
|
||||
#define D_STR_SILENT "Тихий"
|
||||
#define D_STR_FILTER "Фильтр"
|
||||
#define D_STR_CELSIUS "Цельсий"
|
||||
#define D_STR_FAHRENHEIT "Фаренгейт"
|
||||
#define D_STR_UP "Выше"
|
||||
#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP
|
||||
#define D_STR_DOWN "Ниже"
|
||||
#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN
|
||||
#define D_STR_CHANGE "Изменение"
|
||||
#define D_STR_START "Запуск"
|
||||
#define D_STR_STOP "Остановка"
|
||||
#define D_STR_MOVE "Перемещение"
|
||||
#define D_STR_SET "Установка"
|
||||
#define D_STR_CANCEL "Отмена"
|
||||
#define D_STR_COMFORT "Комфорт"
|
||||
#define D_STR_SENSOR "Сенсор"
|
||||
#define D_STR_DISPLAY "Дисплей"
|
||||
#define D_STR_WEEKLY "Недельный"
|
||||
#define D_STR_LAST "Последний"
|
||||
#define D_STR_FAST "Быстро"
|
||||
#define D_STR_SLOW "Медленно"
|
||||
#define D_STR_AIRFLOW "Воздушный Поток"
|
||||
#define D_STR_STEP "Шаг"
|
||||
#define D_STR_NA "Н/Д"
|
||||
#define D_STR_INSIDE "Внутри"
|
||||
#define D_STR_OUTSIDE "Снаружи"
|
||||
#define D_STR_LOUD "Громко"
|
||||
#define D_STR_UPPER "Верхнее"
|
||||
#define D_STR_LOWER "Нижнее"
|
||||
#define D_STR_BREEZE "Бриз"
|
||||
#define D_STR_CIRCULATE "Циркуляция"
|
||||
#define D_STR_CEILING "Потолок"
|
||||
#define D_STR_WALL "Стена"
|
||||
#define D_STR_ROOM "Комната"
|
||||
#define D_STR_6THSENSE "6-ое чувство"
|
||||
#define D_STR_FIXED "Фиксированный"
|
||||
#define D_STR_TYPE "Тип"
|
||||
#define D_STR_SPECIAL "Специальный"
|
||||
#define D_STR_RECYCLE "Рециркуляция"
|
||||
#define D_STR_VANE "Жалюзи"
|
||||
#define D_STR_LOCK "Блокировка"
|
||||
#define D_STR_AUTO "Авто"
|
||||
#define D_STR_AUTOMATIC "Автоматический"
|
||||
#define D_STR_MANUAL "Ручной"
|
||||
#define D_STR_COOL "Охл"
|
||||
#define D_STR_COOLING "Охлаждение"
|
||||
#define D_STR_HEAT "Нагр"
|
||||
#define D_STR_HEATING "Обогрев"
|
||||
#define D_STR_FAN "Вентиляция"
|
||||
#define D_STR_ONLY "Только"
|
||||
#define D_STR_FANSPACEONLY D_STR_ONLY " " D_STR_FAN
|
||||
#define D_STR_FANONLYNOSPACE D_STR_ONLY D_STR_FAN
|
||||
#define D_STR_DRY "Сухо"
|
||||
#define D_STR_DRYING "Сушка"
|
||||
#define D_STR_DEHUMIDIFY "Осушение"
|
||||
#define D_STR_MAX "Макс"
|
||||
#define D_STR_MAXIMUM "Максимум"
|
||||
#define D_STR_MIN "Мин"
|
||||
#define D_STR_MINIMUM "Минимум"
|
||||
#define D_STR_MED "Сред"
|
||||
#define D_STR_MEDIUM "Среднее"
|
||||
#define D_STR_HIGHEST "Верхнее"
|
||||
#define D_STR_HIGH "Верх"
|
||||
#define D_STR_HI "Верх"
|
||||
#define D_STR_MID "Сред"
|
||||
#define D_STR_MIDDLE "Середина"
|
||||
#define D_STR_LOW "Низ"
|
||||
#define D_STR_LO "Низ"
|
||||
#define D_STR_LOWEST "Нижнее"
|
||||
#define D_STR_RIGHT "Право"
|
||||
#define D_STR_LEFT "Лево"
|
||||
#define D_STR_WIDE "Широкий"
|
||||
#define D_STR_CENTRE "Центр"
|
||||
#define D_STR_TOP "Наивысший"
|
||||
#define D_STR_BOTTOM "Наинизший"
|
||||
#define D_STR_DAY "День"
|
||||
#define D_STR_DAYS "Дней"
|
||||
#define D_STR_HOUR "Час"
|
||||
#define D_STR_HOURS "Часов"
|
||||
#define D_STR_MINUTE "Минута"
|
||||
#define D_STR_MINUTES "Минут"
|
||||
#define D_STR_SECOND "Секунда"
|
||||
#define D_STR_SECONDS "Секунд"
|
||||
#define D_STR_NOW "Сейчас"
|
||||
#define D_STR_THREELETTERDAYS "ВскПндВтрСреЧтвПтнСуб"
|
||||
#define D_STR_YES "Да"
|
||||
#define D_STR_NO "Нет"
|
||||
#define D_STR_TRUE "Истина"
|
||||
#define D_STR_FALSE "Ложь"
|
||||
#define D_STR_REPEAT "Повтор"
|
||||
#define D_STR_CODE "Код"
|
||||
#define D_STR_BITS "Бит"
|
||||
|
||||
// IRrecvDumpV2+
|
||||
#define D_STR_TIMESTAMP "Метка Времени"
|
||||
#define D_STR_LIBRARY "Библиотека"
|
||||
#define D_STR_MESGDESC "Описание Сообщения."
|
||||
#define D_STR_TOLERANCE "Допуск"
|
||||
#define D_STR_IRRECVDUMP_STARTUP \
|
||||
"IRrecvDump запущен и ождает ИК команды на Входе %d"
|
||||
#define D_WARN_BUFFERFULL \
|
||||
"ПРЕДУПРЕЖДЕНИЕ: ИК код слишком велик для буфера (>= %d). " \
|
||||
"Этому результату не следует доверять, пока это не будет исправлено. " \
|
||||
"Исправьте и увеличьте `kCaptureBufferSize`."
|
||||
|
||||
#endif // LOCALE_RU_RU_H_
|
|
@ -0,0 +1,189 @@
|
|||
// Copyright 2021 - Tom Rosenback (@tomrosenback)
|
||||
// Locale/language file for swedish / Sweden.
|
||||
// This file will override the default values located in `defaults.h`.
|
||||
#ifndef LOCALE_SV_SE_H_
|
||||
#define LOCALE_SV_SE_H_
|
||||
|
||||
#define D_STR_UNKNOWN "OKÄND"
|
||||
#define D_STR_PROTOCOL "Protokoll"
|
||||
#define D_STR_POWER "Strömläge"
|
||||
#define D_STR_PREVIOUS "Föregående"
|
||||
#define D_STR_ON "På"
|
||||
#define D_STR_OFF "Av"
|
||||
#define D_STR_MODE "Läge"
|
||||
#define D_STR_TOGGLE "Växla"
|
||||
#define D_STR_TURBO "Turbo"
|
||||
#define D_STR_SUPER "Super"
|
||||
#define D_STR_SLEEP "Sova"
|
||||
#define D_STR_LIGHT "Svag"
|
||||
#define D_STR_POWERFUL "Kraftig"
|
||||
#define D_STR_QUIET "Tyst"
|
||||
#define D_STR_ECONO "Eko"
|
||||
#define D_STR_SWING "Sving"
|
||||
#define D_STR_SWINGH D_STR_SWING"(H)"
|
||||
#define D_STR_SWINGV D_STR_SWING"(V)"
|
||||
#define D_STR_BEEP "Pip"
|
||||
#define D_STR_MOULD "Forma"
|
||||
#define D_STR_CLEAN "Rengör"
|
||||
#define D_STR_PURIFY "Rena"
|
||||
#define D_STR_TIMER "Timer"
|
||||
#define D_STR_ONTIMER "På timer"
|
||||
#define D_STR_OFFTIMER "Av timer"
|
||||
#define D_STR_TIMERMODE "Timerläge"
|
||||
#define D_STR_CLOCK "Klocka"
|
||||
#define D_STR_COMMAND "Kommando"
|
||||
#define D_STR_XFAN "XFan"
|
||||
#define D_STR_HEALTH "Hälsa"
|
||||
#define D_STR_MODEL "Modell"
|
||||
#define D_STR_TEMP "Temp"
|
||||
#define D_STR_IFEEL "Känns som"
|
||||
#define D_STR_HUMID "Humid"
|
||||
#define D_STR_SAVE "Save"
|
||||
#define D_STR_EYE "Öga"
|
||||
#define D_STR_FOLLOW "Följ"
|
||||
#define D_STR_ION "Ion"
|
||||
#define D_STR_FRESH "Frisk"
|
||||
#define D_STR_HOLD "Håll"
|
||||
#define D_STR_8C_HEAT "8C " D_STR_HEAT
|
||||
#define D_STR_10C_HEAT "10C " D_STR_HEAT
|
||||
#define D_STR_BUTTON "Knapp"
|
||||
#define D_STR_NIGHT "Natt"
|
||||
#define D_STR_SILENT "Tyst"
|
||||
#define D_STR_FILTER "Filter"
|
||||
#define D_STR_3D "3D"
|
||||
#define D_STR_CELSIUS "Celsius"
|
||||
#define D_STR_FAHRENHEIT "Fahrenheit"
|
||||
#define D_STR_CELSIUS_FAHRENHEIT D_STR_CELSIUS "/" D_STR_FAHRENHEIT
|
||||
#define D_STR_UP "Upp"
|
||||
#define D_STR_TEMPUP D_STR_TEMP " upp"
|
||||
#define D_STR_DOWN "Ner"
|
||||
#define D_STR_TEMPDOWN D_STR_TEMP " ner"
|
||||
#define D_STR_CHANGE "Ändra"
|
||||
#define D_STR_START "Starta"
|
||||
#define D_STR_STOP "Stoppa"
|
||||
#define D_STR_MOVE "Flytta"
|
||||
#define D_STR_SET "Ställ in"
|
||||
#define D_STR_CANCEL "Avbryt"
|
||||
#define D_STR_COMFORT "Komfort"
|
||||
#define D_STR_SENSOR "Sensor"
|
||||
#define D_STR_DISPLAY "Display"
|
||||
#define D_STR_WEEKLY "Veckovis"
|
||||
#define D_STR_WEEKLYTIMER D_STR_WEEKLY " timer"
|
||||
#define D_STR_WIFI "WiFi"
|
||||
#define D_STR_LAST "Senast"
|
||||
#define D_STR_FAST "Snabb"
|
||||
#define D_STR_SLOW "Sakta"
|
||||
#define D_STR_AIRFLOW "Luftflöde"
|
||||
#define D_STR_STEP "Steppa"
|
||||
#define D_STR_NA "N/A"
|
||||
#define D_STR_INSIDE "Inne"
|
||||
#define D_STR_OUTSIDE "Ute"
|
||||
#define D_STR_LOUD "Hög"
|
||||
#define D_STR_UPPER "Övre"
|
||||
#define D_STR_LOWER "Nedre"
|
||||
#define D_STR_BREEZE "Bris"
|
||||
#define D_STR_CIRCULATE "Cirkulera"
|
||||
#define D_STR_CEILING "Tak"
|
||||
#define D_STR_WALL "Vägg"
|
||||
#define D_STR_ROOM "Rum"
|
||||
#define D_STR_6THSENSE "6e sinne"
|
||||
#define D_STR_ZONEFOLLOW "Följ zon"
|
||||
#define D_STR_FIXED "Fast"
|
||||
#define D_STR_TYPE "Typ"
|
||||
#define D_STR_SPECIAL "Speciell"
|
||||
#define D_STR_RECYCLE "Återvinn"
|
||||
#define D_STR_ID "Id"
|
||||
#define D_STR_VANE "Vindflöjel"
|
||||
|
||||
#define D_STR_AUTO "Auto"
|
||||
#define D_STR_AUTOMATIC "Automatisk"
|
||||
#define D_STR_MANUAL "Manuell"
|
||||
#define D_STR_COOL "Kyla"
|
||||
#define D_STR_HEAT "Värme"
|
||||
#define D_STR_FAN "Fläkt"
|
||||
#define D_STR_FANONLY "fläkt-enbart"
|
||||
#define D_STR_FAN_ONLY "fläkt_enbart"
|
||||
#define D_STR_ONLY "Enbart"
|
||||
#define D_STR_FANSPACEONLY D_STR_FAN " " D_STR_ONLY
|
||||
#define D_STR_FANONLYNOSPACE D_STR_FAN D_STR_ONLY
|
||||
#define D_STR_DRY "Torka"
|
||||
|
||||
#define D_STR_MAX "Max"
|
||||
#define D_STR_MAXIMUM "Maximum"
|
||||
#define D_STR_MIN "Min"
|
||||
#define D_STR_MINIMUM "Minimum"
|
||||
#define D_STR_MED "Med"
|
||||
#define D_STR_MEDIUM "Medium"
|
||||
|
||||
#define D_STR_HIGHEST "Högsta"
|
||||
#define D_STR_HIGH "Hög"
|
||||
#define D_STR_HI "Hög"
|
||||
#define D_STR_MID "Mellan"
|
||||
#define D_STR_MIDDLE "Mellan"
|
||||
#define D_STR_LOW "Låg"
|
||||
#define D_STR_LO "Låg"
|
||||
#define D_STR_LOWEST "Lägsta"
|
||||
#define D_STR_RIGHT "Höger"
|
||||
#define D_STR_MAXRIGHT D_STR_MAX " höger"
|
||||
#define D_STR_RIGHTMAX_NOSPACE D_STR_MAX D_STR_RIGHT
|
||||
#define D_STR_LEFT "Vänster"
|
||||
#define D_STR_MAXLEFT D_STR_MAX " vänster"
|
||||
#define D_STR_LEFTMAX_NOSPACE D_STR_MAX D_STR_LEFT
|
||||
#define D_STR_WIDE "Vid"
|
||||
#define D_STR_CENTRE "Mitten"
|
||||
#define D_STR_TOP "Topp"
|
||||
#define D_STR_BOTTOM "Botten"
|
||||
|
||||
#define D_STR_ECONOTOGGLE D_STR_TOGGLE " eko"
|
||||
#define D_STR_EYEAUTO D_STR_AUTO " öga"
|
||||
#define D_STR_LIGHTTOGGLE D_STR_TOGGLE " svag"
|
||||
#define D_STR_OUTSIDEQUIET D_STR_QUIET " ute"
|
||||
#define D_STR_POWERTOGGLE D_STR_TOGGLE " strömläge"
|
||||
#define D_STR_POWERBUTTON "Strömknapp"
|
||||
#define D_STR_PREVIOUSPOWER "Föregående strömläge"
|
||||
#define D_STR_DISPLAYTEMP "Displaytemp"
|
||||
#define D_STR_SENSORTEMP "Sensortemp"
|
||||
#define D_STR_SLEEP_TIMER "Sovtimer"
|
||||
#define D_STR_SWINGVMODE D_STR_SWINGV " läge"
|
||||
#define D_STR_SWINGVTOGGLE D_STR_TOGGLE " sving(v)"
|
||||
#define D_STR_TURBOTOGGLE D_STR_TOGGLE " turbo"
|
||||
|
||||
// Separatorer
|
||||
#define D_CHR_TIME_SEP ':'
|
||||
#define D_STR_SPACELBRACE " ("
|
||||
#define D_STR_COMMASPACE ", "
|
||||
#define D_STR_COLONSPACE ": "
|
||||
|
||||
#define D_STR_DAY "Dag"
|
||||
#define D_STR_DAYS D_STR_DAY "ar"
|
||||
#define D_STR_HOUR "Timme"
|
||||
#define D_STR_HOURS "Timmar"
|
||||
#define D_STR_MINUTE "Minut"
|
||||
#define D_STR_MINUTES D_STR_MINUTE "er"
|
||||
#define D_STR_SECOND "Sekund"
|
||||
#define D_STR_SECONDS D_STR_MINUTE "er"
|
||||
#define D_STR_NOW "Nu"
|
||||
#define D_STR_THREELETTERDAYS "SönMånTisOnsTorFreLör"
|
||||
|
||||
#define D_STR_YES "Ja"
|
||||
#define D_STR_NO "Nej"
|
||||
#define D_STR_TRUE "Sant"
|
||||
#define D_STR_FALSE "Falskt"
|
||||
|
||||
#define D_STR_REPEAT "Upprepa"
|
||||
#define D_STR_CODE "Kod"
|
||||
#define D_STR_BITS "Bitar"
|
||||
|
||||
// IRrecvDumpV2+
|
||||
#define D_STR_TIMESTAMP "Tidskod"
|
||||
#define D_STR_LIBRARY "Bibliotek"
|
||||
#define D_STR_MESGDESC "Meddelande beskr."
|
||||
#define D_STR_TOLERANCE "Tolerans"
|
||||
#define D_STR_IRRECVDUMP_STARTUP \
|
||||
"IRrecvDump har nu startats och väntar på IR signaler på PIN %d"
|
||||
#define D_WARN_BUFFERFULL \
|
||||
"VARNING: IR koden är för stor för att rymmas i bufferminnet (>= %d). " \
|
||||
"Detta resultat är inte pålitligt innan problemet är åtgärdat. " \
|
||||
"Redigera och öka `kCaptureBufferSize`."
|
||||
|
||||
#endif // LOCALE_SV_SE_H_
|
|
@ -19,6 +19,7 @@
|
|||
#include "ir_Kelvinator.h"
|
||||
#include "ir_LG.h"
|
||||
#include "ir_Midea.h"
|
||||
#include "ir_Mirage.h"
|
||||
#include "ir_Mitsubishi.h"
|
||||
#include "ir_MitsubishiHeavy.h"
|
||||
#include "ir_Neoclima.h"
|
||||
|
@ -560,7 +561,8 @@ TEST(TestIRac, Electra) {
|
|||
IRrecv capture(kGpioUnused);
|
||||
char expected[] =
|
||||
"Power: On, Mode: 6 (Fan), Temp: 26C, Fan: 1 (High), "
|
||||
"Swing(V): On, Swing(H): On, Light: Toggle, Clean: On, Turbo: On";
|
||||
"Swing(V): On, Swing(H): On, Light: Toggle, Clean: On, Turbo: On, "
|
||||
"IFeel: Off";
|
||||
|
||||
ac.begin();
|
||||
irac.electra(&ac,
|
||||
|
@ -727,9 +729,10 @@ TEST(TestIRac, Gree) {
|
|||
IRrecv capture(kGpioUnused);
|
||||
char expected[] =
|
||||
"Model: 1 (YAW1F), Power: On, Mode: 1 (Cool), Temp: 71F, "
|
||||
"Fan: 2 (Medium), Turbo: Off, IFeel: Off, WiFi: Off, XFan: On, "
|
||||
"Light: On, Sleep: On, Swing(V) Mode: Manual, "
|
||||
"Swing(V): 3 (UNKNOWN), Timer: Off, Display Temp: 0 (Off)";
|
||||
"Fan: 2 (Medium), Turbo: Off, Econo: Off, IFeel: Off, 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)";
|
||||
|
||||
ac.begin();
|
||||
irac.gree(&ac,
|
||||
|
@ -740,7 +743,9 @@ TEST(TestIRac, Gree) {
|
|||
71, // Degrees (F)
|
||||
stdAc::fanspeed_t::kMedium, // Fan speed
|
||||
stdAc::swingv_t::kHigh, // Vertical swing
|
||||
stdAc::swingh_t::kRight, // Horizontal swing
|
||||
false, // Turbo
|
||||
false, // Econo
|
||||
true, // Light
|
||||
true, // Clean (aka Mold/XFan)
|
||||
8 * 60 + 0); // Sleep time
|
||||
|
@ -760,7 +765,7 @@ TEST(TestIRac, Haier) {
|
|||
IRrecv capture(kGpioUnused);
|
||||
char expected[] =
|
||||
"Command: 1 (On), Mode: 1 (Cool), Temp: 24C, Fan: 2 (Medium), "
|
||||
"Swing: 1 (Up), Sleep: On, Health: On, Clock: 13:45, "
|
||||
"Swing(V): 1 (Up), Sleep: On, Health: On, Clock: 13:45, "
|
||||
"On Timer: Off, Off Timer: Off";
|
||||
|
||||
ac.begin();
|
||||
|
@ -788,17 +793,22 @@ TEST(TestIRac, Haier176) {
|
|||
IRac irac(kGpioUnused);
|
||||
IRrecv capture(kGpioUnused);
|
||||
const char expected[] =
|
||||
"Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 23C, "
|
||||
"Fan: 2 (Medium), Turbo: 1 (High), Swing: 1 (Highest), Sleep: On, "
|
||||
"Health: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off";
|
||||
"Model: 1 (V9014557-A), Power: On, Button: 5 (Power), "
|
||||
"Mode: 1 (Cool), Temp: 23C, Fan: 2 (Medium), Turbo: On, Quiet: Off, "
|
||||
"Swing(V): 1 (Highest), Swing(H): 0 (Middle), Sleep: On, Health: On, "
|
||||
"Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off";
|
||||
ac.begin();
|
||||
irac.haier176(&ac,
|
||||
haier_ac176_remote_model_t::V9014557_A, // Model
|
||||
true, // Power
|
||||
stdAc::opmode_t::kCool, // Mode
|
||||
23, // Celsius
|
||||
true, // Celsius
|
||||
23, // Degrees
|
||||
stdAc::fanspeed_t::kMedium, // Fan speed
|
||||
stdAc::swingv_t::kHigh, // Vertical swing
|
||||
stdAc::swingh_t::kOff, // Horizontal swing
|
||||
true, // Turbo
|
||||
false, // Quiet
|
||||
true, // Filter
|
||||
8 * 60 + 0); // Sleep time
|
||||
ASSERT_EQ(expected, ac.toString());
|
||||
|
@ -816,18 +826,22 @@ TEST(TestIRac, HaierYrwo2) {
|
|||
IRac irac(kGpioUnused);
|
||||
IRrecv capture(kGpioUnused);
|
||||
char expected[] =
|
||||
"Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 23C, "
|
||||
"Fan: 2 (Medium), Turbo: 1 (High), Swing: 1 (Highest), Sleep: On, "
|
||||
"Health: On, Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off";
|
||||
"Model: 1 (V9014557-A), Power: On, Button: 5 (Power), "
|
||||
"Mode: 1 (Cool), Temp: 23C, Fan: 2 (Medium), Turbo: Off, Quiet: On, "
|
||||
"Swing(V): 1 (Highest), Swing(H): 7 (Auto), Sleep: On, Health: On, "
|
||||
"Timer Mode: 0 (N/A), On Timer: Off, Off Timer: Off, Lock: Off";
|
||||
|
||||
ac.begin();
|
||||
irac.haierYrwo2(&ac,
|
||||
true, // Power
|
||||
stdAc::opmode_t::kCool, // Mode
|
||||
23, // Celsius
|
||||
true, // Celsius
|
||||
23, // Degrees
|
||||
stdAc::fanspeed_t::kMedium, // Fan speed
|
||||
stdAc::swingv_t::kHigh, // Vertical swing
|
||||
true, // Turbo
|
||||
stdAc::swingh_t::kAuto, // Vertical swing
|
||||
false, // Turbo
|
||||
true, // Quiet
|
||||
true, // Filter
|
||||
8 * 60 + 0); // Sleep time
|
||||
ASSERT_EQ(expected, ac.toString());
|
||||
|
@ -1125,7 +1139,22 @@ TEST(TestIRac, Issue1513) {
|
|||
stdAc::swingh_t::kOff, // Horizontal swing
|
||||
true); // Light
|
||||
ac._irsend.makeDecodeResult();
|
||||
// All sent, we assume the above works. Just need to switch to swing off now.
|
||||
EXPECT_EQ(121, ac._irsend.capture.rawlen);
|
||||
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
|
||||
ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG"
|
||||
ASSERT_EQ(kLgBits, ac._irsend.capture.bits);
|
||||
ASSERT_EQ(
|
||||
"Model: 2 (AKB75215403), Power: On, Mode: 4 (Heat), Temp: 26C, "
|
||||
"Fan: 0 (Quiet)",
|
||||
IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
|
||||
// The next should be a SwingV On.
|
||||
EXPECT_TRUE(capture.decodeLG(&ac._irsend.capture, 61));
|
||||
ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG"
|
||||
ASSERT_EQ(kLgBits, ac._irsend.capture.bits);
|
||||
EXPECT_EQ(kLgAcSwingVSwing, ac._irsend.capture.value);
|
||||
ASSERT_EQ("Model: 3 (AKB74955603), Swing(V): 20 (Swing)",
|
||||
IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
ac._irsend.reset();
|
||||
ac.stateReset();
|
||||
ac.send();
|
||||
|
@ -1163,6 +1192,79 @@ TEST(TestIRac, Issue1513) {
|
|||
IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
}
|
||||
|
||||
// Ref:
|
||||
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1651#issuecomment-952811720
|
||||
TEST(TestIRac, Issue1651) {
|
||||
// Simulate sending a state with a SwingV off, then followed by a SwingV Auto.
|
||||
IRLgAc ac(kGpioUnused);
|
||||
IRac irac(kGpioUnused);
|
||||
IRrecv capture(kGpioUnused);
|
||||
ac.begin();
|
||||
// IRhvac {"Vendor":"LG2","Model":3,"Mode":"Auto","Power":"On","Celsius":"On",
|
||||
// "Temp":15,"FanSpeed":"Auto","SwingV":"Off","SwingH":"Off",
|
||||
// "Quiet":"Off","Turbo":"Off","Econo":"Off","Light":"On",
|
||||
// "Filter":"Off","Clean":"Off","Beep":"Off","Sleep":-1}
|
||||
ac._irsend.reset();
|
||||
irac.lg(&ac,
|
||||
lg_ac_remote_model_t::AKB74955603, // Model
|
||||
true, // Power
|
||||
stdAc::opmode_t::kAuto, // Mode
|
||||
15, // Degrees C (Note: 16C is min)
|
||||
stdAc::fanspeed_t::kAuto, // Fan speed
|
||||
stdAc::swingv_t::kOff, // Vertical swing
|
||||
stdAc::swingv_t::kOff, // Vertical swing (previous)
|
||||
stdAc::swingh_t::kOff, // Horizontal swing
|
||||
true); // Light
|
||||
ac._irsend.makeDecodeResult();
|
||||
// As we are not making a change of the SwingV state, there should only be
|
||||
// one message. (i.e. 60 + 1)
|
||||
EXPECT_EQ(61, ac._irsend.capture.rawlen);
|
||||
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
|
||||
ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG"
|
||||
ASSERT_EQ(kLgBits, ac._irsend.capture.bits);
|
||||
ASSERT_EQ(
|
||||
"Model: 2 (AKB75215403), Power: On, Mode: 3 (Auto), Temp: 16C, "
|
||||
"Fan: 5 (Auto)",
|
||||
IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
ac._irsend.reset();
|
||||
ac.stateReset();
|
||||
ac.send();
|
||||
// IRhvac {"Vendor":"LG2","Model":3,"Mode":"Auto","Power":"On","Celsius":"On",
|
||||
// "Temp":15,"FanSpeed":"Max","SwingV":"Auto","SwingH":"Off",
|
||||
// "Quiet":"Off","Turbo":"Off","Econo":"Off","Light":"On",
|
||||
// "Filter":"Off","Clean":"Off","Beep":"Off","Sleep":-1}
|
||||
ac._irsend.makeDecodeResult();
|
||||
ac._irsend.reset();
|
||||
irac.lg(&ac,
|
||||
lg_ac_remote_model_t::AKB74955603, // Model
|
||||
true, // Power
|
||||
stdAc::opmode_t::kAuto, // Mode
|
||||
15, // Degrees C (Note: 16C is min)
|
||||
stdAc::fanspeed_t::kMax, // Fan speed
|
||||
stdAc::swingv_t::kAuto, // Vertical swing
|
||||
stdAc::swingv_t::kOff, // Vertical swing (previous)
|
||||
stdAc::swingh_t::kOff, // Horizontal swing
|
||||
true); // Light
|
||||
ac._irsend.makeDecodeResult();
|
||||
// There should only be two messages.
|
||||
EXPECT_EQ(121, ac._irsend.capture.rawlen);
|
||||
// First message should be normal.
|
||||
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
|
||||
ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG"
|
||||
ASSERT_EQ(kLgBits, ac._irsend.capture.bits);
|
||||
ASSERT_EQ(
|
||||
"Model: 2 (AKB75215403), Power: On, Mode: 3 (Auto), Temp: 16C, "
|
||||
"Fan: 4 (Maximum)",
|
||||
IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
// The next should be a SwingV Off.
|
||||
EXPECT_TRUE(capture.decodeLG(&ac._irsend.capture, 61));
|
||||
ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG"
|
||||
ASSERT_EQ(kLgBits, ac._irsend.capture.bits);
|
||||
EXPECT_EQ(kLgAcSwingVSwing, ac._irsend.capture.value);
|
||||
ASSERT_EQ("Model: 3 (AKB74955603), Swing(V): 20 (Swing)",
|
||||
IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
}
|
||||
|
||||
TEST(TestIRac, LG2_AKB73757604) {
|
||||
IRLgAc ac(kGpioUnused);
|
||||
IRac irac(kGpioUnused);
|
||||
|
@ -1252,6 +1354,62 @@ TEST(TestIRac, Midea) {
|
|||
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
|
||||
}
|
||||
|
||||
TEST(TestIRac, Mirage) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
IRac irac(kGpioUnused);
|
||||
IRrecv capture(kGpioUnused);
|
||||
stdAc::state_t state, r, p;
|
||||
const char expected_KKG9AC1[] =
|
||||
"Model: 1 (KKG9AC1), Power: On, Mode: 3 (Dry), Temp: 27C, "
|
||||
"Fan: 2 (Medium), Turbo: Off, Sleep: On, Light: Off, "
|
||||
"Swing(V): 9 (High), Clock: 17:31";
|
||||
|
||||
ac.begin();
|
||||
|
||||
state.model = mirage_ac_remote_model_t::KKG9AC1;
|
||||
state.power = true;
|
||||
state.mode = stdAc::opmode_t::kDry;
|
||||
state.celsius = true;
|
||||
state.degrees = 27;
|
||||
state.fanspeed = stdAc::fanspeed_t::kMedium;
|
||||
state.swingv = stdAc::swingv_t::kHigh;
|
||||
state.swingh = stdAc::swingh_t::kLeft;
|
||||
state.turbo = false;
|
||||
state.quiet = true;
|
||||
state.light = false;
|
||||
state.filter = true;
|
||||
state.clean = false;
|
||||
state.sleep = 8 * 60 + 0;
|
||||
state.clock = 17 * 60 + 31;
|
||||
state.beep = false;
|
||||
irac.mirage(&ac, state);
|
||||
|
||||
ASSERT_EQ(expected_KKG9AC1, ac.toString());
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
|
||||
ASSERT_EQ(MIRAGE, ac._irsend.capture.decode_type);
|
||||
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));
|
||||
|
||||
const char expected_KKG29AC1[] =
|
||||
"Model: 2 (KKG29AC1), Power: On, Mode: 3 (Dry), Temp: 27C, "
|
||||
"Fan: 3 (Medium), Turbo: Off, Sleep: On, Quiet: On, Light: -, "
|
||||
"Swing(V): On, Swing(H): On, Filter: On, Clean: -, "
|
||||
"On Timer: Off, Off Timer: Off, IFeel: Off";
|
||||
ac._irsend.reset();
|
||||
state.model = mirage_ac_remote_model_t::KKG29AC1;
|
||||
irac.mirage(&ac, state);
|
||||
ASSERT_EQ(expected_KKG29AC1, ac.toString());
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
|
||||
ASSERT_EQ(MIRAGE, ac._irsend.capture.decode_type);
|
||||
ASSERT_EQ(kMirageBits, ac._irsend.capture.bits);
|
||||
ASSERT_EQ(expected_KKG29AC1,
|
||||
IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
|
||||
}
|
||||
|
||||
TEST(TestIRac, Mitsubishi) {
|
||||
IRMitsubishiAC ac(kGpioUnused);
|
||||
IRac irac(kGpioUnused);
|
||||
|
@ -1493,9 +1651,10 @@ TEST(TestIRac, Samsung) {
|
|||
IRSamsungAc ac(kGpioUnused);
|
||||
IRac irac(kGpioUnused);
|
||||
IRrecv capture(kGpioUnused);
|
||||
char expected[] =
|
||||
"Power: On, Mode: 0 (Auto), Temp: 28C, Fan: 6 (Auto), Swing: On, "
|
||||
"Beep: On, Clean: On, Quiet: On, Powerful: Off, Breeze: Off, "
|
||||
const char expected[] =
|
||||
"Power: On, Mode: 0 (Auto), Temp: 28C, Fan: 6 (Auto), "
|
||||
"Swing(V): On, Swing(H): On, Beep: Toggle, "
|
||||
"Clean: Toggle, Quiet: On, Powerful: Off, ""Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off";
|
||||
|
||||
ac.begin();
|
||||
|
@ -1505,14 +1664,18 @@ TEST(TestIRac, Samsung) {
|
|||
28, // Celsius
|
||||
stdAc::fanspeed_t::kMedium, // Fan speed
|
||||
stdAc::swingv_t::kAuto, // Vertical swing
|
||||
stdAc::swingh_t::kAuto, // Horizontal swing
|
||||
true, // Quiet
|
||||
false, // Turbo
|
||||
false, // Econo
|
||||
true, // Light (Display)
|
||||
false, // Filter (Ion)
|
||||
true, // Clean
|
||||
true, // Clean (Toggle)
|
||||
true, // Beep
|
||||
-1, // Sleep
|
||||
true, // Previous power state
|
||||
false); // with dopower Off
|
||||
-1, // Previous Sleep
|
||||
false); // Force Extended
|
||||
ASSERT_EQ(expected, ac.toString());
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
|
||||
|
@ -1529,22 +1692,59 @@ TEST(TestIRac, Samsung) {
|
|||
28, // Celsius
|
||||
stdAc::fanspeed_t::kMedium, // Fan speed
|
||||
stdAc::swingv_t::kAuto, // Vertical swing
|
||||
stdAc::swingh_t::kAuto, // Horizontal swing
|
||||
true, // Quiet
|
||||
false, // Turbo
|
||||
false, // Econo
|
||||
true, // Light (Display)
|
||||
false, // Filter (Ion)
|
||||
true, // Clean
|
||||
true, // Clean (Toggle)
|
||||
true, // Beep
|
||||
-1, // Sleep
|
||||
true, // Previous power state
|
||||
true); // with dopower On
|
||||
-1, // Previous Sleep
|
||||
true); // Force Extended
|
||||
ASSERT_EQ(expected, ac.toString()); // Class should be in the desired mode.
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
|
||||
ASSERT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
|
||||
// We expect an extended state because of `dopower`.
|
||||
// We expect an extended state because of `Force Extended`.
|
||||
ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
|
||||
ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
|
||||
|
||||
ac._irsend.reset();
|
||||
const char sleep[] =
|
||||
"Power: On, Mode: 0 (Auto), Temp: 28C, Fan: 6 (Auto), "
|
||||
"Swing(V): On, Swing(H): Off, Beep: -, Clean: Toggle, "
|
||||
"Quiet: On, Powerful: Off, Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off, Sleep Timer: 08:00";
|
||||
irac.samsung(&ac,
|
||||
true, // Power
|
||||
stdAc::opmode_t::kAuto, // Mode
|
||||
28, // Celsius
|
||||
stdAc::fanspeed_t::kMedium, // Fan speed
|
||||
stdAc::swingv_t::kAuto, // Vertical swing
|
||||
stdAc::swingh_t::kOff, // Horizontal swing
|
||||
true, // Quiet
|
||||
false, // Turbo
|
||||
false, // Econo
|
||||
true, // Light (Display)
|
||||
false, // Filter (Ion)
|
||||
true, // Clean (Toggle)
|
||||
false, // Beep
|
||||
8 * 60, // Sleep
|
||||
true, // Previous power state
|
||||
-1, // Previous Sleep
|
||||
false); // Force Extended
|
||||
ASSERT_EQ(sleep, ac.toString());
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(capture.decode(&ac._irsend.capture));
|
||||
ASSERT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
|
||||
// We expect an extended state because of the change in `sleep`.
|
||||
ASSERT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
|
||||
ASSERT_EQ(sleep, IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p));
|
||||
}
|
||||
|
||||
TEST(TestIRac, Sanyo) {
|
||||
|
@ -1610,7 +1810,7 @@ TEST(TestIRac, Sharp) {
|
|||
IRrecv capture(kGpioUnused);
|
||||
char expected[] =
|
||||
"Model: 1 (A907), Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium), "
|
||||
"Turbo: Off, Swing(V) Toggle: On, Ion: On, Econo: -, Clean: Off";
|
||||
"Swing(V): 7 (Swing), Turbo: Off, Ion: On, Econo: -, Clean: Off";
|
||||
|
||||
ac.begin();
|
||||
irac.sharp(&ac,
|
||||
|
@ -1621,6 +1821,7 @@ TEST(TestIRac, Sharp) {
|
|||
28, // Celsius
|
||||
stdAc::fanspeed_t::kMedium, // Fan speed
|
||||
stdAc::swingv_t::kAuto, // Vertical swing
|
||||
stdAc::swingv_t::kOff, // Previous Vertical swing
|
||||
false, // Turbo
|
||||
false, // Light
|
||||
true, // Filter (Ion)
|
||||
|
@ -1640,12 +1841,14 @@ TEST(TestIRac, Tcl112) {
|
|||
IRac irac(kGpioUnused);
|
||||
IRrecv capture(kGpioUnused);
|
||||
char expected[] =
|
||||
"Type: 1, Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 3 (Medium), "
|
||||
"Econo: On, Health: On, Turbo: Off, Swing(H): On, Swing(V): Off, "
|
||||
"Light: On";
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 20C, "
|
||||
"Fan: 3 (Medium), Swing(V): 0 (Auto), Swing(H): On, "
|
||||
"Econo: On, Health: On, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off";
|
||||
|
||||
ac.begin();
|
||||
irac.tcl112(&ac,
|
||||
tcl_ac_remote_model_t::TAC09CHSD, // Model
|
||||
true, // Power
|
||||
stdAc::opmode_t::kCool, // Mode
|
||||
20, // Celsius
|
||||
|
@ -1668,6 +1871,7 @@ TEST(TestIRac, Tcl112) {
|
|||
// Test the quiet mode, which should generate two messages.
|
||||
ac._irsend.reset();
|
||||
irac.tcl112(&ac,
|
||||
tcl_ac_remote_model_t::TAC09CHSD, // Model
|
||||
true, // Power
|
||||
stdAc::opmode_t::kCool, // Mode
|
||||
20, // Celsius
|
||||
|
@ -1684,7 +1888,7 @@ TEST(TestIRac, Tcl112) {
|
|||
ASSERT_EQ(TCL112AC, ac._irsend.capture.decode_type);
|
||||
ASSERT_EQ(kTcl112AcBits, ac._irsend.capture.bits);
|
||||
ASSERT_EQ(
|
||||
"Type: 2, Quiet: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 2, Quiet: On",
|
||||
IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
// TCL112 uses the Mitsubishi112 decoder.
|
||||
// Skip first message.
|
||||
|
@ -2335,6 +2539,10 @@ TEST(TestIRac, opmodeToString) {
|
|||
EXPECT_EQ("Auto", IRac::opmodeToString(stdAc::opmode_t::kAuto));
|
||||
EXPECT_EQ("Cool", IRac::opmodeToString(stdAc::opmode_t::kCool));
|
||||
EXPECT_EQ("UNKNOWN", IRac::opmodeToString((stdAc::opmode_t)500));
|
||||
// Home Assistant/Google Home differences.
|
||||
EXPECT_EQ("Fan", IRac::opmodeToString(stdAc::opmode_t::kFan, false));
|
||||
EXPECT_EQ("fan_only", IRac::opmodeToString(stdAc::opmode_t::kFan, true));
|
||||
EXPECT_EQ("Fan", IRac::opmodeToString(stdAc::opmode_t::kFan)); // Default
|
||||
}
|
||||
|
||||
TEST(TestIRac, fanspeedToString) {
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
# make [all] - makes everything.
|
||||
# make TARGET - makes the given target.
|
||||
# make run - makes everything and runs all the tests.
|
||||
# make run_tests - run all tests
|
||||
# make run-% - run specific test file (exclude _test.cpp)
|
||||
# replace % with given test file, eg run-IRsend
|
||||
# make clean - removes all files generated by make.
|
||||
# make install-googletest - install the googletest code suite
|
||||
|
||||
|
@ -45,6 +48,7 @@ clean :
|
|||
run : all
|
||||
failed=""; \
|
||||
for unittest in $(TESTS); do \
|
||||
echo "RUNNING: $${unittest}"; \
|
||||
./$${unittest} || failed="$${failed} $${unittest}"; \
|
||||
done; \
|
||||
if [ -n "$${failed}" ]; then \
|
||||
|
@ -55,6 +59,10 @@ run : all
|
|||
|
||||
run_tests : run
|
||||
|
||||
run-% : %_test
|
||||
echo "RUNNING: $*"; \
|
||||
./$*_test
|
||||
|
||||
install-googletest :
|
||||
rm -rf ../lib/googletest
|
||||
git clone -b v1.8.x https://github.com/google/googletest.git ../lib/googletest
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright 2021 crankyoldgit
|
||||
|
||||
#include "IRac.h"
|
||||
#include "IRrecv.h"
|
||||
#include "IRrecv_test.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRsend_test.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
// Tests for decodeAirton().
|
||||
|
||||
TEST(TestDecodeAirton, RealExample) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
const uint16_t rawData[115] = {
|
||||
6632, 3352,
|
||||
404, 1266, 404, 1264, 406, 430, 406, 430, 400, 1264, 406, 430, 402, 1264,
|
||||
408, 1262, 406, 1264, 404, 430, 402, 434, 402, 432, 402, 1264, 406, 430,
|
||||
404, 432, 400, 456, 376, 432, 402, 430, 402, 1264, 404, 1264, 404, 432,
|
||||
402, 434, 398, 434, 402, 430, 404, 1264, 404, 432, 402, 430, 404, 1264,
|
||||
406, 430, 402, 432, 400, 434, 402, 430, 402, 430, 404, 432, 402, 430,
|
||||
402, 432, 402, 432, 402, 430, 402, 432, 402, 430, 402, 434, 400, 432,
|
||||
402, 1264, 404, 430, 404, 1264, 404, 432, 402, 454, 378, 432, 402, 430,
|
||||
404, 1264, 404, 1264, 404, 1264, 378, 1292, 404, 432, 402, 1264, 404, 432,
|
||||
402};
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendRaw(rawData, 115, 38);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
ASSERT_EQ(decode_type_t::AIRTON, irsend.capture.decode_type);
|
||||
ASSERT_EQ(kAirtonBits, irsend.capture.bits);
|
||||
EXPECT_EQ(0x5E1400090C11D3, irsend.capture.value);
|
||||
EXPECT_EQ(0x0, irsend.capture.address);
|
||||
EXPECT_EQ(0x0, irsend.capture.command);
|
||||
}
|
||||
|
||||
TEST(TestDecodeAirton, SyntheticExample) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendAirton(0x5E1400090C11D3);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
ASSERT_EQ(decode_type_t::AIRTON, irsend.capture.decode_type);
|
||||
ASSERT_EQ(kAirtonBits, irsend.capture.bits);
|
||||
EXPECT_EQ(0x5E1400090C11D3, irsend.capture.value);
|
||||
EXPECT_EQ(0x0, irsend.capture.address);
|
||||
EXPECT_EQ(0x0, irsend.capture.command);
|
||||
}
|
||||
|
||||
TEST(TestUtils, Housekeeping) {
|
||||
ASSERT_EQ("AIRTON", typeToString(decode_type_t::AIRTON));
|
||||
ASSERT_EQ(decode_type_t::AIRTON, strToDecodeType("AIRTON"));
|
||||
ASSERT_FALSE(hasACState(decode_type_t::AIRTON));
|
||||
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::AIRTON));
|
||||
ASSERT_EQ(kAirtonBits, IRsend::defaultBits(decode_type_t::AIRTON));
|
||||
ASSERT_EQ(kAirtonDefaultRepeat, IRsend::minRepeats(decode_type_t::AIRTON));
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
// Copyright 2021 David Conran
|
||||
|
||||
#include "IRac.h"
|
||||
#include "IRrecv.h"
|
||||
#include "IRrecv_test.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRsend_test.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
// Tests for decodeArris().
|
||||
|
||||
// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1595
|
||||
// Data from:
|
||||
// https://github.com/crankyoldgit/IRremoteESP8266/files/7100289/raw_data.txt
|
||||
TEST(TestDecodeArris, RealExample) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
|
||||
const uint16_t rawData_1[59] = {
|
||||
2584, 1896, 666, 306, 338, 300, 336, 304, 668, 610, 332, 306, 338, 300,
|
||||
334, 304, 332, 312, 332, 306, 340, 300, 334, 304, 330, 308, 338, 302, 334,
|
||||
304, 330, 308, 336, 308, 336, 302, 332, 306, 330, 310, 674, 606, 336, 302,
|
||||
332, 306, 338, 306, 668, 612, 668, 306, 338, 304, 332, 308, 336, 608,
|
||||
334}; // UNKNOWN EDF1C0D0
|
||||
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendRaw(rawData_1, 59, 38);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
ASSERT_EQ(decode_type_t::ARRIS, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kArrisBits, irsend.capture.bits);
|
||||
EXPECT_EQ(0x1000085E, irsend.capture.value);
|
||||
EXPECT_EQ(0x0, irsend.capture.address);
|
||||
EXPECT_EQ(0x85, irsend.capture.command);
|
||||
|
||||
irsend.reset();
|
||||
const uint16_t rawData_2[115] = {
|
||||
2584, 1898, 664, 308, 338, 302, 332, 306, 668, 614, 330, 308, 336, 302,
|
||||
332, 306, 340, 304, 330, 310, 336, 304, 332, 306, 338, 300, 334, 304, 330,
|
||||
308, 336, 302, 332, 312, 334, 306, 330, 308, 336, 302, 670, 610, 332, 306,
|
||||
330, 310, 336, 308, 674, 606, 664, 312, 334, 306, 338, 302, 334, 612, 330,
|
||||
5930,
|
||||
2584, 1898, 664, 308, 336, 302, 332, 306, 666, 614, 338, 300, 336, 304,
|
||||
332, 310, 674, 610, 332, 334, 312, 328, 308, 332, 304, 336, 310, 330, 306,
|
||||
332, 302, 314, 330, 336, 308, 330, 306, 334, 640, 612, 330, 308, 336, 302,
|
||||
332, 312, 672, 608, 672, 608, 672, 304, 330, 614, 330
|
||||
}; // UNKNOWN E6A77D83
|
||||
irsend.sendRaw(rawData_2, 115, 38);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
ASSERT_EQ(decode_type_t::ARRIS, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kArrisBits, irsend.capture.bits);
|
||||
EXPECT_EQ(0x1000085E, irsend.capture.value);
|
||||
EXPECT_EQ(0x0, irsend.capture.address);
|
||||
EXPECT_EQ(0x85, irsend.capture.command);
|
||||
|
||||
const uint16_t rawData_3[51] = {
|
||||
2584, 1896, 666, 308, 338, 328, 306, 332, 640, 612, 332, 336, 310, 300,
|
||||
334, 304, 678, 606, 336, 330, 306, 334, 310, 300, 334, 304, 332, 308, 338,
|
||||
302, 334, 310, 672, 304, 332, 614, 668, 612, 330, 336, 638, 620, 670, 610,
|
||||
670, 304, 330, 310, 336, 610, 672}; // UNKNOWN 4CA048A1
|
||||
irsend.reset();
|
||||
irsend.sendRaw(rawData_3, 51, 38);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
ASSERT_EQ(decode_type_t::ARRIS, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kArrisBits, irsend.capture.bits);
|
||||
EXPECT_EQ(0x1080695D, irsend.capture.value);
|
||||
EXPECT_EQ(0x1, irsend.capture.address);
|
||||
EXPECT_EQ(0x695, irsend.capture.command);
|
||||
}
|
||||
|
||||
TEST(TestDecodeArris, SyntheticExample) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendArris(0x1000085E);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
EXPECT_TRUE(irrecv.decode(&irsend.capture));
|
||||
EXPECT_EQ(decode_type_t::ARRIS, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kArrisBits, irsend.capture.bits);
|
||||
EXPECT_EQ(0x1000085E, irsend.capture.value);
|
||||
EXPECT_EQ(0x0, irsend.capture.address);
|
||||
EXPECT_EQ(0x85, irsend.capture.command);
|
||||
|
||||
EXPECT_EQ(
|
||||
"f38000d50"
|
||||
// const uint16_t rawData_1[59] = {
|
||||
// 2584, 1896,
|
||||
"m2560s1920"
|
||||
// 666, 306,
|
||||
"m640s320"
|
||||
// 338, 300,
|
||||
"m320s320"
|
||||
// 336, 304,
|
||||
"m320s320"
|
||||
// 668, 610,
|
||||
"m640s640"
|
||||
// 332, 306,
|
||||
"m320s320"
|
||||
// 338, 300,
|
||||
"m320s320"
|
||||
// 334, 304,
|
||||
"m320s320"
|
||||
// 332, 312,
|
||||
"m320s320"
|
||||
// 332, 306,
|
||||
"m320s320"
|
||||
// 340, 300,
|
||||
"m320s320"
|
||||
// 334, 304,
|
||||
"m320s320"
|
||||
// 330, 308,
|
||||
"m320s320"
|
||||
// 338, 302,
|
||||
"m320s320"
|
||||
// 334, 304,
|
||||
"m320s320"
|
||||
// 330, 308,
|
||||
"m320s320"
|
||||
// 336, 308,
|
||||
"m320s320"
|
||||
// 336, 302,
|
||||
"m320s320"
|
||||
// 332, 306,
|
||||
"m320s320"
|
||||
// 330, 310,
|
||||
"m320s320"
|
||||
// 674, 606,
|
||||
"m640s640"
|
||||
// 336, 302,
|
||||
"m320s320"
|
||||
// 332, 306,
|
||||
"m320s320"
|
||||
// 338, 306,
|
||||
"m320s320"
|
||||
// 668, 612,
|
||||
"m640s640"
|
||||
// 668, 306,
|
||||
"m640s320"
|
||||
// 338, 304,
|
||||
"m320s320"
|
||||
// 332, 308,
|
||||
"m320s320"
|
||||
// 336, 608,
|
||||
"m320s640"
|
||||
// 334}; // UNKNOWN EDF1C0D0
|
||||
"m320s77184", irsend.outputStr());
|
||||
|
||||
irsend.reset();
|
||||
irsend.sendArris(0x1080695D);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
EXPECT_TRUE(irrecv.decode(&irsend.capture));
|
||||
EXPECT_EQ(decode_type_t::ARRIS, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kArrisBits, irsend.capture.bits);
|
||||
EXPECT_EQ(0x1080695D, irsend.capture.value);
|
||||
EXPECT_EQ(0x1, irsend.capture.address);
|
||||
EXPECT_EQ(0x695, irsend.capture.command);
|
||||
}
|
||||
|
||||
TEST(TestUtils, Housekeeping) {
|
||||
ASSERT_EQ("ARRIS", typeToString(decode_type_t::ARRIS));
|
||||
ASSERT_EQ(decode_type_t::ARRIS, strToDecodeType("ARRIS"));
|
||||
ASSERT_FALSE(hasACState(decode_type_t::ARRIS));
|
||||
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::ARRIS));
|
||||
ASSERT_EQ(kArrisBits, IRsend::defaultBits(decode_type_t::ARRIS));
|
||||
ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::ARRIS));
|
||||
}
|
||||
|
||||
TEST(TestSendArris, ReleaseToggle) {
|
||||
EXPECT_EQ(0x10800F5D, IRsend::toggleArrisRelease(0x10000F55));
|
||||
EXPECT_EQ(0x10000F55, IRsend::toggleArrisRelease(0x10800F5D));
|
||||
EXPECT_EQ(
|
||||
0x10800F5D,
|
||||
IRsend::toggleArrisRelease(IRsend::toggleArrisRelease(0x10800F5D)));
|
||||
}
|
||||
|
||||
TEST(TestSendArris, encodeArris) {
|
||||
EXPECT_EQ(0x10800F5D, IRsend::encodeArris(0xF5, true));
|
||||
EXPECT_EQ(0x10000F55, IRsend::encodeArris(0xF5, false));
|
||||
EXPECT_EQ(0x1080695D, IRsend::encodeArris(0x695, true));
|
||||
}
|
|
@ -101,7 +101,8 @@ TEST(TestDecodeElectraAC, RealExampleDecode) {
|
|||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off",
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
|
@ -235,7 +236,8 @@ TEST(TestIRElectraAcClass, HumanReadable) {
|
|||
ac.setRaw(on_cool_32C_auto_voff);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 32C, Fan: 5 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off",
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
ac.toString());
|
||||
uint8_t on_cool_16C_auto_voff[13] = {
|
||||
0xC3, 0x47, 0xE0, 0x00, 0xA0, 0x00, 0x20,
|
||||
|
@ -243,7 +245,8 @@ TEST(TestIRElectraAcClass, HumanReadable) {
|
|||
ac.setRaw(on_cool_16C_auto_voff);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 5 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off",
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
ac.toString());
|
||||
uint8_t on_cool_16C_low_voff[13] = {
|
||||
0xC3, 0x47, 0xE0, 0x00, 0x60, 0x00, 0x20,
|
||||
|
@ -251,7 +254,8 @@ TEST(TestIRElectraAcClass, HumanReadable) {
|
|||
ac.setRaw(on_cool_16C_low_voff);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off",
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -275,7 +279,8 @@ TEST(TestIRElectraAcClass, Clean) {
|
|||
ac.setRaw(on);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off",
|
||||
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -301,7 +306,8 @@ TEST(TestIRElectraAcClass, Turbo) {
|
|||
ac.setRaw(on);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: On",
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: On, "
|
||||
"IFeel: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -325,7 +331,8 @@ TEST(TestIRElectraAcClass, LightToggle) {
|
|||
ac.setRaw(on);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off",
|
||||
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -352,8 +359,76 @@ TEST(TestIRElectraAcClass, ConstructKnownState) {
|
|||
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off",
|
||||
"Swing(V): Off, Swing(H): Off, Light: Toggle, Clean: On, Turbo: Off, "
|
||||
"IFeel: Off",
|
||||
ac.toString());
|
||||
EXPECT_STATE_EQ(on_cool_24C_fan1_swing_off_turbo_off_clean_on,
|
||||
ac.getRaw(), kElectraAcBits);
|
||||
}
|
||||
|
||||
TEST(TestIRElectraAcClass, IFeelAndSensor) {
|
||||
IRElectraAc ac(kGpioUnused);
|
||||
ac.stateReset();
|
||||
// Test a real example.
|
||||
const uint8_t ifeel_on[kElectraAcStateLength] = {
|
||||
0xC3, 0x6F, 0xE0, 0x00, 0xA0, 0x00, 0x28,
|
||||
0x64, 0x00, 0x20, 0x00, 0x1E, 0x7C};
|
||||
ac.setRaw(ifeel_on);
|
||||
EXPECT_TRUE(ac.getIFeel());
|
||||
EXPECT_EQ(26, ac.getSensorTemp());
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 5 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: On, Sensor Temp: 26C",
|
||||
ac.toString());
|
||||
|
||||
ac.stateReset();
|
||||
EXPECT_FALSE(ac.getIFeel());
|
||||
EXPECT_EQ(kElectraAcSensorMinTemp, ac.getSensorTemp());
|
||||
|
||||
ac.setIFeel(true);
|
||||
EXPECT_TRUE(ac.getIFeel());
|
||||
EXPECT_EQ(kElectraAcSensorMinTemp, ac.getSensorTemp());
|
||||
|
||||
ac.setSensorTemp(kElectraAcSensorMaxTemp);
|
||||
EXPECT_EQ(kElectraAcSensorMaxTemp, ac.getSensorTemp());
|
||||
|
||||
ac.setSensorTemp(kElectraAcSensorMaxTemp + 1);
|
||||
EXPECT_EQ(kElectraAcSensorMaxTemp, ac.getSensorTemp());
|
||||
|
||||
ac.setIFeel(false);
|
||||
EXPECT_FALSE(ac.getIFeel());
|
||||
EXPECT_EQ(kElectraAcSensorMinTemp, ac.getSensorTemp());
|
||||
EXPECT_EQ(0, ac._.SensorTemp);
|
||||
|
||||
ac.setIFeel(true);
|
||||
ac.setSensorTemp(kElectraAcSensorMinTemp);
|
||||
EXPECT_TRUE(ac.getIFeel());
|
||||
EXPECT_EQ(kElectraAcSensorMinTemp, ac.getSensorTemp());
|
||||
|
||||
ac.setSensorTemp(26); // Celsius
|
||||
EXPECT_TRUE(ac.getIFeel());
|
||||
EXPECT_EQ(26, ac.getSensorTemp());
|
||||
|
||||
EXPECT_FALSE(ac.getSensorUpdate());
|
||||
ac.setSensorUpdate(true);
|
||||
EXPECT_TRUE(ac.getSensorUpdate());
|
||||
EXPECT_EQ("Sensor Temp: 26C", ac.toString());
|
||||
ac.setSensorUpdate(false);
|
||||
EXPECT_FALSE(ac.getSensorUpdate());
|
||||
|
||||
const uint8_t sensor_update_28C[kElectraAcStateLength] = {
|
||||
0xC3, 0x9F, 0xE0, 0x40, 0xA0, 0x00, 0x88,
|
||||
0x66, 0x00, 0x30, 0x00, 0x1E, 0x5E};
|
||||
ac.setRaw(sensor_update_28C);
|
||||
EXPECT_TRUE(ac.getSensorUpdate());
|
||||
EXPECT_EQ(28, ac.getSensorTemp());
|
||||
EXPECT_EQ("Sensor Temp: 28C", ac.toString());
|
||||
ac.setSensorUpdate(false);
|
||||
EXPECT_FALSE(ac.getSensorUpdate());
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 4 (Heat), Temp: 27C, Fan: 5 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, Light: -, Clean: Off, Turbo: Off, "
|
||||
"IFeel: On, Sensor Temp: 28C",
|
||||
ac.toString());
|
||||
}
|
||||
|
|
|
@ -303,9 +303,10 @@ TEST(TestGreeClass, Temperature) {
|
|||
EXPECT_EQ(63, ac.getTemp());
|
||||
EXPECT_EQ(
|
||||
"Model: 2 (YBOFB), Power: On, Mode: 1 (Cool), Temp: 63F, Fan: 0 (Auto), "
|
||||
"Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, "
|
||||
"Swing(V) Mode: Manual, Swing(V): 0 (Last), Timer: Off, "
|
||||
"Display Temp: 0 (Off)", ac.toString());
|
||||
"Turbo: Off, Econo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, "
|
||||
"Sleep: Off, "
|
||||
"Swing(V) Mode: Manual, Swing(V): 0 (Last), Swing(H): 0 (Off), "
|
||||
"Timer: Off, Display Temp: 0 (Off)", ac.toString());
|
||||
}
|
||||
|
||||
TEST(TestGreeClass, OperatingMode) {
|
||||
|
@ -385,6 +386,20 @@ TEST(TestGreeClass, Turbo) {
|
|||
EXPECT_TRUE(ac.getTurbo());
|
||||
}
|
||||
|
||||
TEST(TestGreeClass, Econo) {
|
||||
IRGreeAC ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setEcono(true);
|
||||
EXPECT_TRUE(ac.getEcono());
|
||||
|
||||
ac.setEcono(false);
|
||||
EXPECT_FALSE(ac.getEcono());
|
||||
|
||||
ac.setEcono(true);
|
||||
EXPECT_TRUE(ac.getEcono());
|
||||
}
|
||||
|
||||
TEST(TestGreeClass, IFeel) {
|
||||
IRGreeAC ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
@ -506,6 +521,24 @@ TEST(TestGreeClass, VerticalSwing) {
|
|||
EXPECT_EQ(kGreeSwingAuto, ac.getSwingVerticalPosition());
|
||||
}
|
||||
|
||||
TEST(TestGreeClass, HorizontalSwing) {
|
||||
IRGreeAC ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setSwingHorizontal(kGreeSwingHAuto);
|
||||
EXPECT_EQ(kGreeSwingHAuto, ac.getSwingHorizontal());
|
||||
|
||||
ac.setSwingHorizontal(kGreeSwingHMiddle);
|
||||
EXPECT_EQ(kGreeSwingHMiddle, ac.getSwingHorizontal());
|
||||
|
||||
ac.setSwingHorizontal(kGreeSwingHMaxRight);
|
||||
EXPECT_EQ(kGreeSwingHMaxRight, ac.getSwingHorizontal());
|
||||
|
||||
// Out of bounds.
|
||||
ac.setSwingHorizontal(kGreeSwingHMaxRight + 1);
|
||||
EXPECT_EQ(kGreeSwingHOff, ac.getSwingHorizontal());
|
||||
}
|
||||
|
||||
TEST(TestGreeClass, SetAndGetRaw) {
|
||||
IRGreeAC ac(kGpioUnused);
|
||||
uint8_t initialState[kGreeStateLength] = {0x00, 0x09, 0x20, 0x50,
|
||||
|
@ -543,8 +576,9 @@ TEST(TestGreeClass, HumanReadable) {
|
|||
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (YAW1F), Power: Off, Mode: 0 (Auto), Temp: 25C, Fan: 0 (Auto), "
|
||||
"Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, "
|
||||
"Swing(V) Mode: Manual, Swing(V): 0 (Last), "
|
||||
"Turbo: Off, Econo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, "
|
||||
"Sleep: Off, "
|
||||
"Swing(V) Mode: Manual, Swing(V): 0 (Last), Swing(H): 0 (Off), "
|
||||
"Timer: Off, Display Temp: 0 (Off)",
|
||||
ac.toString());
|
||||
ac.on();
|
||||
|
@ -562,9 +596,10 @@ TEST(TestGreeClass, HumanReadable) {
|
|||
ac.setDisplayTempSource(3);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (YAW1F), Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 3 (High), "
|
||||
"Turbo: On, IFeel: On, WiFi: On, XFan: On, Light: Off, Sleep: On, "
|
||||
"Swing(V) Mode: Auto, Swing(V): 1 (Auto), Timer: 12:30, "
|
||||
"Display Temp: 3 (Outside)",
|
||||
"Turbo: On, Econo: Off, IFeel: On, WiFi: On, XFan: On, Light: Off, "
|
||||
"Sleep: On, "
|
||||
"Swing(V) Mode: Auto, Swing(V): 1 (Auto), Swing(H): 0 (Off), "
|
||||
"Timer: 12:30, Display Temp: 3 (Outside)",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -623,9 +658,10 @@ TEST(TestDecodeGree, NormalRealExample) {
|
|||
ac.setRaw(irsend.capture.state);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (YAW1F), Power: On, Mode: 1 (Cool), Temp: 26C, Fan: 1 (Low), "
|
||||
"Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, "
|
||||
"Swing(V) Mode: Manual, Swing(V): 2 (UNKNOWN), Timer: Off, "
|
||||
"Display Temp: 3 (Outside)",
|
||||
"Turbo: Off, Econo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, "
|
||||
"Sleep: Off, "
|
||||
"Swing(V) Mode: Manual, Swing(V): 2 (UNKNOWN), Swing(H): 0 (Off), "
|
||||
"Timer: Off, Display Temp: 3 (Outside)",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
|
@ -681,8 +717,9 @@ TEST(TestGreeClass, Issue814Power) {
|
|||
EXPECT_EQ(gree_ac_remote_model_t::YBOFB, ac.getModel());
|
||||
EXPECT_EQ(
|
||||
"Model: 2 (YBOFB), Power: On, Mode: 1 (Cool), Temp: 23C, Fan: 1 (Low), "
|
||||
"Turbo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, Sleep: Off, "
|
||||
"Swing(V) Mode: Auto, Swing(V): 1 (Auto), Timer: Off, "
|
||||
"Turbo: Off, Econo: Off, IFeel: Off, WiFi: Off, XFan: Off, Light: On, "
|
||||
"Sleep: Off, "
|
||||
"Swing(V) Mode: Auto, Swing(V): 1 (Auto), Swing(H): 0 (Off), Timer: Off, "
|
||||
"Display Temp: 0 (Off)",
|
||||
ac.toString());
|
||||
ac.off();
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,6 @@
|
|||
// Copyright 2020 David Conran
|
||||
// Copyright 2020-2021 David Conran
|
||||
|
||||
#include "ir_Mirage.h"
|
||||
#include "IRac.h"
|
||||
#include "IRrecv.h"
|
||||
#include "IRrecv_test.h"
|
||||
|
@ -11,7 +12,7 @@ TEST(TestUtils, Housekeeping) {
|
|||
ASSERT_EQ("MIRAGE", typeToString(decode_type_t::MIRAGE));
|
||||
ASSERT_EQ(decode_type_t::MIRAGE, strToDecodeType("MIRAGE"));
|
||||
ASSERT_TRUE(hasACState(decode_type_t::MIRAGE));
|
||||
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::MIRAGE));
|
||||
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::MIRAGE));
|
||||
ASSERT_EQ(kMirageBits, IRsend::defaultBits(decode_type_t::MIRAGE));
|
||||
ASSERT_EQ(kMirageMinRepeat, IRsend::minRepeats(decode_type_t::MIRAGE));
|
||||
}
|
||||
|
@ -55,7 +56,9 @@ TEST(TestDecodeMirage, RealExample) {
|
|||
ASSERT_EQ(kMirageBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"",
|
||||
"Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 25C, "
|
||||
"Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, "
|
||||
"Swing(V): 0 (Off), Clock: 14:16",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
}
|
||||
|
||||
|
@ -70,13 +73,14 @@ TEST(TestDecodeMirage, SyntheticExample) {
|
|||
irsend.sendMirage(expected);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
ASSERT_EQ(decode_type_t::MIRAGE, irsend.capture.decode_type);
|
||||
ASSERT_EQ(kMirageBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"",
|
||||
"Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 25C, "
|
||||
"Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, "
|
||||
"Swing(V): 0 (Off), Clock: 14:16",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
}
|
||||
|
||||
|
@ -119,6 +123,469 @@ TEST(TestDecodeMirage, RealExampleWithDodgyHardwareCapture) {
|
|||
ASSERT_EQ(kMirageBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"",
|
||||
"Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 25C, "
|
||||
"Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, "
|
||||
"Swing(V): 0 (Off), Clock: 14:16",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, Power) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1);
|
||||
ac.on();
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
ac.on();
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
|
||||
ac.off();
|
||||
EXPECT_FALSE(ac.getPower());
|
||||
ac.off();
|
||||
EXPECT_FALSE(ac.getPower());
|
||||
|
||||
ac.setPower(true);
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
|
||||
ac.setPower(false);
|
||||
EXPECT_FALSE(ac.getPower());
|
||||
|
||||
const uint8_t on[kMirageStateLength] = {
|
||||
0x56, 0x75, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x16, 0x14, 0x26};
|
||||
ac.setRaw(on);
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
const uint8_t off[kMirageStateLength] = {
|
||||
0x56, 0x6C, 0x00, 0x00, 0x21, 0xD8, 0x00, 0x00,
|
||||
0x0C, 0x00, 0x0C, 0x2C, 0x23, 0x01, 0x61};
|
||||
ac.setRaw(off);
|
||||
EXPECT_FALSE(ac.getPower());
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1);
|
||||
ac.on();
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
ac.off();
|
||||
EXPECT_FALSE(ac.getPower());
|
||||
ac.setPower(true);
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
ac.setPower(false);
|
||||
EXPECT_FALSE(ac.getPower());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, OperatingMode) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setMode(kMirageAcCool);
|
||||
EXPECT_EQ(kMirageAcCool, ac.getMode());
|
||||
ac.setMode(kMirageAcHeat);
|
||||
EXPECT_EQ(kMirageAcHeat, ac.getMode());
|
||||
ac.setMode(kMirageAcDry);
|
||||
EXPECT_EQ(kMirageAcDry, ac.getMode());
|
||||
ac.setMode(kMirageAcFan);
|
||||
EXPECT_EQ(kMirageAcFan, ac.getMode());
|
||||
ac.setMode(kMirageAcRecycle);
|
||||
EXPECT_EQ(kMirageAcRecycle, ac.getMode());
|
||||
ac.setMode(255);
|
||||
EXPECT_EQ(kMirageAcCool, ac.getMode());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, HumanReadable) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
// Tests for the KKG9AC1 model.
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 16C, "
|
||||
"Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, "
|
||||
"Swing(V): 13 (Auto), Clock: 00:00",
|
||||
ac.toString());
|
||||
// Ref: https://docs.google.com/spreadsheets/d/1Ucu9mOOIIJoWQjUJq_VCvwgV3EwKaRk8K2AuZgccYEk/edit#gid=0&range=C7
|
||||
// 0x56710000201A00000C000C26010041
|
||||
const uint8_t cool_21c_auto[kMirageStateLength] = {
|
||||
0x56, 0x71, 0x00, 0x00, 0x20, 0x1A, 0x00, 0x00,
|
||||
0x0C, 0x00, 0x0C, 0x26, 0x01, 0x00, 0x41};
|
||||
ac.setRaw(cool_21c_auto);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 21C, "
|
||||
"Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, "
|
||||
"Swing(V): 13 (Auto), Clock: 00:01",
|
||||
ac.toString());
|
||||
|
||||
const uint8_t SyntheticExample[kMirageStateLength] = {
|
||||
0x56, 0x75, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x16, 0x14, 0x26};
|
||||
ac.setRaw(SyntheticExample);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (KKG9AC1), Power: On, Mode: 2 (Cool), Temp: 25C, "
|
||||
"Fan: 0 (Auto), Turbo: Off, Sleep: Off, Light: Off, "
|
||||
"Swing(V): 0 (Off), Clock: 14:16",
|
||||
ac.toString());
|
||||
|
||||
// Tests for the KKG29AC1 model.
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1);
|
||||
EXPECT_EQ(
|
||||
"Model: 2 (KKG29AC1), Power: On, Mode: 2 (Cool), Temp: 25C, "
|
||||
"Fan: 0 (Auto), Turbo: Off, Sleep: Off, Quiet: Off, Light: -, "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Filter: Off, Clean: -, On Timer: Off, Off Timer: Off, "
|
||||
"IFeel: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, Temperature) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setTemp(0);
|
||||
EXPECT_EQ(kMirageAcMinTemp, ac.getTemp());
|
||||
|
||||
ac.setTemp(255);
|
||||
EXPECT_EQ(kMirageAcMaxTemp, ac.getTemp());
|
||||
|
||||
ac.setTemp(kMirageAcMinTemp);
|
||||
EXPECT_EQ(kMirageAcMinTemp, ac.getTemp());
|
||||
|
||||
ac.setTemp(kMirageAcMaxTemp);
|
||||
EXPECT_EQ(kMirageAcMaxTemp, ac.getTemp());
|
||||
|
||||
ac.setTemp(kMirageAcMinTemp - 1);
|
||||
EXPECT_EQ(kMirageAcMinTemp, ac.getTemp());
|
||||
|
||||
ac.setTemp(kMirageAcMaxTemp + 1);
|
||||
EXPECT_EQ(kMirageAcMaxTemp, ac.getTemp());
|
||||
|
||||
ac.setTemp(17);
|
||||
EXPECT_EQ(17, ac.getTemp());
|
||||
|
||||
ac.setTemp(21);
|
||||
EXPECT_EQ(21, ac.getTemp());
|
||||
|
||||
ac.setTemp(25);
|
||||
EXPECT_EQ(25, ac.getTemp());
|
||||
|
||||
ac.setTemp(30);
|
||||
EXPECT_EQ(30, ac.getTemp());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, FanSpeed) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setFan(kMirageAcFanAuto);
|
||||
EXPECT_EQ(kMirageAcFanAuto, ac.getFan());
|
||||
ac.setFan(kMirageAcFanLow);
|
||||
EXPECT_EQ(kMirageAcFanLow, ac.getFan());
|
||||
ac.setFan(kMirageAcFanMed);
|
||||
EXPECT_EQ(kMirageAcFanMed, ac.getFan());
|
||||
ac.setFan(kMirageAcFanHigh);
|
||||
EXPECT_EQ(kMirageAcFanHigh, ac.getFan());
|
||||
|
||||
ac.setFan(255);
|
||||
EXPECT_EQ(kMirageAcFanAuto, ac.getFan());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, Turbo) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1);
|
||||
ac.setTurbo(true);
|
||||
EXPECT_TRUE(ac.getTurbo());
|
||||
ac.setTurbo(false);
|
||||
EXPECT_FALSE(ac.getTurbo());
|
||||
ac.setTurbo(true);
|
||||
EXPECT_TRUE(ac.getTurbo());
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1);
|
||||
ac.setTurbo(true);
|
||||
EXPECT_TRUE(ac.getTurbo());
|
||||
ac.setTurbo(false);
|
||||
EXPECT_FALSE(ac.getTurbo());
|
||||
ac.setTurbo(true);
|
||||
EXPECT_TRUE(ac.getTurbo());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, Light) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1);
|
||||
ac.setLight(true);
|
||||
EXPECT_TRUE(ac.getLight());
|
||||
ac.setLight(false);
|
||||
EXPECT_FALSE(ac.getLight());
|
||||
ac.setLight(true);
|
||||
EXPECT_TRUE(ac.getLight());
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1);
|
||||
ac.setLight(true);
|
||||
EXPECT_TRUE(ac.getLight());
|
||||
ac.setLight(false);
|
||||
EXPECT_FALSE(ac.getLight());
|
||||
ac.setLight(true);
|
||||
EXPECT_TRUE(ac.getLight());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, Sleep) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1);
|
||||
ac.setSleep(true);
|
||||
EXPECT_TRUE(ac.getSleep());
|
||||
ac.setSleep(false);
|
||||
EXPECT_FALSE(ac.getSleep());
|
||||
ac.setSleep(true);
|
||||
EXPECT_TRUE(ac.getSleep());
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1);
|
||||
ac.setSleep(true);
|
||||
EXPECT_TRUE(ac.getSleep());
|
||||
ac.setSleep(false);
|
||||
EXPECT_FALSE(ac.getSleep());
|
||||
ac.setSleep(true);
|
||||
EXPECT_TRUE(ac.getSleep());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, Clock) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // This model supports time.
|
||||
ac.setClock(0);
|
||||
EXPECT_EQ(0, ac.getClock());
|
||||
ac.setClock(12 * 60 * 60 + 30 * 60 + 59); // aka. 12:30:59
|
||||
EXPECT_EQ(12 * 60 * 60 + 30 * 60 + 59, ac.getClock());
|
||||
ac.setClock(23 * 60 * 60 + 59 * 60 + 59); // aka. 23:59:59
|
||||
EXPECT_EQ(23 * 60 * 60 + 59 * 60 + 59, ac.getClock());
|
||||
ac.setClock(24 * 60 * 60); // aka. 24:00:00
|
||||
EXPECT_EQ(23 * 60 * 60 + 59 * 60 + 59, ac.getClock()); // aka. 23:59:59
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1); // This model has no clock.
|
||||
EXPECT_EQ(0, ac.getClock());
|
||||
ac.setClock(12 * 60 * 60 + 30 * 60 + 59); // aka. 12:30:59
|
||||
EXPECT_EQ(0, ac.getClock());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, Checksums) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
const uint8_t SyntheticExample[kMirageStateLength] = {
|
||||
0x56, 0x75, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x16, 0x14, 0x26};
|
||||
EXPECT_TRUE(IRMirageAc::validChecksum(SyntheticExample));
|
||||
EXPECT_EQ(0x26, IRMirageAc::calculateChecksum(SyntheticExample));
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, SwingV) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
// Set the model to one with full swingv support.
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1);
|
||||
|
||||
ac.setSwingV(kMirageAcSwingVAuto);
|
||||
EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV());
|
||||
|
||||
ac.setSwingV(kMirageAcSwingVHigh);
|
||||
EXPECT_EQ(kMirageAcSwingVHigh, ac.getSwingV());
|
||||
|
||||
ac.setSwingV(0xFF);
|
||||
EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV());
|
||||
|
||||
ac.setSwingV(kMirageAcSwingVLowest);
|
||||
EXPECT_EQ(kMirageAcSwingVLowest, ac.getSwingV());
|
||||
|
||||
ac.setSwingV(kMirageAcSwingVLowest - 1);
|
||||
EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV());
|
||||
|
||||
// Set the model to one with limited swingv support.
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1);
|
||||
|
||||
ac.setSwingV(kMirageAcSwingVAuto);
|
||||
EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV());
|
||||
ac.setSwingV(kMirageAcSwingVOff);
|
||||
EXPECT_EQ(kMirageAcSwingVOff, ac.getSwingV());
|
||||
ac.setSwingV(kMirageAcSwingVHigh);
|
||||
EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV());
|
||||
ac.setSwingV(0xFF);
|
||||
EXPECT_EQ(kMirageAcSwingVAuto, ac.getSwingV());
|
||||
ac.setSwingV(kMirageAcSwingVOff);
|
||||
EXPECT_EQ(kMirageAcSwingVOff, ac.getSwingV());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, SwingH) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1);
|
||||
ac.setSwingH(true);
|
||||
EXPECT_FALSE(ac.getSwingH());
|
||||
ac.setSwingH(false);
|
||||
EXPECT_FALSE(ac.getSwingH());
|
||||
ac.setSwingH(true);
|
||||
EXPECT_FALSE(ac.getSwingH());
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1);
|
||||
ac.setSwingH(true);
|
||||
EXPECT_TRUE(ac.getSwingH());
|
||||
ac.setSwingH(false);
|
||||
EXPECT_FALSE(ac.getSwingH());
|
||||
ac.setSwingH(true);
|
||||
EXPECT_TRUE(ac.getSwingH());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, Filter) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // No Support
|
||||
ac.setFilter(true);
|
||||
EXPECT_FALSE(ac.getFilter());
|
||||
ac.setFilter(false);
|
||||
EXPECT_FALSE(ac.getFilter());
|
||||
ac.setFilter(true);
|
||||
EXPECT_FALSE(ac.getFilter());
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1); // Supported
|
||||
ac.setFilter(true);
|
||||
EXPECT_TRUE(ac.getFilter());
|
||||
ac.setFilter(false);
|
||||
EXPECT_FALSE(ac.getFilter());
|
||||
ac.setFilter(true);
|
||||
EXPECT_TRUE(ac.getFilter());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, Quiet) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // No Support
|
||||
ac.setQuiet(true);
|
||||
EXPECT_FALSE(ac.getQuiet());
|
||||
ac.setQuiet(false);
|
||||
EXPECT_FALSE(ac.getQuiet());
|
||||
ac.setQuiet(true);
|
||||
EXPECT_FALSE(ac.getQuiet());
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1); // Supported
|
||||
ac.setQuiet(true);
|
||||
EXPECT_TRUE(ac.getQuiet());
|
||||
ac.setQuiet(false);
|
||||
EXPECT_FALSE(ac.getQuiet());
|
||||
ac.setQuiet(true);
|
||||
EXPECT_TRUE(ac.getQuiet());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, CleanToggle) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1);
|
||||
ac.setCleanToggle(true);
|
||||
EXPECT_FALSE(ac.getCleanToggle());
|
||||
ac.setCleanToggle(false);
|
||||
EXPECT_FALSE(ac.getCleanToggle());
|
||||
ac.setCleanToggle(true);
|
||||
EXPECT_FALSE(ac.getCleanToggle());
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1);
|
||||
ac.setCleanToggle(true);
|
||||
EXPECT_TRUE(ac.getCleanToggle());
|
||||
ac.setCleanToggle(false);
|
||||
EXPECT_FALSE(ac.getCleanToggle());
|
||||
ac.setCleanToggle(true);
|
||||
EXPECT_TRUE(ac.getCleanToggle());
|
||||
ac.send(); // Should be reset when sent.
|
||||
EXPECT_FALSE(ac.getCleanToggle());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, Timers) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // No timer support
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
ac.setOnTimer(12 * 60 + 37); // 12:37
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
ac.setOffTimer(17 * 60 + 5); // 17:05
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1); // Timer supported
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setOnTimer(12 * 60 + 37); // 12:37
|
||||
EXPECT_EQ(12 * 60 + 37, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setOffTimer(17 * 60 + 5); // 17:05
|
||||
EXPECT_EQ(17 * 60 + 5, ac.getOffTimer());
|
||||
EXPECT_EQ(12 * 60 + 37, ac.getOnTimer());
|
||||
ac.setOnTimer(0); // Off/Disabled
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(17 * 60 + 5, ac.getOffTimer());
|
||||
ac.setOffTimer(0); // Off/Disabled
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
|
||||
ac.setOnTimer(12 * 60 + 37); // 12:37
|
||||
ac.setOffTimer(17 * 60 + 5); // 17:05
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // No timer support
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, IFeelAndSensorTemp) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG9AC1); // No support
|
||||
EXPECT_FALSE(ac.getIFeel());
|
||||
EXPECT_EQ(0, ac.getSensorTemp());
|
||||
ac.setIFeel(true);
|
||||
EXPECT_FALSE(ac.getIFeel());
|
||||
EXPECT_EQ(0, ac.getSensorTemp());
|
||||
ac.setSensorTemp(20); // 20C
|
||||
EXPECT_FALSE(ac.getIFeel());
|
||||
EXPECT_EQ(0, ac.getSensorTemp());
|
||||
|
||||
ac.setModel(mirage_ac_remote_model_t::KKG29AC1); // Supported
|
||||
EXPECT_FALSE(ac.getIFeel());
|
||||
EXPECT_EQ(0, ac.getSensorTemp());
|
||||
ac.setIFeel(true);
|
||||
EXPECT_TRUE(ac.getIFeel());
|
||||
EXPECT_EQ(0, ac.getSensorTemp());
|
||||
ac.setSensorTemp(25); // 25C
|
||||
EXPECT_TRUE(ac.getIFeel());
|
||||
EXPECT_EQ(25, ac.getSensorTemp());
|
||||
ac.setIFeel(false);
|
||||
EXPECT_FALSE(ac.getIFeel());
|
||||
}
|
||||
|
||||
TEST(TestMirageAcClass, getModel) {
|
||||
IRMirageAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
const uint8_t KKG9AC1[kMirageStateLength] = {
|
||||
0x56, 0x6C, 0x00, 0x00, 0x20, 0xD8, 0x00, 0x00,
|
||||
0x0C, 0x32, 0x0B, 0x00, 0x32, 0x0F, 0x64};
|
||||
EXPECT_EQ(mirage_ac_remote_model_t::KKG9AC1, IRMirageAc::getModel(KKG9AC1));
|
||||
|
||||
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1573#issuecomment-955722044
|
||||
const uint8_t KKG29AC1[kMirageStateLength] = {
|
||||
0x56, 0x74, 0x00, 0x00, 0x12, 0x00, 0x40, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1D};
|
||||
EXPECT_EQ(mirage_ac_remote_model_t::KKG29AC1, IRMirageAc::getModel(KKG29AC1));
|
||||
|
||||
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1573#issuecomment-962362540
|
||||
const uint8_t KKG29AC1_2[kMirageStateLength] = {
|
||||
0x56, 0x72, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19};
|
||||
EXPECT_EQ(mirage_ac_remote_model_t::KKG29AC1,
|
||||
IRMirageAc::getModel(KKG29AC1_2));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,396 @@
|
|||
// Copyright 2021 Tom Rosenback
|
||||
|
||||
#include "IRac.h"
|
||||
#include "ir_Rhoss.h"
|
||||
#include "IRrecv.h"
|
||||
#include "IRrecv_test.h"
|
||||
#include "IRsend.h"
|
||||
#include "IRsend_test.h"
|
||||
#include "IRutils.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(TestUtils, Housekeeping) {
|
||||
ASSERT_EQ("RHOSS", typeToString(decode_type_t::RHOSS));
|
||||
ASSERT_EQ(decode_type_t::RHOSS, strToDecodeType("RHOSS"));
|
||||
ASSERT_TRUE(hasACState(decode_type_t::RHOSS));
|
||||
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::RHOSS));
|
||||
}
|
||||
|
||||
// Test sending typical data only.
|
||||
TEST(TestSendRhoss, SendDataOnly) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
irsend.begin();
|
||||
|
||||
uint8_t expectedState[kRhossStateLength] = {
|
||||
0xAA, 0x05, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x33 };
|
||||
|
||||
irsend.reset();
|
||||
irsend.sendRhoss(expectedState);
|
||||
|
||||
EXPECT_EQ(
|
||||
"f38000d50"
|
||||
"m3042s4248"
|
||||
"m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457m648s1545"
|
||||
"m648s1545m648s457m648s1545m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s1545m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s1545m648s457m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s1545"
|
||||
"m648s457m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s1545m648s1545m648s457m648s457m648s1545m648s1545m648s457m648s457"
|
||||
"m648s457m648"
|
||||
"s100000",
|
||||
irsend.outputStr());
|
||||
}
|
||||
|
||||
// Test send typical data with repeats
|
||||
TEST(TestSendRhoss, SendWithRepeats) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
irsend.begin();
|
||||
|
||||
irsend.reset();
|
||||
|
||||
uint8_t expectedState[kRhossStateLength] = {
|
||||
0xAA, 0x05, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x33 };
|
||||
|
||||
irsend.sendRhoss(expectedState, kRhossStateLength, 0); // 0 repeats.
|
||||
EXPECT_EQ(
|
||||
"f38000d50"
|
||||
"m3042s4248"
|
||||
"m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457m648s1545"
|
||||
"m648s1545m648s457m648s1545m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s1545m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s1545m648s457m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s1545"
|
||||
"m648s457m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s1545m648s1545m648s457m648s457m648s1545m648s1545m648s457m648s457"
|
||||
"m648s457m648"
|
||||
"s100000",
|
||||
irsend.outputStr());
|
||||
|
||||
irsend.sendRhoss(expectedState, kRhossStateLength, 2); // 2 repeats.
|
||||
EXPECT_EQ(
|
||||
"f38000d50"
|
||||
"m3042s4248"
|
||||
"m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457m648s1545"
|
||||
"m648s1545m648s457m648s1545m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s1545m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s1545m648s457m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s1545"
|
||||
"m648s457m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s1545m648s1545m648s457m648s457m648s1545m648s1545m648s457m648s457"
|
||||
"m648s457m648"
|
||||
"s100000"
|
||||
"m3042s4248"
|
||||
"m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457m648s1545"
|
||||
"m648s1545m648s457m648s1545m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s1545m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s1545m648s457m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s1545"
|
||||
"m648s457m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s1545m648s1545m648s457m648s457m648s1545m648s1545m648s457m648s457"
|
||||
"m648s457m648"
|
||||
"s100000"
|
||||
"m3042s4248"
|
||||
"m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457m648s1545"
|
||||
"m648s1545m648s457m648s1545m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s1545m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s1545m648s457m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s1545"
|
||||
"m648s457m648s457m648s1545m648s457m648s1545m648s457m648s1545m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s457m648s457m648s457m648s457m648s457m648s457m648s457m648s457"
|
||||
"m648s1545m648s1545m648s457m648s457m648s1545m648s1545m648s457m648s457"
|
||||
"m648s457m648"
|
||||
"s100000",
|
||||
irsend.outputStr());
|
||||
}
|
||||
|
||||
// Test send raw data
|
||||
TEST(TestSendRhoss, RawData) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
|
||||
// Power on, mode cool, temp 20, fan auto, swing off
|
||||
const uint16_t rawData[197] = {
|
||||
3044, 4248,
|
||||
648, 458, 650, 1540, 646, 458, 650, 1538,
|
||||
650, 458, 650, 1538, 650, 458, 650, 1540, // byte 0
|
||||
648, 458, 650, 458, 650, 1540, 646, 484,
|
||||
624, 456, 650, 456, 650, 456, 650, 456, // byte 1
|
||||
650, 456, 650, 456, 650, 456, 650, 456,
|
||||
650, 458, 650, 1540, 650, 1538, 650, 456, // byte 2
|
||||
650, 456, 650, 456, 650, 456, 650, 458,
|
||||
650, 456, 650, 456, 650, 456, 650, 458, // byte 3
|
||||
650, 458, 650, 456, 650, 458, 650, 458,
|
||||
650, 458, 650, 1538, 650, 458, 650, 458, // byte 4
|
||||
650, 458, 648, 458, 674, 434, 648, 458,
|
||||
672, 434, 648, 458, 650, 458, 648, 1540, // byte 5
|
||||
672, 434, 650, 458, 672, 1518, 644, 488,
|
||||
622, 1540, 644, 464, 672, 1516, 672, 434, // byte 6
|
||||
672, 434, 672, 434, 650, 458, 648, 458,
|
||||
672, 434, 674, 434, 672, 434, 650, 458, // byte 7
|
||||
672, 434, 648, 458, 650, 458, 672, 434,
|
||||
672, 436, 648, 458, 648, 456, 650, 458, // byte 8
|
||||
650, 458, 650, 456, 674, 434, 650, 458,
|
||||
650, 456, 650, 458, 674, 432, 650, 458, // byte 9
|
||||
650, 456, 650, 456, 650, 458, 648, 458,
|
||||
674, 432, 650, 456, 674, 434, 650, 458, // byte 10
|
||||
650, 458, 650, 1538, 650, 458, 650, 458,
|
||||
650, 456, 650, 458, 650, 456, 650, 458, // byte 11
|
||||
650, 456,
|
||||
650 }; // UNKNOWN 93E7BDB2
|
||||
|
||||
irsend.sendRaw(rawData, 197, 38);
|
||||
irsend.makeDecodeResult();
|
||||
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
ASSERT_EQ(RHOSS, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kRhossBits, irsend.capture.bits);
|
||||
|
||||
uint8_t expected[kRhossStateLength] = {
|
||||
0xAA, 0x04, 0x60, 0x00, 0x20, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x02 };
|
||||
EXPECT_STATE_EQ(expected, irsend.capture.state, kRhossBits);
|
||||
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 2 (Cool), Temp: 20C, Fan: 0 (Auto), Swing(V): Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
}
|
||||
|
||||
// Test synthetic decode
|
||||
TEST(TestDecodeRhoss, SyntheticSelfDecode) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(0);
|
||||
IRRhossAc ac(0);
|
||||
|
||||
uint8_t expectedState[kRhossStateLength] = {
|
||||
0xAA, 0x05, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x33 };
|
||||
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendRhoss(expectedState);
|
||||
irsend.makeDecodeResult();
|
||||
ASSERT_TRUE(irrecv.decode(&irsend.capture));
|
||||
EXPECT_EQ(RHOSS, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kRhossBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
ac.setRaw(irsend.capture.state);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 5 (Auto), Temp: 21C, Fan: 0 (Auto), Swing(V): Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
// Test strict decoding
|
||||
TEST(TestDecodeRhoss, StrictDecode) {
|
||||
IRsendTest irsend(kGpioUnused);
|
||||
IRrecv irrecv(0);
|
||||
IRRhossAc ac(0);
|
||||
|
||||
uint8_t expectedState[kRhossStateLength] = {
|
||||
0xAA, 0x05, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x33 };
|
||||
|
||||
irsend.begin();
|
||||
irsend.reset();
|
||||
irsend.sendRhoss(expectedState);
|
||||
irsend.makeDecodeResult();
|
||||
ASSERT_TRUE(
|
||||
irrecv.decodeRhoss(&irsend.capture,
|
||||
kStartOffset, kRhossBits, true));
|
||||
EXPECT_EQ(RHOSS, irsend.capture.decode_type);
|
||||
EXPECT_EQ(kRhossBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
ac.setRaw(irsend.capture.state);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 5 (Auto), Temp: 21C, Fan: 0 (Auto), Swing(V): Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
// Tests for IRRhossAc class.
|
||||
|
||||
TEST(TestRhossAcClass, Power) {
|
||||
IRRhossAc ac(0);
|
||||
ac.begin();
|
||||
|
||||
ac.on();
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
|
||||
ac.off();
|
||||
EXPECT_FALSE(ac.getPower());
|
||||
|
||||
ac.setPower(true);
|
||||
EXPECT_TRUE(ac.getPower());
|
||||
|
||||
ac.setPower(false);
|
||||
EXPECT_FALSE(ac.getPower());
|
||||
}
|
||||
|
||||
TEST(TestRhossAcClass, Temperature) {
|
||||
IRRhossAc ac(0);
|
||||
ac.begin();
|
||||
|
||||
ac.setTemp(0);
|
||||
EXPECT_EQ(kRhossTempMin, ac.getTemp());
|
||||
|
||||
ac.setTemp(255);
|
||||
EXPECT_EQ(kRhossTempMax, ac.getTemp());
|
||||
|
||||
ac.setTemp(kRhossTempMin);
|
||||
EXPECT_EQ(kRhossTempMin, ac.getTemp());
|
||||
|
||||
ac.setTemp(kRhossTempMax);
|
||||
EXPECT_EQ(kRhossTempMax, ac.getTemp());
|
||||
|
||||
ac.setTemp(kRhossTempMin - 1);
|
||||
EXPECT_EQ(kRhossTempMin, ac.getTemp());
|
||||
|
||||
ac.setTemp(kRhossTempMax + 1);
|
||||
EXPECT_EQ(kRhossTempMax, ac.getTemp());
|
||||
|
||||
ac.setTemp(17);
|
||||
EXPECT_EQ(17, ac.getTemp());
|
||||
|
||||
ac.setTemp(21);
|
||||
EXPECT_EQ(21, ac.getTemp());
|
||||
|
||||
ac.setTemp(25);
|
||||
EXPECT_EQ(25, ac.getTemp());
|
||||
|
||||
ac.setTemp(29);
|
||||
EXPECT_EQ(29, ac.getTemp());
|
||||
}
|
||||
|
||||
|
||||
TEST(TestRhossAcClass, OperatingMode) {
|
||||
IRRhossAc ac(0);
|
||||
ac.begin();
|
||||
|
||||
ac.setMode(kRhossModeAuto);
|
||||
EXPECT_EQ(kRhossModeAuto, ac.getMode());
|
||||
|
||||
ac.setMode(kRhossModeCool);
|
||||
EXPECT_EQ(kRhossModeCool, ac.getMode());
|
||||
|
||||
ac.setMode(kRhossModeHeat);
|
||||
EXPECT_EQ(kRhossModeHeat, ac.getMode());
|
||||
|
||||
ac.setMode(kRhossModeDry);
|
||||
EXPECT_EQ(kRhossModeDry, ac.getMode());
|
||||
|
||||
ac.setMode(kRhossModeFan);
|
||||
EXPECT_EQ(kRhossModeFan, ac.getMode());
|
||||
|
||||
ac.setMode(kRhossModeAuto + 1);
|
||||
EXPECT_EQ(kRhossDefaultMode, ac.getMode());
|
||||
|
||||
ac.setMode(255);
|
||||
EXPECT_EQ(kRhossDefaultMode, ac.getMode());
|
||||
}
|
||||
|
||||
TEST(TestRhossAcClass, FanSpeed) {
|
||||
IRRhossAc ac(0);
|
||||
ac.begin();
|
||||
|
||||
ac.setFan(0);
|
||||
EXPECT_EQ(kRhossFanAuto, ac.getFan());
|
||||
|
||||
ac.setFan(255);
|
||||
EXPECT_EQ(kRhossFanAuto, ac.getFan());
|
||||
|
||||
ac.setFan(kRhossFanMax);
|
||||
EXPECT_EQ(kRhossFanMax, ac.getFan());
|
||||
|
||||
ac.setFan(kRhossFanMax + 1);
|
||||
EXPECT_EQ(kRhossFanAuto, ac.getFan());
|
||||
|
||||
ac.setFan(kRhossFanMax - 1);
|
||||
EXPECT_EQ(kRhossFanMax - 1, ac.getFan());
|
||||
|
||||
ac.setFan(1);
|
||||
EXPECT_EQ(1, ac.getFan());
|
||||
|
||||
ac.setFan(1);
|
||||
EXPECT_EQ(1, ac.getFan());
|
||||
|
||||
ac.setFan(3);
|
||||
EXPECT_EQ(3, ac.getFan());
|
||||
}
|
||||
|
||||
TEST(TestRhossAcClass, Swing) {
|
||||
IRRhossAc ac(0);
|
||||
ac.begin();
|
||||
|
||||
ac.setSwing(false);
|
||||
EXPECT_FALSE(ac.getSwing());
|
||||
|
||||
ac.setSwing(true);
|
||||
EXPECT_TRUE(ac.getSwing());
|
||||
}
|
||||
|
||||
TEST(TestRhossAcClass, Checksums) {
|
||||
uint8_t state[kRhossStateLength] = {
|
||||
0xAA, 0x05, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x33 };
|
||||
|
||||
ASSERT_EQ(0x33, IRRhossAc::calcChecksum(state));
|
||||
EXPECT_TRUE(IRRhossAc::validChecksum(state));
|
||||
// Change the array so the checksum is invalid.
|
||||
state[0] ^= 0xFF;
|
||||
EXPECT_FALSE(IRRhossAc::validChecksum(state));
|
||||
// Restore the previous change, and change another byte.
|
||||
state[0] ^= 0xFF;
|
||||
state[4] ^= 0xFF;
|
||||
EXPECT_FALSE(IRRhossAc::validChecksum(state));
|
||||
state[4] ^= 0xFF;
|
||||
EXPECT_TRUE(IRRhossAc::validChecksum(state));
|
||||
|
||||
// Additional known good states.
|
||||
uint8_t knownGood1[kRhossStateLength] = {
|
||||
0xAA, 0x06, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x34 };
|
||||
EXPECT_TRUE(IRRhossAc::validChecksum(knownGood1));
|
||||
ASSERT_EQ(0x34, IRRhossAc::calcChecksum(knownGood1));
|
||||
|
||||
uint8_t knownGood2[kRhossStateLength] = {
|
||||
0xAA, 0x07, 0x60, 0x00, 0x50, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x35 };
|
||||
EXPECT_TRUE(IRRhossAc::validChecksum(knownGood2));
|
||||
ASSERT_EQ(0x35, IRRhossAc::calcChecksum(knownGood2));
|
||||
|
||||
uint8_t knownGood3[kRhossStateLength] = {
|
||||
0xAA, 0x07, 0x60, 0x00, 0x53, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x38 };
|
||||
EXPECT_TRUE(IRRhossAc::validChecksum(knownGood3));
|
||||
ASSERT_EQ(0x38, IRRhossAc::calcChecksum(knownGood3));
|
||||
|
||||
// Validate calculation of checksum,
|
||||
// same as knownGood3 except for the checksum.
|
||||
uint8_t knownBad[kRhossStateLength] = {
|
||||
0xAA, 0x07, 0x60, 0x00, 0x53, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
EXPECT_FALSE(IRRhossAc::validChecksum(knownBad));
|
||||
IRRhossAc ac(0);
|
||||
ac.setRaw(knownBad);
|
||||
EXPECT_STATE_EQ(knownGood3, ac.getRaw(), kRhossBits);
|
||||
}
|
|
@ -426,16 +426,37 @@ TEST(TestIRSamsungAcClass, SetAndGetPower) {
|
|||
|
||||
TEST(TestIRSamsungAcClass, SetAndGetSwing) {
|
||||
IRSamsungAc ac(kGpioUnused);
|
||||
|
||||
// Vertical
|
||||
ac.setSwing(true);
|
||||
EXPECT_TRUE(ac.getSwing());
|
||||
EXPECT_FALSE(ac.getSwingH());
|
||||
ac.setSwing(false);
|
||||
EXPECT_FALSE(ac.getSwing());
|
||||
EXPECT_FALSE(ac.getSwingH());
|
||||
ac.setSwing(true);
|
||||
EXPECT_TRUE(ac.getSwing());
|
||||
EXPECT_FALSE(ac.getSwingH());
|
||||
// Horizontal
|
||||
ac.setSwingH(true);
|
||||
EXPECT_TRUE(ac.getSwing());
|
||||
EXPECT_TRUE(ac.getSwingH());
|
||||
ac.setSwingH(false);
|
||||
EXPECT_TRUE(ac.getSwing());
|
||||
EXPECT_FALSE(ac.getSwingH());
|
||||
ac.setSwingH(true);
|
||||
EXPECT_TRUE(ac.getSwing());
|
||||
EXPECT_TRUE(ac.getSwingH());
|
||||
|
||||
ac.setSwing(false);
|
||||
EXPECT_FALSE(ac.getSwing());
|
||||
EXPECT_TRUE(ac.getSwingH());
|
||||
ac.setSwingH(false);
|
||||
EXPECT_FALSE(ac.getSwing());
|
||||
EXPECT_FALSE(ac.getSwingH());
|
||||
|
||||
// Real examples from:
|
||||
// https://github.com/crankyoldgit/IRremoteESP8266/issues/505#issuecomment-424036602
|
||||
// TODO(Hollako): Explain why state[9] lowest bit changes between on and off.
|
||||
const uint8_t expected_off[kSamsungAcStateLength] = {
|
||||
0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
|
||||
0x01, 0xE2, 0xFE, 0x71, 0x80, 0x11, 0xF0};
|
||||
|
@ -576,14 +597,24 @@ TEST(TestIRSamsungAcClass, SetAndGetPowerful) {
|
|||
EXPECT_EQ(kSamsungAcFanTurbo, ac.getFan());
|
||||
ac.setPowerful(false);
|
||||
EXPECT_FALSE(ac.getPowerful());
|
||||
EXPECT_EQ(kSamsungAcFanAuto, ac.getFan());
|
||||
|
||||
// Breeze and Powerful/Turbo are mutually exclusive.
|
||||
// Breeze, Econo, and Powerful/Turbo are mutually exclusive.
|
||||
ac.setPowerful(true);
|
||||
EXPECT_TRUE(ac.getPowerful());
|
||||
EXPECT_FALSE(ac.getBreeze());
|
||||
EXPECT_FALSE(ac.getEcono());
|
||||
ac.setBreeze(true);
|
||||
EXPECT_TRUE(ac.getBreeze());
|
||||
EXPECT_FALSE(ac.getPowerful());
|
||||
EXPECT_FALSE(ac.getEcono());
|
||||
ac.setEcono(true);
|
||||
EXPECT_TRUE(ac.getEcono());
|
||||
EXPECT_FALSE(ac.getBreeze());
|
||||
EXPECT_FALSE(ac.getPowerful());
|
||||
ac.setPowerful(true);
|
||||
EXPECT_TRUE(ac.getPowerful());
|
||||
EXPECT_FALSE(ac.getBreeze());
|
||||
EXPECT_FALSE(ac.getEcono());
|
||||
|
||||
// Actual powerful on & off states from:
|
||||
// https://github.com/crankyoldgit/IRremoteESP8266/issues/734#issuecomment-500120270
|
||||
|
@ -594,9 +625,10 @@ TEST(TestIRSamsungAcClass, SetAndGetPowerful) {
|
|||
EXPECT_TRUE(ac.getPowerful());
|
||||
EXPECT_EQ(kSamsungAcFanTurbo, ac.getFan());
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 7 (Turbo), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: On, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 7 (Turbo), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: On, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
|
||||
uint8_t off[kSamsungAcStateLength] = {
|
||||
|
@ -606,9 +638,10 @@ TEST(TestIRSamsungAcClass, SetAndGetPowerful) {
|
|||
EXPECT_FALSE(ac.getPowerful());
|
||||
EXPECT_NE(kSamsungAcFanTurbo, ac.getFan());
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -633,6 +666,44 @@ TEST(TestIRSamsungAcClass, QuietAndPowerfulAreMutuallyExclusive) {
|
|||
EXPECT_NE(kSamsungAcFanTurbo, ac.getFan());
|
||||
}
|
||||
|
||||
TEST(TestIRSamsungAcClass, SetAndGetEcono) {
|
||||
IRSamsungAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
EXPECT_FALSE(ac.getEcono());
|
||||
ac.setFan(kSamsungAcFanMed);
|
||||
ac.setSwing(false);
|
||||
ac.setEcono(true);
|
||||
EXPECT_TRUE(ac.getEcono());
|
||||
EXPECT_FALSE(ac.getBreeze());
|
||||
EXPECT_FALSE(ac.getPowerful());
|
||||
EXPECT_TRUE(ac.getSwing()); // Econo turns on swingv.
|
||||
EXPECT_EQ(kSamsungAcFanAuto, ac.getFan()); // And sets the fan to Auto.
|
||||
ac.setEcono(false);
|
||||
EXPECT_FALSE(ac.getEcono());
|
||||
EXPECT_FALSE(ac.getBreeze());
|
||||
EXPECT_FALSE(ac.getPowerful());
|
||||
|
||||
// Breeze, Econo, and Powerful/Turbo are mutually exclusive.
|
||||
// But that is tested in `SetAndGetPowerful`
|
||||
|
||||
// Actual econo on state from:
|
||||
// https://cryptpad.fr/sheet/#/2/sheet/view/r9k8pmELYEjLyC71cD7EsThEYgKGLJygREZ5pVfNkS8/
|
||||
// Row: 33
|
||||
uint8_t on[kSamsungAcStateLength] = {
|
||||
0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
|
||||
0x01, 0xD2, 0xAE, 0x7F, 0x80, 0x11, 0xF0};
|
||||
ac.setRaw(on, kSamsungAcStateLength);
|
||||
EXPECT_TRUE(ac.getEcono());
|
||||
EXPECT_TRUE(ac.getSwing());
|
||||
EXPECT_EQ(kSamsungAcFanAuto, ac.getFan());
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), "
|
||||
"Swing(V): On, Swing(H): Off, Beep: -, Clean: -, "
|
||||
"Quiet: Off, Powerful: Off, Econo: On, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
TEST(TestIRSamsungAcClass, ChecksumCalculation) {
|
||||
IRSamsungAc ac(kGpioUnused);
|
||||
|
||||
|
@ -668,9 +739,10 @@ TEST(TestIRSamsungAcClass, ChecksumCalculation) {
|
|||
TEST(TestIRSamsungAcClass, HumanReadable) {
|
||||
IRSamsungAc ac(kGpioUnused);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), Swing: On, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), "
|
||||
"Swing(V): On, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, Econo: Off, "
|
||||
"Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
ac.setTemp(kSamsungAcMaxTemp);
|
||||
ac.setMode(kSamsungAcHeat);
|
||||
|
@ -680,28 +752,32 @@ TEST(TestIRSamsungAcClass, HumanReadable) {
|
|||
ac.setBeep(true);
|
||||
ac.setClean(true);
|
||||
EXPECT_EQ(
|
||||
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 5 (High), Swing: Off, "
|
||||
"Beep: On, Clean: On, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 5 (High), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: Toggle, Clean: Toggle, Quiet: Off, Powerful: Off, Econo: Off, "
|
||||
"Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
ac.setQuiet(true);
|
||||
EXPECT_EQ(
|
||||
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: On, Clean: On, Quiet: On, Powerful: Off, Breeze: Off, "
|
||||
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, Beep: Toggle, "
|
||||
"Clean: Toggle, Quiet: On, Powerful: Off, Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
ac.setQuiet(false);
|
||||
ac.setPowerful(true);
|
||||
EXPECT_EQ(
|
||||
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 7 (Turbo), Swing: Off, "
|
||||
"Beep: On, Clean: On, Quiet: Off, Powerful: On, Breeze: Off, "
|
||||
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 7 (Turbo), "
|
||||
"Swing(V): Off, Swing(H): Off, Beep: Toggle, "
|
||||
"Clean: Toggle, Quiet: Off, Powerful: On, Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
ac.setIon(true);
|
||||
ac.setDisplay(false);
|
||||
EXPECT_EQ(
|
||||
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 7 (Turbo), Swing: Off, "
|
||||
"Beep: On, Clean: On, Quiet: Off, Powerful: On, Breeze: Off, "
|
||||
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 7 (Turbo), "
|
||||
"Swing(V): Off, Swing(H): Off, Beep: Toggle, "
|
||||
"Clean: Toggle, Quiet: Off, Powerful: On, Econo: Off, Breeze: Off, "
|
||||
"Light: Off, Ion: On",
|
||||
ac.toString());
|
||||
}
|
||||
|
@ -802,9 +878,10 @@ TEST(TestDecodeSamsungAC, DecodeRealExample) {
|
|||
IRSamsungAc ac(kGpioUnused);
|
||||
ac.setRaw(irsend.capture.state);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), Swing: On, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), "
|
||||
"Swing(V): On, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -852,9 +929,10 @@ TEST(TestDecodeSamsungAC, DecodeRealExample2) {
|
|||
IRSamsungAc ac(kGpioUnused);
|
||||
ac.setRaw(irsend.capture.state);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -912,9 +990,10 @@ TEST(TestDecodeSamsungAC, DecodePowerOnSample) {
|
|||
IRSamsungAc ac(kGpioUnused);
|
||||
ac.setRaw(irsend.capture.state, kSamsungAcExtendedStateLength);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -973,9 +1052,10 @@ TEST(TestDecodeSamsungAC, DecodePowerOffSample) {
|
|||
IRSamsungAc ac(kGpioUnused);
|
||||
ac.setRaw(irsend.capture.state, kSamsungAcExtendedStateLength);
|
||||
EXPECT_EQ(
|
||||
"Power: Off, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: Off, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -1021,9 +1101,10 @@ TEST(TestDecodeSamsungAC, DecodeHeatSample) {
|
|||
IRSamsungAc ac(kGpioUnused);
|
||||
ac.setRaw(irsend.capture.state);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 4 (Heat), Temp: 17C, Fan: 0 (Auto), Swing: On, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 4 (Heat), Temp: 17C, Fan: 0 (Auto), "
|
||||
"Swing(V): On, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -1066,9 +1147,10 @@ TEST(TestDecodeSamsungAC, DecodeCoolSample) {
|
|||
EXPECT_EQ(kSamsungAcBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
|
@ -1127,9 +1209,10 @@ TEST(TestDecodeSamsungAC, Issue604DecodeExtended) {
|
|||
IRSamsungAc ac(kGpioUnused);
|
||||
ac.setRaw(irsend.capture.state, irsend.capture.bits / 8);
|
||||
EXPECT_EQ(
|
||||
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), "
|
||||
"Swing(V): On, Swing(H): On, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -1311,8 +1394,10 @@ TEST(TestIRSamsungAcClass, Issue604SendPowerHack) {
|
|||
"m586s436m586s436m586s436m586s436m586s436m586s436m586s436m586s436"
|
||||
"m586s2886";
|
||||
std::string text = "Power: On, Mode: 1 (Cool), Temp: 23C, Fan: 4 (Med), "
|
||||
"Swing: On, Beep: Off, Clean: Off, Quiet: Off, "
|
||||
"Powerful: Off, Breeze: Off, Light: On, Ion: Off";
|
||||
"Swing(V): On, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, "
|
||||
"Powerful: Off, Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off";
|
||||
// Don't do a setPower()/on()/off() as that will trigger the special message.
|
||||
// So it should only be the normal "settings" message.
|
||||
ac.setTemp(23);
|
||||
|
@ -1445,9 +1530,10 @@ TEST(TestDecodeSamsungAC, Issue734QuietSetting) {
|
|||
IRSamsungAc ac(0);
|
||||
ac.setRaw(irsend.capture.state, irsend.capture.bits / 8);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: On, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: On, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
|
||||
// Make sure the ac class state is in something wildly different first.
|
||||
|
@ -1468,9 +1554,10 @@ TEST(TestDecodeSamsungAC, Issue734QuietSetting) {
|
|||
ac.setClean(false);
|
||||
ac.setQuiet(true);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: On, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: On, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
// Check it matches the known good/expected state.
|
||||
EXPECT_STATE_EQ(expectedState, ac.getRaw(), kSamsungAcBits);
|
||||
|
@ -1519,9 +1606,10 @@ TEST(TestDecodeSamsungAC, Issue734PowerfulOff) {
|
|||
IRSamsungAc ac(0);
|
||||
ac.setRaw(irsend.capture.state, irsend.capture.bits / 8);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -1553,9 +1641,10 @@ TEST(TestIRSamsungAcClass, SetAndGetBreeze) {
|
|||
ac.setRaw(on);
|
||||
ASSERT_TRUE(ac.getBreeze());
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 3 (Fan), Temp: 24C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: On, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 3 (Fan), Temp: 24C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: On, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
// MODE FAN, 24C WINDFREE OFF, FAN = LOW
|
||||
const uint8_t off[14] = {
|
||||
|
@ -1564,9 +1653,10 @@ TEST(TestIRSamsungAcClass, SetAndGetBreeze) {
|
|||
ac.setRaw(off);
|
||||
ASSERT_FALSE(ac.getBreeze());
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 3 (Fan), Temp: 24C, Fan: 2 (Low), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off",
|
||||
"Power: On, Mode: 3 (Fan), Temp: 24C, Fan: 2 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -1614,9 +1704,10 @@ TEST(TestDecodeSamsungAC, Issue1227VeryPoorSignal) {
|
|||
EXPECT_EQ(kSamsungAcBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), Swing: Off, "
|
||||
"Beep: Off, Clean: Off, Quiet: Off, Powerful: Off, Breeze: Off, "
|
||||
"Light: Off, Ion: Off",
|
||||
"Power: On, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: Off, Ion: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
|
@ -1671,3 +1762,362 @@ TEST(TestIRSamsungAcClass, SectionChecksums) {
|
|||
EXPECT_EQ(IRSamsungAc::getSectionChecksum(extended_off + 14),
|
||||
IRSamsungAc::calcSectionChecksum(extended_off + 14));
|
||||
}
|
||||
|
||||
TEST(TestIRSamsungAcClass, Issue1648) {
|
||||
IRSamsungAc ac(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
const uint8_t onState[kSamsungAcExtendedStateLength] = {
|
||||
0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
|
||||
0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0xC2, 0xFE, 0x71, 0x90, 0x15, 0xF0};
|
||||
const String onText = "Power: On, Mode: 1 (Cool), Temp: 25C, Fan: 2 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, "
|
||||
"Powerful: Off, Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off";
|
||||
const uint8_t extended_offState[kSamsungAcExtendedStateLength] = {
|
||||
0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0,
|
||||
0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0xE2, 0xFE, 0x71, 0x90, 0x15, 0xC0};
|
||||
const uint8_t short_offState[kSamsungAcStateLength] = {
|
||||
0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0,
|
||||
0x01, 0xE2, 0xFE, 0x71, 0x90, 0x15, 0xC0};
|
||||
const String offText = "Power: Off, Mode: 1 (Cool), Temp: 25C, Fan: 2 (Low), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, "
|
||||
"Powerful: Off, Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off";
|
||||
const uint8_t coolState[kSamsungAcStateLength] = {
|
||||
0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
|
||||
0x01, 0xC2, 0xFE, 0x71, 0x90, 0x15, 0xF0};
|
||||
|
||||
// "setup()"" from provided code.
|
||||
ac.begin(); // User code
|
||||
ac.off(); // User code
|
||||
ac.setFan(kSamsungAcFanLow); // User code
|
||||
ac.setMode(kSamsungAcCool); // User code
|
||||
ac.setTemp(25); // User code
|
||||
ac.setSwing(false); // User code
|
||||
|
||||
// Go through "loop()" from provided code.
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
ac.on(); // User code
|
||||
ac.send(); // User code
|
||||
|
||||
// Verify what was sent.
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(irrecv.decode(&ac._irsend.capture));
|
||||
EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
|
||||
EXPECT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(onState, ac._irsend.capture.state, ac._irsend.capture.bits);
|
||||
EXPECT_EQ(onText, IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
EXPECT_TRUE(ac._lastsentpowerstate);
|
||||
ac._irsend.reset();
|
||||
|
||||
ac.setMode(kSamsungAcCool); // User code
|
||||
ac.send(); // User code
|
||||
|
||||
// Verify what was sent.
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(irrecv.decode(&ac._irsend.capture));
|
||||
EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
|
||||
EXPECT_EQ(kSamsungAcBits, ac._irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(coolState, ac._irsend.capture.state,
|
||||
ac._irsend.capture.bits);
|
||||
EXPECT_EQ(onText, IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
ac._irsend.reset();
|
||||
EXPECT_TRUE(ac._lastsentpowerstate);
|
||||
EXPECT_FALSE(ac._forceextended);
|
||||
|
||||
ac.off(); // User code
|
||||
ac.send(); // User code
|
||||
|
||||
// Verify what was sent.
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(irrecv.decode(&ac._irsend.capture));
|
||||
EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
|
||||
EXPECT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(extended_offState, ac._irsend.capture.state,
|
||||
ac._irsend.capture.bits);
|
||||
EXPECT_EQ(offText, IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
EXPECT_FALSE(ac._lastsentpowerstate);
|
||||
ac._irsend.reset();
|
||||
|
||||
ac.off(); // User code
|
||||
ac.send(); // User code
|
||||
|
||||
// Verify what was sent.
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(irrecv.decode(&ac._irsend.capture));
|
||||
EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
|
||||
EXPECT_EQ(kSamsungAcBits, ac._irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(short_offState, ac._irsend.capture.state,
|
||||
ac._irsend.capture.bits);
|
||||
EXPECT_EQ(offText, IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
EXPECT_FALSE(ac._lastsentpowerstate);
|
||||
ac._irsend.reset();
|
||||
// End of "loop()" code.
|
||||
}
|
||||
|
||||
// Data from https://github.com/crankyoldgit/IRremoteESP8266/issues/1648#issuecomment-950822399
|
||||
const uint8_t expectedState[kSamsungAcExtendedStateLength] = {
|
||||
0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0,
|
||||
0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x12, 0xAF, 0x71, 0x80, 0x15, 0xC0};
|
||||
const String expectedText = "Power: Off, Mode: 1 (Cool), Temp: 24C, "
|
||||
"Fan: 2 (Low), Swing(V): On, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, "
|
||||
"Quiet: Off, Powerful: Off, Econo: Off, "
|
||||
"Breeze: Off, Light: On, Ion: Off";
|
||||
|
||||
ac.stateReset();
|
||||
ac.setRaw(expectedState, kSamsungAcExtendedStateLength);
|
||||
EXPECT_EQ(expectedText, ac.toString());
|
||||
|
||||
// Try to generate the same message.
|
||||
ac.stateReset();
|
||||
ac.off();
|
||||
ac.setMode(kSamsungAcCool);
|
||||
ac.setTemp(24);
|
||||
ac.setFan(kSamsungAcFanLow);
|
||||
ac.setSwing(true);
|
||||
ac.setBeep(false);
|
||||
ac.setClean(false);
|
||||
ac.setQuiet(false);
|
||||
ac.setPowerful(false);
|
||||
ac.setBreeze(false);
|
||||
ac.setDisplay(true);
|
||||
ac.setIon(false);
|
||||
EXPECT_EQ(expectedText, ac.toString());
|
||||
|
||||
ac.send();
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(irrecv.decode(&ac._irsend.capture));
|
||||
EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
|
||||
EXPECT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, ac._irsend.capture.state,
|
||||
ac._irsend.capture.bits);
|
||||
EXPECT_EQ(expectedText, IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
ac._irsend.reset();
|
||||
}
|
||||
|
||||
TEST(TestIRSamsungAcClass, Timers) {
|
||||
IRSamsungAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
// https://github.com/crankyoldgit/IRremoteESP8266/issues/1277#issuecomment-961836703
|
||||
const uint8_t on_timer_30m[kSamsungAcExtendedStateLength] = {
|
||||
0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0,
|
||||
0x01, 0xA2, 0x0F, 0x30, 0x00, 0x02, 0x00,
|
||||
0x01, 0x02, 0xFF, 0x71, 0x40, 0x11, 0xC0};
|
||||
const uint8_t off_timer_1h_on_timer_10m[kSamsungAcExtendedStateLength] = {
|
||||
0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0,
|
||||
0x01, 0x92, 0x8F, 0x10, 0x00, 0x06, 0x00,
|
||||
0x01, 0x02, 0xFF, 0x71, 0x40, 0x11, 0xC0};
|
||||
const uint8_t off_timer_1h_on_timer_0m[kSamsungAcExtendedStateLength] = {
|
||||
0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0,
|
||||
0x01, 0xA2, 0x8F, 0x00, 0x00, 0x06, 0x00,
|
||||
0x01, 0x02, 0xFF, 0x71, 0x40, 0x11, 0xC0};
|
||||
|
||||
ac.setRaw(on_timer_30m, kSamsungAcExtendedStateLength);
|
||||
EXPECT_EQ(
|
||||
"Power: Off, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, Light: On, Ion: Off, On Timer: 00:30",
|
||||
ac.toString());
|
||||
ac.setRaw(off_timer_1h_on_timer_10m, kSamsungAcExtendedStateLength);
|
||||
EXPECT_EQ(
|
||||
"Power: Off, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off, On Timer: 00:10, Off Timer: 01:00",
|
||||
ac.toString());
|
||||
ac.setRaw(off_timer_1h_on_timer_0m, kSamsungAcExtendedStateLength);
|
||||
EXPECT_EQ(
|
||||
"Power: Off, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off, On Timer: 00:00, Off Timer: 01:00",
|
||||
ac.toString());
|
||||
|
||||
// https://cryptpad.fr/sheet/#/2/sheet/view/r9k8pmELYEjLyC71cD7EsThEYgKGLJygREZ5pVfNkS8/
|
||||
// Row 155
|
||||
const uint8_t off_timer_11h_on_timer_6h[kSamsungAcExtendedStateLength] = {
|
||||
0x02, 0xB2, 0x0F, 0x00, 0x00, 0x00, 0xC0,
|
||||
0x01, 0x62, 0x8F, 0x05, 0x03, 0x06, 0x00,
|
||||
0x01, 0x02, 0xFF, 0x71, 0x40, 0x11, 0xC0};
|
||||
ac.setRaw(off_timer_11h_on_timer_6h, kSamsungAcExtendedStateLength);
|
||||
EXPECT_EQ(
|
||||
"Power: Off, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off, On Timer: 06:00, Off Timer: 11:00",
|
||||
ac.toString());
|
||||
|
||||
ac.stateReset(false);
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setOnTimer(0);
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setOffTimer(0);
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
// On Timer only
|
||||
ac.setOnTimer(30);
|
||||
EXPECT_EQ(30, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setOnTimer(90); // 1h30m
|
||||
EXPECT_EQ(90, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setOnTimer(85); // 1h25m -> 1h20m
|
||||
EXPECT_EQ(80, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setOnTimer(23 * 60 + 59); // 23:59
|
||||
EXPECT_EQ(23 * 60 + 50, ac.getOnTimer()); // 23:50
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setOnTimer(24 * 60 + 30); // 24:30
|
||||
EXPECT_EQ(24 * 60, ac.getOnTimer()); // 24:00 (Max)
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
// Off Timer only
|
||||
ac.setOnTimer(0);
|
||||
ac.setOffTimer(0);
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setOffTimer(30);
|
||||
EXPECT_EQ(30, ac.getOffTimer());
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
|
||||
ac.setOffTimer(90); // 1h30m
|
||||
EXPECT_EQ(90, ac.getOffTimer());
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
|
||||
ac.setOffTimer(85); // 1h25m -> 1h20m
|
||||
EXPECT_EQ(80, ac.getOffTimer());
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
|
||||
ac.setOffTimer(23 * 60 + 59); // 23:59
|
||||
EXPECT_EQ(23 * 60 + 50, ac.getOffTimer()); // 23:50
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
|
||||
ac.setOffTimer(24 * 60 + 30); // 24:30
|
||||
EXPECT_EQ(24 * 60, ac.getOffTimer()); // 24:00 (Max)
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
|
||||
// Both Timers
|
||||
ac.setOnTimer(24 * 60); // 24:00
|
||||
EXPECT_EQ(24 * 60, ac.getOnTimer()); // 24:00 (Max)
|
||||
EXPECT_EQ(24 * 60, ac.getOffTimer()); // 24:00 (Max)
|
||||
|
||||
ac.setOnTimer(1 * 60 + 30); // 1:30
|
||||
ac.setOffTimer(11 * 60); // 11:00
|
||||
EXPECT_EQ(1 * 60 + 30, ac.getOnTimer());
|
||||
EXPECT_EQ(11 * 60, ac.getOffTimer());
|
||||
}
|
||||
|
||||
TEST(TestIRSamsungAcClass, Sleep) {
|
||||
IRSamsungAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
// https://cryptpad.fr/sheet/#/2/sheet/view/r9k8pmELYEjLyC71cD7EsThEYgKGLJygREZ5pVfNkS8/
|
||||
const uint8_t sleep_8h[kSamsungAcExtendedStateLength] = {
|
||||
0x02, 0x82, 0x0F, 0x00, 0x00, 0x10, 0xF0,
|
||||
0x01, 0xA2, 0x0F, 0x04, 0x00, 0x0C, 0x00,
|
||||
0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0};
|
||||
ac.setRaw(sleep_8h, kSamsungAcExtendedStateLength);
|
||||
EXPECT_EQ(8 * 60, ac.getSleepTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(
|
||||
"Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), "
|
||||
"Swing(V): Off, Swing(H): Off, "
|
||||
"Beep: -, Clean: -, Quiet: Off, Powerful: Off, "
|
||||
"Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off, Sleep Timer: 08:00",
|
||||
ac.toString());
|
||||
|
||||
ac.stateReset(false);
|
||||
EXPECT_EQ(0, ac.getSleepTimer());
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setOnTimer(60);
|
||||
ac.setOffTimer(90);
|
||||
EXPECT_EQ(0, ac.getSleepTimer());
|
||||
EXPECT_EQ(60, ac.getOnTimer());
|
||||
EXPECT_EQ(90, ac.getOffTimer());
|
||||
|
||||
ac.setSleepTimer(120);
|
||||
EXPECT_EQ(120, ac.getSleepTimer());
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
|
||||
ac.setSleepTimer(24 * 60 + 31); // 24h31m
|
||||
EXPECT_EQ(24 * 60, ac.getSleepTimer()); // 24h (Max)
|
||||
|
||||
ac.setSleepTimer(35); // 45m
|
||||
EXPECT_EQ(30, ac.getSleepTimer()); // 30m (Only stored in 10m increments).
|
||||
|
||||
ac.setOnTimer(60); // Seting an On Timer should clear the sleep setting.
|
||||
EXPECT_EQ(0, ac.getSleepTimer());
|
||||
EXPECT_EQ(60, ac.getOnTimer());
|
||||
|
||||
ac.setSleepTimer(120);
|
||||
ac.setOffTimer(90); // Setting an Off Timer will clear the sleep setting.
|
||||
EXPECT_EQ(0, ac.getSleepTimer());
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(90, ac.getOffTimer());
|
||||
}
|
||||
|
||||
TEST(TestIRSamsungAcClass, BuildKnownSleepSate) {
|
||||
// For https://github.com/crankyoldgit/IRremoteESP8266/issues/1277#issuecomment-965047193
|
||||
IRSamsungAc ac(kGpioUnused);
|
||||
IRrecv irrecv(kGpioUnused);
|
||||
ac.begin();
|
||||
const uint8_t expectedState[kSamsungAcExtendedStateLength] = {
|
||||
0x02, 0x82, 0x0F, 0x00, 0x00, 0x10, 0xF0,
|
||||
0x01, 0xA2, 0x0F, 0x04, 0x00, 0x0C, 0x00,
|
||||
0x01, 0xD2, 0xFE, 0x71, 0x50, 0x41, 0xF0};
|
||||
const char expectedStr[] = "Power: On, Mode: 4 (Heat), Temp: 21C, "
|
||||
"Fan: 0 (Auto), Swing(V): Off, Swing(H): Off, Beep: -, Clean: -, "
|
||||
"Quiet: Off, Powerful: Off, Econo: Off, Breeze: Off, "
|
||||
"Light: On, Ion: Off, Sleep Timer: 08:00";
|
||||
ac.setPower(true);
|
||||
ac.setMode(kSamsungAcHeat);
|
||||
ac.setTemp(21);
|
||||
ac.setFan(kSamsungAcFanAuto);
|
||||
ac.setSwing(false);
|
||||
ac.setSwingH(false);
|
||||
ac.setBeep(false);
|
||||
ac.setClean(false);
|
||||
ac.setQuiet(false);
|
||||
ac.setPowerful(false);
|
||||
ac.setEcono(false);
|
||||
ac.setBreeze(false);
|
||||
ac.setDisplay(true);
|
||||
ac.setIon(false);
|
||||
ac.setSleepTimer(8 * 60);
|
||||
EXPECT_EQ(expectedStr, ac.toString());
|
||||
ac.send();
|
||||
ac._irsend.makeDecodeResult();
|
||||
EXPECT_TRUE(irrecv.decode(&ac._irsend.capture));
|
||||
EXPECT_EQ(SAMSUNG_AC, ac._irsend.capture.decode_type);
|
||||
EXPECT_EQ(kSamsungAcExtendedBits, ac._irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, ac._irsend.capture.state,
|
||||
ac._irsend.capture.bits);
|
||||
EXPECT_EQ(expectedStr, IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
ac._irsend.reset();
|
||||
}
|
||||
|
|
|
@ -410,8 +410,8 @@ TEST(TestDecodeSharpAc, RealExample) {
|
|||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 27C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 2 (Cool), Temp: 27C, Fan: 2 (Auto), "
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
stdAc::state_t r, p;
|
||||
ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p));
|
||||
|
@ -561,7 +561,7 @@ TEST(TestSharpAcClass, OperatingMode) {
|
|||
// Check toString() says Fan rather than Auto.
|
||||
EXPECT_EQ(
|
||||
"Model: 2 (A705), Power: Off, Mode: 0 (Fan), Temp: 15C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -615,8 +615,8 @@ TEST(TestSharpAcClass, ReconstructKnownState) {
|
|||
EXPECT_STATE_EQ(on_auto_auto, ac.getRaw(), kSharpAcBits);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
|
||||
uint8_t cool_auto_28[kSharpAcStateLength] = {
|
||||
|
@ -629,8 +629,8 @@ TEST(TestSharpAcClass, ReconstructKnownState) {
|
|||
ac.setTemp(28);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
EXPECT_STATE_EQ(cool_auto_28, ac.getRaw(), kSharpAcBits);
|
||||
}
|
||||
|
@ -647,8 +647,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
|||
ac.setRaw(off_auto_auto);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: Off, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: Off, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), "
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t on_auto_auto[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0x00, 0x11, 0x20, 0x00, 0x08, 0x80, 0x00, 0xE0,
|
||||
|
@ -657,8 +657,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
|||
ac.setRaw(on_auto_auto);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_auto_28[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x22, 0x00, 0x08, 0x80, 0x04, 0xE0,
|
||||
|
@ -667,8 +667,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
|||
ac.setRaw(cool_auto_28);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_fan1_28[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x42, 0x00, 0x08, 0x80, 0x05, 0xE0,
|
||||
|
@ -677,8 +677,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
|||
ac.setRaw(cool_fan1_28);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 4 (Low), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 4 (Low), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_fan2_28[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x32, 0x00, 0x08, 0x80, 0x05, 0xE0,
|
||||
|
@ -688,7 +688,7 @@ TEST(TestSharpAcClass, KnownStates) {
|
|||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_fan3_28[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x52, 0x00, 0x08, 0x80, 0x05, 0xE0,
|
||||
|
@ -698,7 +698,7 @@ TEST(TestSharpAcClass, KnownStates) {
|
|||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 5 (UNKNOWN), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_fan4_28[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x72, 0x00, 0x08, 0x80, 0x05, 0xE0,
|
||||
|
@ -707,8 +707,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
|||
ac.setRaw(cool_fan4_28);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
uint8_t cool_fan4_28_ion_on[kSharpAcStateLength] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x61, 0x72, 0x08, 0x08, 0x80, 0x00, 0xE4,
|
||||
|
@ -717,8 +717,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
|||
ac.setRaw(cool_fan4_28_ion_on);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: -, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: On, Econo: -, Clean: Off",
|
||||
"Power: -, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: On, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
/* Unsupported / Not yet reverse engineered.
|
||||
uint8_t cool_fan4_28_eco1[kSharpAcStateLength] = {
|
||||
|
@ -735,8 +735,8 @@ TEST(TestSharpAcClass, KnownStates) {
|
|||
ac.setRaw(dry_auto);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), "
|
||||
"Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -747,6 +747,7 @@ TEST(TestSharpAcClass, toCommon) {
|
|||
ac.setMode(kSharpAcCool);
|
||||
ac.setTemp(20);
|
||||
ac.setFan(kSharpAcFanMax);
|
||||
ac.setSwingV(kSharpAcSwingVOff);
|
||||
// Now test it.
|
||||
ASSERT_EQ(decode_type_t::SHARP_AC, ac.toCommon().protocol);
|
||||
ASSERT_TRUE(ac.toCommon().power);
|
||||
|
@ -755,8 +756,8 @@ TEST(TestSharpAcClass, toCommon) {
|
|||
ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon().mode);
|
||||
ASSERT_EQ(stdAc::fanspeed_t::kMax, ac.toCommon().fanspeed);
|
||||
ASSERT_EQ(sharp_ac_remote_model_t::A705, ac.toCommon().model);
|
||||
// Unsupported.
|
||||
ASSERT_EQ(stdAc::swingv_t::kOff, ac.toCommon().swingv);
|
||||
// Unsupported.
|
||||
ASSERT_EQ(stdAc::swingh_t::kOff, ac.toCommon().swingh);
|
||||
ASSERT_FALSE(ac.toCommon().turbo);
|
||||
ASSERT_FALSE(ac.toCommon().quiet);
|
||||
|
@ -868,20 +869,20 @@ TEST(TestSharpAcClass, Turbo) {
|
|||
EXPECT_EQ(kSharpAcFanMax, ac.getFan());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), "
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Turbo: On, "
|
||||
"Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off",
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), "
|
||||
"Swing(V): 0 (N/A), Turbo: On, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
|
||||
ac.setRaw(off_state);
|
||||
EXPECT_FALSE(ac.getTurbo());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), "
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off",
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), "
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
TEST(TestSharpAcClass, SwingToggle) {
|
||||
TEST(TestSharpAcClass, Swings) {
|
||||
IRSharpAc ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
|
@ -906,6 +907,70 @@ TEST(TestSharpAcClass, SwingToggle) {
|
|||
|
||||
ac.setRaw(off_state);
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
|
||||
// Vertical
|
||||
ac.setSwingV(kSharpAcSwingVToggle);
|
||||
EXPECT_EQ(kSharpAcSwingVToggle, ac.getSwingV());
|
||||
EXPECT_TRUE(ac.getSwingToggle());
|
||||
|
||||
ac.setSwingV(kSharpAcSwingVHigh);
|
||||
EXPECT_EQ(kSharpAcSwingVHigh, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
|
||||
ac.setSwingV(0xFF); // Doesn't change if invalid position given.
|
||||
EXPECT_EQ(kSharpAcSwingVHigh, ac.getSwingV());
|
||||
|
||||
ac.setSwingV(kSharpAcSwingVMid);
|
||||
EXPECT_EQ(kSharpAcSwingVMid, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
|
||||
ac.setSwingV(kSharpAcSwingVLow);
|
||||
EXPECT_EQ(kSharpAcSwingVLow, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
|
||||
ac.setSwingV(kSharpAcSwingVIgnore);
|
||||
EXPECT_EQ(kSharpAcSwingVIgnore, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
|
||||
// Lowest/Coanda only works in Heat mode.
|
||||
ac.setMode(kSharpAcCool);
|
||||
ac.setSwingV(kSharpAcSwingVLowest);
|
||||
EXPECT_EQ(kSharpAcSwingVLow, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
ac.setModel(sharp_ac_remote_model_t::A907); // Model A907 has heat mode.
|
||||
ac.setMode(kSharpAcHeat);
|
||||
EXPECT_EQ(kSharpAcHeat, ac.getMode());
|
||||
ac.setSwingV(kSharpAcSwingVLowest);
|
||||
EXPECT_EQ(kSharpAcSwingVLowest, ac.getSwingV());
|
||||
|
||||
// Check we can force Coanda in Cool mode.
|
||||
ac.setMode(kSharpAcCool);
|
||||
ASSERT_EQ(kSharpAcSwingVCoanda, kSharpAcSwingVLowest);
|
||||
ac.setSwingV(kSharpAcSwingVCoanda, true);
|
||||
EXPECT_EQ(kSharpAcSwingVCoanda, ac.getSwingV());
|
||||
EXPECT_FALSE(ac.getSwingToggle());
|
||||
EXPECT_EQ(kSharpAcCool, ac.getMode());
|
||||
|
||||
// Real messages/states
|
||||
// ref: https://github.com/crankyoldgit/IRremoteESP8266/discussions/1590#discussioncomment-1254748
|
||||
ac.stateReset();
|
||||
const uint8_t coanda_heat_on[13] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xC8, 0x31, 0x21,
|
||||
0x0A, 0x0E, 0x80, 0x06, 0xF4, 0x81};
|
||||
ac.setRaw(coanda_heat_on);
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: On, Mode: 1 (Heat), Temp: 23C, Fan: 2 (Auto), "
|
||||
"Swing(V): 6 (Lowest), Turbo: Off, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
|
||||
const uint8_t coanda_cool_on[13] = {
|
||||
0xAA, 0x5A, 0xCF, 0x10, 0xC7, 0x31, 0x22,
|
||||
0x0A, 0x0E, 0x80, 0x06, 0xF4, 0x41};
|
||||
ac.setRaw(coanda_cool_on);
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: On, Mode: 2 (Cool), Temp: 22C, Fan: 2 (Auto), "
|
||||
"Swing(V): 6 (Highest), Turbo: Off, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
TEST(TestSharpAcClass, Ion) {
|
||||
|
@ -1005,8 +1070,8 @@ TEST(TestSharpAcClass, Timers) {
|
|||
EXPECT_TRUE(ac.isPowerSpecial());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), "
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Turbo: Off, "
|
||||
"Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off, Off Timer: 08:30",
|
||||
"Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), Swing(V): 0 (N/A), "
|
||||
"Turbo: Off, Ion: On, Light: -, Clean: Off, Off Timer: 08:30",
|
||||
ac.toString());
|
||||
|
||||
// ref: https://docs.google.com/spreadsheets/d/1otzVFM5_tegrZ4ROCLgQ_jvJaWCDlZs1vC-YuR1FFXM/edit#gid=0&range=E80
|
||||
|
@ -1020,7 +1085,7 @@ TEST(TestSharpAcClass, Timers) {
|
|||
EXPECT_TRUE(ac.isPowerSpecial());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: -, Mode: 2 (Cool), Temp: 21C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off, "
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off, "
|
||||
"On Timer: 12:00",
|
||||
ac.toString());
|
||||
}
|
||||
|
@ -1058,13 +1123,13 @@ TEST(TestSharpAcClass, Clean) {
|
|||
EXPECT_TRUE(ac.getClean());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: On",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: On",
|
||||
ac.toString());
|
||||
ac.setRaw(clean_off_state);
|
||||
EXPECT_FALSE(ac.getClean());
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: On, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
|
||||
// Try constructing the clean on state.
|
||||
|
@ -1084,13 +1149,13 @@ TEST(TestSharpAcClass, Clean) {
|
|||
ac.setPower(false);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: Off, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
// Clean ON
|
||||
ac.setClean(true);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: On",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: On",
|
||||
ac.toString());
|
||||
// Clean OFF (state is identical to `off_msg`).
|
||||
// i.e. It just clears the clean settings & turns off the device.
|
||||
|
@ -1098,25 +1163,25 @@ TEST(TestSharpAcClass, Clean) {
|
|||
ac.setPower(false, true);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: Off, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
// Clean ON
|
||||
ac.setClean(true);
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: On",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: On",
|
||||
ac.toString());
|
||||
// AC OFF
|
||||
ac.off();
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: Off, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
// AC ON (Mode Cool, Temp 25, Ion OFF, Fan 7)
|
||||
ac.on();
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: On, Mode: 2 (Cool), Temp: 25C, Fan: 7 (High), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -1126,7 +1191,7 @@ TEST(TestSharpAcClass, Issue1309) {
|
|||
ac.stateReset();
|
||||
EXPECT_EQ(
|
||||
"Model: 1 (A907), Power: Off, Mode: 0 (Auto), Temp: 15C, Fan: 0 (UNKNOWN), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Econo: -, Clean: Off",
|
||||
ac.toString());
|
||||
|
||||
const uint8_t issue1309_on[13] = {
|
||||
|
@ -1135,7 +1200,7 @@ TEST(TestSharpAcClass, Issue1309) {
|
|||
ac.setRaw(issue1309_on);
|
||||
EXPECT_EQ(
|
||||
"Model: 2 (A705), Power: On, Mode: 2 (Cool), Temp: 16C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
EXPECT_STATE_EQ(issue1309_on, ac.getRaw(), kSharpAcBits);
|
||||
|
||||
|
@ -1147,7 +1212,7 @@ TEST(TestSharpAcClass, Issue1309) {
|
|||
ac.on();
|
||||
EXPECT_EQ(
|
||||
"Model: 2 (A705), Power: On, Mode: 2 (Cool), Temp: 16C, Fan: 2 (Auto), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: Off, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: Off, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -1200,13 +1265,13 @@ TEST(TestSharpAcClass, Issue1387Power) {
|
|||
EXPECT_STATE_EQ(real_off, ac.getRaw(), kSharpAcBits);
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: Off, Mode: 2 (Cool), Temp: 27C, Fan: 3 (Low), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
// Create the same off state.
|
||||
ac.setPower(true, ac.getPower());
|
||||
EXPECT_STATE_EQ(real_on, ac.getRaw(), kSharpAcBits);
|
||||
EXPECT_EQ(
|
||||
"Model: 3 (A903), Power: On, Mode: 2 (Cool), Temp: 27C, Fan: 3 (Low), "
|
||||
"Turbo: Off, Swing(V) Toggle: Off, Ion: On, Light: -, Clean: Off",
|
||||
"Swing(V): 0 (N/A), Turbo: Off, Ion: On, Light: -, Clean: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
|
|
@ -10,8 +10,18 @@
|
|||
|
||||
// General housekeeping
|
||||
TEST(TestTcl112Ac, Housekeeping) {
|
||||
ASSERT_EQ("TCL112AC", typeToString(TCL112AC));
|
||||
ASSERT_TRUE(hasACState(TCL112AC));
|
||||
ASSERT_EQ("TCL112AC", typeToString(decode_type_t::TCL112AC));
|
||||
ASSERT_EQ(decode_type_t::TCL112AC, strToDecodeType("TCL112AC"));
|
||||
ASSERT_TRUE(hasACState(decode_type_t::TCL112AC));
|
||||
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::TCL112AC));
|
||||
ASSERT_EQ(kTcl112AcBits, IRsend::defaultBits(decode_type_t::TCL112AC));
|
||||
ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::TCL112AC));
|
||||
ASSERT_EQ(tcl_ac_remote_model_t::TAC09CHSD, IRac::strToModel("TAC09CHSD"));
|
||||
ASSERT_EQ(irutils::modelToStr(decode_type_t::TCL112AC,
|
||||
tcl_ac_remote_model_t::TAC09CHSD), "TAC09CHSD");
|
||||
ASSERT_EQ(tcl_ac_remote_model_t::GZ055BE1, IRac::strToModel("GZ055BE1"));
|
||||
ASSERT_EQ(irutils::modelToStr(decode_type_t::TCL112AC,
|
||||
tcl_ac_remote_model_t::GZ055BE1), "GZ055BE1");
|
||||
}
|
||||
|
||||
// Tests for decodeTcl112Ac().
|
||||
|
@ -63,9 +73,10 @@ TEST(TestDecodeTcl112Ac, DecodeRealExample) {
|
|||
EXPECT_EQ(kTcl112AcBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Type: 1, Power: On, Mode: 3 (Cool), Temp: 24C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 24C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
}
|
||||
|
||||
|
@ -106,27 +117,31 @@ TEST(TestTcl112AcClass, Temperature) {
|
|||
IRTcl112Ac ac(kGpioUnused);
|
||||
ac.setRaw(temp16C);
|
||||
EXPECT_EQ(
|
||||
"Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
ac.toString());
|
||||
ac.setRaw(temp16point5C);
|
||||
EXPECT_EQ(
|
||||
"Type: 1, Power: On, Mode: 3 (Cool), Temp: 16.5C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16.5C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
ac.toString());
|
||||
ac.setRaw(temp19point5C);
|
||||
EXPECT_EQ(
|
||||
"Type: 1, Power: On, Mode: 3 (Cool), Temp: 19.5C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 19.5C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
ac.toString());
|
||||
ac.setRaw(temp31C);
|
||||
EXPECT_EQ(
|
||||
"Type: 1, Power: On, Mode: 3 (Cool), Temp: 31C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 31C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
ac.toString());
|
||||
|
||||
ac.setTemp(kTcl112AcTempMin);
|
||||
|
@ -206,9 +221,10 @@ TEST(TestTcl112AcClass, OperatingMode) {
|
|||
0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0x48};
|
||||
ac.setRaw(automode);
|
||||
EXPECT_EQ(
|
||||
"Type: 1, Power: On, Mode: 8 (Auto), Temp: 24C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 8 (Auto), Temp: 24C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -236,9 +252,10 @@ TEST(TestTcl112AcClass, Power) {
|
|||
0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCB};
|
||||
ac.setRaw(on);
|
||||
EXPECT_EQ(
|
||||
"Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
ac.toString());
|
||||
|
||||
const uint8_t off[kTcl112AcStateLength] = {
|
||||
|
@ -246,9 +263,10 @@ TEST(TestTcl112AcClass, Power) {
|
|||
0x07, 0x40, 0x00, 0x00, 0x00, 0x80, 0xCB};
|
||||
ac.setRaw(off);
|
||||
EXPECT_EQ(
|
||||
"Type: 1, Power: Off, Mode: 3 (Cool), Temp: 24C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: Off, Mode: 3 (Cool), Temp: 24C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -263,15 +281,17 @@ TEST(TestTcl112AcClass, Checksum) {
|
|||
EXPECT_EQ(0xCB, ac.calcChecksum(temp16C));
|
||||
ac.setRaw(temp16C);
|
||||
EXPECT_EQ(
|
||||
"Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
ac.toString());
|
||||
ac.setRaw(temp31C);
|
||||
EXPECT_EQ(
|
||||
"Type: 1, Power: On, Mode: 3 (Cool), Temp: 31C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 31C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
ac.toString());
|
||||
EXPECT_EQ(0xBC, ac.calcChecksum(temp31C));
|
||||
|
||||
|
@ -337,12 +357,22 @@ TEST(TestTcl112AcClass, SwingVertical) {
|
|||
IRTcl112Ac ac(kGpioUnused);
|
||||
ac.begin();
|
||||
|
||||
ac.setSwingVertical(true);
|
||||
EXPECT_TRUE(ac.getSwingVertical());
|
||||
ac.setSwingVertical(false);
|
||||
EXPECT_EQ(false, ac.getSwingVertical());
|
||||
ac.setSwingVertical(true);
|
||||
EXPECT_TRUE(ac.getSwingVertical());
|
||||
ac.setSwingVertical(kTcl112AcSwingVOff);
|
||||
EXPECT_EQ(kTcl112AcSwingVOff, ac.getSwingVertical());
|
||||
ac.setSwingVertical(kTcl112AcSwingVOn);
|
||||
EXPECT_EQ(kTcl112AcSwingVOn, ac.getSwingVertical());
|
||||
ac.setSwingVertical(kTcl112AcSwingVHigh);
|
||||
EXPECT_EQ(kTcl112AcSwingVHigh, ac.getSwingVertical());
|
||||
ac.setSwingVertical(kTcl112AcSwingVOff);
|
||||
EXPECT_EQ(kTcl112AcSwingVOff, ac.getSwingVertical());
|
||||
ac.setSwingVertical(0xFF); // Unused value so shouldn't change from previous.
|
||||
EXPECT_EQ(kTcl112AcSwingVOff, ac.getSwingVertical());
|
||||
|
||||
const uint8_t highest[kTcl112AcStateLength] = {
|
||||
0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
|
||||
0x0F, 0x08, 0x00, 0x00, 0x00, 0x00, 0x53};
|
||||
ac.setRaw(highest);
|
||||
EXPECT_EQ(kTcl112AcSwingVHighest, ac.getSwingVertical());
|
||||
}
|
||||
|
||||
TEST(TestTcl112AcClass, Turbo) {
|
||||
|
@ -405,6 +435,7 @@ TEST(TestTcl112AcClass, Quiet_Mute) {
|
|||
|
||||
TEST(TestTcl112AcClass, toCommon) {
|
||||
IRTcl112Ac ac(kGpioUnused);
|
||||
ac.setModel(tcl_ac_remote_model_t::TAC09CHSD);
|
||||
ac.setPower(true);
|
||||
ac.setMode(kTcl112AcCool);
|
||||
ac.setTemp(20);
|
||||
|
@ -418,7 +449,7 @@ TEST(TestTcl112AcClass, toCommon) {
|
|||
ac.setQuiet(false);
|
||||
// Now test it.
|
||||
ASSERT_EQ(decode_type_t::TCL112AC, ac.toCommon().protocol);
|
||||
ASSERT_EQ(-1, ac.toCommon().model);
|
||||
ASSERT_EQ(1, ac.toCommon().model);
|
||||
ASSERT_TRUE(ac.toCommon().power);
|
||||
ASSERT_TRUE(ac.toCommon().celsius);
|
||||
ASSERT_EQ(20, ac.toCommon().degrees);
|
||||
|
@ -485,9 +516,10 @@ TEST(TestDecodeTcl112Ac, Issue744) {
|
|||
IRTcl112Ac ac(kGpioUnused);
|
||||
ac.setRaw(irsend.capture.state);
|
||||
EXPECT_EQ(
|
||||
"Type: 1, Power: On, Mode: 3 (Cool), Temp: 23C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 23C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: On, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
ac.toString());
|
||||
}
|
||||
|
||||
|
@ -527,7 +559,7 @@ TEST(TestDecodeTcl112Ac, Issue1528) {
|
|||
EXPECT_EQ(kTcl112AcBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"Type: 2, Quiet: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 2, Quiet: On",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
}
|
||||
|
||||
|
@ -536,7 +568,6 @@ TEST(TestTcl112AcClass, SendingQuiet) {
|
|||
IRTcl112Ac ac(kGpioUnused);
|
||||
IRrecv capture(kGpioUnused);
|
||||
|
||||
|
||||
ac.begin();
|
||||
ac.on();
|
||||
ac.setTemp(24);
|
||||
|
@ -559,16 +590,116 @@ TEST(TestTcl112AcClass, SendingQuiet) {
|
|||
ASSERT_EQ(TCL112AC, ac._irsend.capture.decode_type);
|
||||
ASSERT_EQ(kTcl112AcBits, ac._irsend.capture.bits);
|
||||
ASSERT_EQ(
|
||||
"Type: 2, Quiet: On",
|
||||
"Model: 1 (TAC09CHSD), Type: 2, Quiet: On",
|
||||
IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
// Second message.
|
||||
// TCL112 uses the Mitsubishi112 decoder.
|
||||
// Skip first message.
|
||||
EXPECT_TRUE(capture.decodeMitsubishi112(&ac._irsend.capture, 229));
|
||||
ASSERT_EQ(TCL112AC, ac._irsend.capture.decode_type);
|
||||
ASSERT_EQ(kTcl112AcBits, ac._irsend.capture.bits);
|
||||
EXPECT_EQ(TCL112AC, ac._irsend.capture.decode_type);
|
||||
EXPECT_EQ(kTcl112AcBits, ac._irsend.capture.bits);
|
||||
ASSERT_EQ(
|
||||
"Type: 1, Power: On, Mode: 3 (Cool), Temp: 24C, Fan: 0 (Auto), "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Swing(H): Off, Swing(V): Off, "
|
||||
"Light: Off", IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
"Model: 1 (TAC09CHSD), Type: 1, Power: On, Mode: 3 (Cool), Temp: 24C, "
|
||||
"Fan: 0 (Auto), Swing(V): 0 (Auto), Swing(H): Off, "
|
||||
"Econo: Off, Health: Off, Turbo: Off, Light: Off, "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
IRAcUtils::resultAcToString(&ac._irsend.capture));
|
||||
}
|
||||
|
||||
TEST(TestTcl112AcClass, isTcl) {
|
||||
const uint8_t tcl_temp16C[kTcl112AcStateLength] = {
|
||||
0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
|
||||
0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCB};
|
||||
EXPECT_TRUE(IRTcl112Ac::isTcl(tcl_temp16C));
|
||||
const uint8_t tcl_temp31C[kTcl112AcStateLength] = {
|
||||
0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBC};
|
||||
EXPECT_TRUE(IRTcl112Ac::isTcl(tcl_temp31C));
|
||||
const uint8_t issue1528[kTcl112AcStateLength] = {
|
||||
0x23, 0xCB, 0x26, 0x02, 0x00, 0x60, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85};
|
||||
EXPECT_TRUE(IRTcl112Ac::isTcl(issue1528));
|
||||
// Ref: https://cociweb.info/container/hvac_ir_recapture_2719.log
|
||||
const uint8_t teknopoint[14] = {
|
||||
0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03,
|
||||
0x0F, 0x38, 0x00, 0x00, 0x00, 0x00, 0x83};
|
||||
EXPECT_FALSE(IRTcl112Ac::isTcl(teknopoint));
|
||||
}
|
||||
|
||||
TEST(TestTcl112AcClass, Timers) {
|
||||
IRTcl112Ac ac(kGpioUnused);
|
||||
|
||||
ac.stateReset();
|
||||
ac.setOnTimer(0);
|
||||
ac.setOffTimer(0);
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
EXPECT_FALSE(ac._.TimerIndicator);
|
||||
EXPECT_FALSE(ac._.OnTimerEnabled);
|
||||
EXPECT_FALSE(ac._.OffTimerEnabled);
|
||||
|
||||
ac.setOnTimer(7 * 60);
|
||||
EXPECT_EQ(7 * 60, ac.getOnTimer());
|
||||
EXPECT_TRUE(ac._.TimerIndicator);
|
||||
EXPECT_TRUE(ac._.OnTimerEnabled);
|
||||
EXPECT_FALSE(ac._.OffTimerEnabled);
|
||||
|
||||
ac.setOnTimer(0);
|
||||
EXPECT_EQ(0, ac.getOnTimer());
|
||||
EXPECT_FALSE(ac._.TimerIndicator);
|
||||
EXPECT_FALSE(ac._.OnTimerEnabled);
|
||||
EXPECT_FALSE(ac._.OffTimerEnabled);
|
||||
|
||||
ac.setOffTimer(13 * 60); // Beyond max.
|
||||
EXPECT_EQ(12 * 60, ac.getOffTimer());
|
||||
EXPECT_TRUE(ac._.TimerIndicator);
|
||||
EXPECT_FALSE(ac._.OnTimerEnabled);
|
||||
EXPECT_TRUE(ac._.OffTimerEnabled);
|
||||
|
||||
ac.setOffTimer(0);
|
||||
EXPECT_EQ(0, ac.getOffTimer());
|
||||
EXPECT_FALSE(ac._.TimerIndicator);
|
||||
EXPECT_FALSE(ac._.OnTimerEnabled);
|
||||
EXPECT_FALSE(ac._.OffTimerEnabled);
|
||||
|
||||
// Real messages/states
|
||||
// Per https://github.com/crankyoldgit/IRremoteESP8266/issues/1486#issuecomment-917545485
|
||||
|
||||
const uint8_t ontimer_1h[14] = {
|
||||
0x23, 0xCB, 0x26, 0x01, 0x00, 0x34, 0x03,
|
||||
0x00, 0x78, 0x00, 0x06, 0x00, 0x00, 0xCA};
|
||||
ac.setRaw(ontimer_1h);
|
||||
EXPECT_EQ(60, ac.getOnTimer());
|
||||
EXPECT_TRUE(ac._.TimerIndicator);
|
||||
EXPECT_TRUE(ac._.OnTimerEnabled);
|
||||
EXPECT_FALSE(ac._.OffTimerEnabled);
|
||||
|
||||
const uint8_t ontimer_4h[14] = {
|
||||
0x23, 0xCB, 0x26, 0x01, 0x00, 0x34, 0x03,
|
||||
0x00, 0x78, 0x00, 0x18, 0x00, 0x00, 0xDC};
|
||||
ac.setRaw(ontimer_4h);
|
||||
EXPECT_EQ(240, ac.getOnTimer());
|
||||
EXPECT_TRUE(ac._.TimerIndicator);
|
||||
EXPECT_TRUE(ac._.OnTimerEnabled);
|
||||
EXPECT_FALSE(ac._.OffTimerEnabled);
|
||||
EXPECT_EQ(
|
||||
"Model: 2 (GZ055BE1), Type: 1, Power: On, Mode: 3 (Cool), Temp: 31C, "
|
||||
"Fan: 0 (Auto), Swing(V): 7 (Swing), "
|
||||
"On Timer: 04:00, Off Timer: Off",
|
||||
ac.toString());
|
||||
|
||||
const uint8_t offtimer_2h[14] = {
|
||||
0x23, 0xCB, 0x26, 0x01, 0x00, 0x2C, 0x08,
|
||||
0x07, 0x78, 0x0C, 0x00, 0x00, 0x00, 0xD4};
|
||||
|
||||
ac.setRaw(offtimer_2h);
|
||||
EXPECT_EQ(120, ac.getOffTimer());
|
||||
EXPECT_TRUE(ac._.TimerIndicator);
|
||||
EXPECT_FALSE(ac._.OnTimerEnabled);
|
||||
EXPECT_TRUE(ac._.OffTimerEnabled);
|
||||
EXPECT_EQ(
|
||||
"Model: 2 (GZ055BE1), Type: 1, Power: On, Mode: 8 (Auto), Temp: 24C, "
|
||||
"Fan: 0 (Auto), Swing(V): 7 (Swing), "
|
||||
"On Timer: Off, Off Timer: 02:00",
|
||||
ac.toString());
|
||||
}
|
||||
|
|
|
@ -44,7 +44,9 @@ TEST(TestDecodeTeknopoint, RealExample) {
|
|||
ASSERT_EQ(kTeknopointBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"",
|
||||
"Model: 2 (GZ055BE1), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, "
|
||||
"Fan: 0 (Auto), Swing(V): 1 (Highest), "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
}
|
||||
|
||||
|
@ -67,7 +69,9 @@ TEST(TestDecodeTeknopoint, SyntheticExample) {
|
|||
ASSERT_EQ(kTeknopointBits, irsend.capture.bits);
|
||||
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
|
||||
EXPECT_EQ(
|
||||
"",
|
||||
"Model: 2 (GZ055BE1), Type: 1, Power: On, Mode: 3 (Cool), Temp: 16C, "
|
||||
"Fan: 0 (Auto), Swing(V): 1 (Highest), "
|
||||
"On Timer: Off, Off Timer: Off",
|
||||
IRAcUtils::resultAcToString(&irsend.capture));
|
||||
|
||||
EXPECT_EQ(
|
||||
|
@ -95,7 +99,7 @@ TEST(TestUtils, Housekeeping) {
|
|||
ASSERT_EQ("TEKNOPOINT", typeToString(decode_type_t::TEKNOPOINT));
|
||||
ASSERT_EQ(decode_type_t::TEKNOPOINT, strToDecodeType("TEKNOPOINT"));
|
||||
ASSERT_TRUE(hasACState(decode_type_t::TEKNOPOINT));
|
||||
ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::TEKNOPOINT));
|
||||
ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::TEKNOPOINT));
|
||||
ASSERT_EQ(kTeknopointBits, IRsend::defaultBits(decode_type_t::TEKNOPOINT));
|
||||
ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::TEKNOPOINT));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
# SYNOPSIS:
|
||||
#
|
||||
# make [all] - makes everything.
|
||||
# make TARGET - makes the given target.
|
||||
# make run_tests - makes everything and runs all test
|
||||
# make run-% - run specific test file (exclude .py)
|
||||
# replace % with given test file
|
||||
# make clean - removes all files generated by make.
|
||||
|
||||
# Please tweak the following variable definitions as needed by your
|
||||
|
@ -37,6 +41,10 @@ run_tests : all
|
|||
echo "PASS: \o/ \o/ All unit tests passed. \o/ \o/"; \
|
||||
fi
|
||||
|
||||
run-% : all
|
||||
echo "RUNNING: $*"; \
|
||||
python3 ./$*.py;
|
||||
|
||||
clean :
|
||||
rm -f *.o *.pyc gc_decode mode2_decode
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ class RawIRMessage():
|
|||
bits = len(binary_str)
|
||||
rev_binary_str = binary_str[::-1]
|
||||
rev_num = int(rev_binary_str, 2)
|
||||
# pylint: disable=C0209
|
||||
self.output.write("\n Bits: %d\n"
|
||||
" Hex: %s (MSB first)\n"
|
||||
" %s (LSB first)\n"
|
||||
|
@ -95,22 +96,21 @@ class RawIRMessage():
|
|||
(bits, ("0x{0:0%dX}" % (bits / 4)).format(num),
|
||||
("0x{0:0%dX}" % (bits / 4)).format(rev_num), num,
|
||||
rev_num, binary_str, rev_binary_str))
|
||||
# pylint: enable=C0209
|
||||
|
||||
def add_data_code(self, bin_str, name="", footer=True):
|
||||
"""Add the common "data" sequence of code to send the bulk of a message."""
|
||||
# pylint: disable=no-self-use
|
||||
code = []
|
||||
nbits = len(bin_str)
|
||||
code.append(" // Data Section #%d" % self.section_count)
|
||||
code.append(" // e.g. data = 0x%X, nbits = %d" % (int(bin_str, 2),
|
||||
nbits))
|
||||
code.append(" sendData(k%sBitMark, k%sOneSpace, k%sBitMark, "
|
||||
"k%sZeroSpace, send_data, %d, true);" %
|
||||
(name, name, name, name, nbits))
|
||||
code.append(" send_data >>= %d;" % nbits)
|
||||
code.append(f" // Data Section #{self.section_count}")
|
||||
code.append(f" // e.g. data = 0x{int(bin_str, 2):X}, nbits = {nbits}")
|
||||
code.append(f" sendData(k{name}BitMark, k{name}OneSpace, k{name}BitMark,"
|
||||
f" k{name}ZeroSpace, send_data, {nbits}, true);")
|
||||
code.append(f" send_data >>= {nbits};")
|
||||
if footer:
|
||||
code.append(" // Footer")
|
||||
code.append(" mark(k%sBitMark);" % name)
|
||||
code.append(f" mark(k{name}BitMark);")
|
||||
return code
|
||||
|
||||
def add_data_decode_code(self, bin_str, name="", footer=True):
|
||||
|
@ -120,21 +120,20 @@ class RawIRMessage():
|
|||
nbits = len(bin_str)
|
||||
code.extend([
|
||||
"",
|
||||
" // Data Section #%d" % self.section_count,
|
||||
" // e.g. data_result.data = 0x%X, nbits = %d" % (int(bin_str, 2),
|
||||
nbits),
|
||||
" data_result = matchData(&(results->rawbuf[offset]), %s," % nbits,
|
||||
" k%sBitMark, k%sOneSpace," % (name, name),
|
||||
" k%sBitMark, k%sZeroSpace);" % (name, name),
|
||||
f" // Data Section #{self.section_count}",
|
||||
f" // e.g. data_result.data = 0x{int(bin_str, 2):X}, nbits = {nbits}",
|
||||
f" data_result = matchData(&(results->rawbuf[offset]), {nbits},",
|
||||
f" k{name}BitMark, k{name}OneSpace,",
|
||||
f" k{name}BitMark, k{name}ZeroSpace);",
|
||||
" offset += data_result.used;",
|
||||
" if (data_result.success == false) return false; // Fail",
|
||||
" data <<= %s; // Make room for the new bits of data." % nbits,
|
||||
f" data <<= {nbits}; // Make room for the new bits of data.",
|
||||
" data |= data_result.data;"])
|
||||
if footer:
|
||||
code.extend([
|
||||
"",
|
||||
" // Footer",
|
||||
" if (!matchMark(results->rawbuf[offset++], k%sBitMark))" % name,
|
||||
f" if (!matchMark(results->rawbuf[offset++], k{name}BitMark))",
|
||||
" return false;"])
|
||||
return code
|
||||
|
||||
|
@ -148,26 +147,28 @@ class RawIRMessage():
|
|||
ambles = {}
|
||||
firstmark = ambles.get("firstmark", 0)
|
||||
firstspace = ambles.get("firstspace", 0)
|
||||
lastmark = ambles.get("lastmark", "k%sBitMark" % name)
|
||||
lastmark = ambles.get("lastmark", f"k{name}BitMark")
|
||||
lastspace = ambles.get("lastspace", "kDefaultMessageGap")
|
||||
code.append(
|
||||
" // Data Section #%d" % self.section_count)
|
||||
code.append(f" // Data Section #{self.section_count}")
|
||||
if nbits % 8:
|
||||
code.append(" // DANGER: Nr. of bits is not a multiple of 8. "
|
||||
"This section won't work!")
|
||||
code.extend([
|
||||
" // e.g.",
|
||||
" // bits = %d; bytes = %d;" % (nbits, nbytes),
|
||||
f" // bits = {nbits}; bytes = {int(nbytes)};",
|
||||
# pylint: disable=C0209
|
||||
" // *(data + pos) = {0x%s};" % (
|
||||
", 0x".join("%02X" % int(bin_str[i:i + 8], 2)
|
||||
for i in range(0, len(bin_str), 8))),
|
||||
" sendGeneric(%s, %s," % (firstmark, firstspace),
|
||||
" k%sBitMark, k%sOneSpace," % (name, name),
|
||||
" k%sBitMark, k%sZeroSpace," % (name, name),
|
||||
" %s, %s," % (lastmark, lastspace),
|
||||
" data + pos, %d, // Bytes" % nbytes,
|
||||
" k%sFreq, true, kNoRepeat, kDutyDefault);" % name,
|
||||
" pos += %d; // Adjust by how many bytes of data we sent" % nbytes])
|
||||
# pylint: enable=C0209
|
||||
f" sendGeneric({firstmark}, {firstspace},",
|
||||
f" k{name}BitMark, k{name}OneSpace,",
|
||||
f" k{name}BitMark, k{name}ZeroSpace,",
|
||||
f" {lastmark}, {lastspace},",
|
||||
f" data + pos, {int(nbytes)}, // Bytes",
|
||||
f" k{name}Freq, true, kNoRepeat, kDutyDefault);",
|
||||
f" pos += {int(nbytes)};"
|
||||
f" // Adjust by how many bytes of data we sent"])
|
||||
return code
|
||||
|
||||
def add_data_byte_decode_code(self, bin_str, name="", ambles=None):
|
||||
|
@ -183,36 +184,37 @@ class RawIRMessage():
|
|||
ambles = {}
|
||||
firstmark = ambles.get("firstmark", 0)
|
||||
firstspace = ambles.get("firstspace", 0)
|
||||
lastmark = ambles.get("lastmark", "k%sBitMark" % name)
|
||||
lastmark = ambles.get("lastmark", f"k{name}BitMark")
|
||||
lastspace = ambles.get("lastspace", "kDefaultMessageGap")
|
||||
|
||||
code.extend([
|
||||
"",
|
||||
" // Data Section #%d" % self.section_count,
|
||||
f" // Data Section #{self.section_count}",
|
||||
" // e.g.",
|
||||
" // bits = %d; bytes = %d;" % (nbits, nbytes),
|
||||
f" // bits = {nbits}; bytes = {int(nbytes)};",
|
||||
# pylint: disable=C0209
|
||||
" // *(results->state + pos) = {0x%s};" % (
|
||||
", 0x".join("%02X" % int(bin_str[i:i + 8], 2)
|
||||
for i in range(0, len(bin_str), 8))),
|
||||
# pylint: enable=C0209
|
||||
" used = matchGeneric(results->rawbuf + offset, results->state + pos,",
|
||||
" results->rawlen - offset, %d," % nbits,
|
||||
" %s, %s," % (firstmark, firstspace),
|
||||
" k%sBitMark, k%sOneSpace," % (name, name),
|
||||
" k%sBitMark, k%sZeroSpace," % (name, name),
|
||||
" %s, %s, true);" % (lastmark, lastspace),
|
||||
f" results->rawlen - offset, {nbits},",
|
||||
f" {firstmark}, {firstspace},",
|
||||
f" k{name}BitMark, k{name}OneSpace,",
|
||||
f" k{name}BitMark, k{name}ZeroSpace,",
|
||||
f" {lastmark}, {lastspace}, true);",
|
||||
" if (used == 0) return false; // We failed to find any data.",
|
||||
" offset += used; // Adjust for how much of the message we read.",
|
||||
" pos += %d; // Adjust by how many bytes of data we read" % nbytes])
|
||||
f" pos += {int(nbytes)};"
|
||||
" // Adjust by how many bytes of data we read"])
|
||||
return code
|
||||
|
||||
def _calc_values(self):
|
||||
"""Calculate the values which describe the standard timings
|
||||
for the protocol."""
|
||||
if self.verbose:
|
||||
self.output.write("Potential Mark Candidates:\n"
|
||||
"%s\n"
|
||||
"Potential Space Candidates:\n"
|
||||
"%s\n" % (str(self.marks), str(self.spaces)))
|
||||
self.output.write(f"Potential Mark Candidates:\n{self.marks}\n"
|
||||
f"Potential Space Candidates:\n{self.spaces}\n")
|
||||
# The bit mark is likely to be the smallest mark.
|
||||
self.bit_mark = self.marks[-1]
|
||||
if len(self.marks) > 2: # Possible leader mark?
|
||||
|
@ -305,8 +307,8 @@ def convert_rawdata(data_str):
|
|||
results.append(int(timing))
|
||||
except ValueError as non_numeric:
|
||||
raise ValueError(
|
||||
"Raw Data contains a non-numeric value of '%s'." %
|
||||
timing) from non_numeric
|
||||
f"Raw Data contains a non-numeric value of '{timing}'."
|
||||
) from non_numeric
|
||||
return results
|
||||
|
||||
|
||||
|
@ -326,35 +328,33 @@ def dump_constants(message, defines, name="", output=sys.stdout):
|
|||
zero_space = avg_list(message.space_buckets[message.zero_space])
|
||||
|
||||
output.write("Guessing key value:\n"
|
||||
"k%sHdrMark = %d\n"
|
||||
"k%sHdrSpace = %d\n"
|
||||
"k%sBitMark = %d\n"
|
||||
"k%sOneSpace = %d\n"
|
||||
"k%sZeroSpace = %d\n" % (name, hdr_mark, name, hdr_space,
|
||||
name, bit_mark, name, one_space,
|
||||
name, zero_space))
|
||||
defines.append("const uint16_t k%sHdrMark = %d;" % (name, hdr_mark))
|
||||
defines.append("const uint16_t k%sBitMark = %d;" % (name, bit_mark))
|
||||
defines.append("const uint16_t k%sHdrSpace = %d;" % (name, hdr_space))
|
||||
defines.append("const uint16_t k%sOneSpace = %d;" % (name, one_space))
|
||||
defines.append("const uint16_t k%sZeroSpace = %d;" % (name, zero_space))
|
||||
f"k{name}HdrMark = {hdr_mark}\n"
|
||||
f"k{name}HdrSpace = {hdr_space}\n"
|
||||
f"k{name}BitMark = {bit_mark}\n"
|
||||
f"k{name}OneSpace = {one_space}\n"
|
||||
f"k{name}ZeroSpace = {zero_space}\n")
|
||||
defines.append(f"const uint16_t k{name}HdrMark = {hdr_mark};")
|
||||
defines.append(f"const uint16_t k{name}BitMark = {bit_mark};")
|
||||
defines.append(f"const uint16_t k{name}HdrSpace = {hdr_space};")
|
||||
defines.append(f"const uint16_t k{name}OneSpace = {one_space};")
|
||||
defines.append(f"const uint16_t k{name}ZeroSpace = {zero_space};")
|
||||
if ldr_mark:
|
||||
output.write("k%sLdrMark = %d\n" % (name, ldr_mark))
|
||||
defines.append("const uint16_t k%sLdrMark = %d;" % (name, ldr_mark))
|
||||
output.write(f"k{name}LdrMark = {ldr_mark}\n")
|
||||
defines.append(f"const uint16_t k{name}LdrMark = {ldr_mark};")
|
||||
|
||||
avg_gaps = [avg_list(message.space_buckets[x]) for x in message.gaps]
|
||||
if len(message.gaps) == 1:
|
||||
output.write("k%sSpaceGap = %d\n" % (name, avg_gaps[0]))
|
||||
defines.append("const uint16_t k%sSpaceGap = %d;" % (name, avg_gaps[0]))
|
||||
output.write(f"k{name}SpaceGap = {avg_gaps[0]}\n")
|
||||
defines.append(f"const uint16_t k{name}SpaceGap = {avg_gaps[0]};")
|
||||
else:
|
||||
count = 0
|
||||
for gap in avg_gaps:
|
||||
# We probably (still) have a gap in the protocol.
|
||||
count = count + 1
|
||||
output.write("k%sSpaceGap%d = %d\n" % (name, count, gap))
|
||||
defines.append("const uint16_t k%sSpaceGap%d = %d;" % (name, count, gap))
|
||||
defines.append("const uint16_t k%sFreq = 38000; "
|
||||
"// Hz. (Guessing the most common frequency.)" % name)
|
||||
output.write(f"k{name}SpaceGap{count} = {gap}\n")
|
||||
defines.append(f"const uint16_t k{name}SpaceGap{count} = {gap};")
|
||||
defines.append(f"const uint16_t k{name}Freq = 38000; "
|
||||
"// Hz. (Guessing the most common frequency.)")
|
||||
|
||||
|
||||
def parse_and_report(rawdata_str, margin, gen_code=False, name="",
|
||||
|
@ -374,7 +374,7 @@ def parse_and_report(rawdata_str, margin, gen_code=False, name="",
|
|||
# Parse the input.
|
||||
rawdata = convert_rawdata(rawdata_str)
|
||||
|
||||
output.write("Found %d timing entries.\n" % len(rawdata))
|
||||
output.write(f"Found {len(rawdata)} timing entries.\n")
|
||||
|
||||
message = RawIRMessage(margin, rawdata, output)
|
||||
output.write("\nGuessing encoding type:\n")
|
||||
|
@ -410,17 +410,17 @@ def decode_data(message, defines, code, name="", output=sys.stdout):
|
|||
|
||||
code["sendcomhead"].extend([
|
||||
"",
|
||||
"#if SEND_%s" % def_name.upper(),
|
||||
f"#if SEND_{def_name.upper()}",
|
||||
SAFE64NOTE,
|
||||
"/// Send a %s formatted message." % name,
|
||||
f"/// Send a {name} formatted message.",
|
||||
"/// Status: ALPHA / Untested."])
|
||||
code["send"].extend([
|
||||
"/// @param[in] data containing the IR command.",
|
||||
"/// @param[in] nbits Nr. of bits to send. usually k%sBits" % name,
|
||||
f"/// @param[in] nbits Nr. of bits to send. usually k{name}Bits",
|
||||
"/// @param[in] repeat Nr. of times the message is to be repeated.",
|
||||
"void IRsend::send%s(const uint64_t data, const uint16_t"
|
||||
" nbits, const uint16_t repeat) {" % def_name,
|
||||
" enableIROut(k%sFreq);" % name,
|
||||
f"void IRsend::send{def_name}(const uint64_t data, const uint16_t"
|
||||
" nbits, const uint16_t repeat) {",
|
||||
f" enableIROut(k{name}Freq);",
|
||||
" for (uint16_t r = 0; r <= repeat; r++) {",
|
||||
" uint64_t send_data = data;"])
|
||||
code["send64+"].extend([
|
||||
|
@ -431,21 +431,21 @@ def decode_data(message, defines, code, name="", output=sys.stdout):
|
|||
CODEGEN,
|
||||
"/// @endcode",
|
||||
"/// @param[in] nbytes Nr. of bytes of data in the array."
|
||||
" (>=k%sStateLength)" % name,
|
||||
f" (>=k{name}StateLength)",
|
||||
"/// @param[in] repeat Nr. of times the message is to be repeated.",
|
||||
"void IRsend::send%s(const uint8_t data[], const uint16_t nbytes,"
|
||||
" const uint16_t repeat) {" % def_name,
|
||||
f"void IRsend::send{def_name}(const uint8_t data[],"
|
||||
" const uint16_t nbytes, const uint16_t repeat) {",
|
||||
" for (uint16_t r = 0; r <= repeat; r++) {",
|
||||
" uint16_t pos = 0;"])
|
||||
code["sendcomfoot"].extend([
|
||||
" }",
|
||||
"}",
|
||||
"#endif // SEND_%s" % def_name.upper()])
|
||||
f"#endif // SEND_{def_name.upper()}"])
|
||||
code["recvcomhead"].extend([
|
||||
"",
|
||||
"#if DECODE_%s" % def_name.upper(),
|
||||
f"#if DECODE_{def_name.upper()}",
|
||||
SAFE64NOTE,
|
||||
"/// Decode the supplied %s message." % name,
|
||||
f"/// Decode the supplied {name} message.",
|
||||
"/// Status: ALPHA / Untested.",
|
||||
"/// @param[in,out] results Ptr to the data to decode &"
|
||||
" where to store the decode",
|
||||
|
@ -456,11 +456,11 @@ def decode_data(message, defines, code, name="", output=sys.stdout):
|
|||
"/// @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::decode%s(decode_results *results, uint16_t offset,"
|
||||
" const uint16_t nbits, const bool strict) {" % def_name,
|
||||
" if (results->rawlen < 2 * nbits + k%sOverhead - offset)" % name,
|
||||
f"bool IRrecv::decode{def_name}(decode_results *results, uint16_t offset,"
|
||||
" const uint16_t nbits, const bool strict) {",
|
||||
f" if (results->rawlen < 2 * nbits + k{name}Overhead - offset)",
|
||||
" return false; // Too short a message to match.",
|
||||
" if (strict && nbits != k%sBits)" % name,
|
||||
f" if (strict && nbits != k{name}Bits)",
|
||||
" return false;",
|
||||
""])
|
||||
code["recv"].extend([
|
||||
|
@ -472,7 +472,7 @@ def decode_data(message, defines, code, name="", output=sys.stdout):
|
|||
code["recvcomfoot"].extend([
|
||||
" return true;",
|
||||
"}",
|
||||
"#endif // DECODE_%s" % def_name.upper()])
|
||||
f"#endif // DECODE_{def_name.upper()}"])
|
||||
|
||||
# states are:
|
||||
# HM: Header/Leader mark
|
||||
|
@ -496,24 +496,24 @@ def decode_data(message, defines, code, name="", output=sys.stdout):
|
|||
code["recv"].extend(message.add_data_decode_code(binary_value, name,
|
||||
False))
|
||||
message.section_count = message.section_count + 1
|
||||
code_info["lastmark"] = "k%s%sdrMark" % (name, mark_type)
|
||||
code_info["lastmark"] = f"k{name}{mark_type}drMark"
|
||||
total_bits = total_bits + binary_value
|
||||
code_info["firstmark"] = "k%s%sdrMark" % (name, mark_type)
|
||||
code_info["firstmark"] = f"k{name}{mark_type}drMark"
|
||||
binary_value = add_bit(binary_value, "reset")
|
||||
output.write("k%s%sdrMark+" % (name, mark_type))
|
||||
code["send"].extend([" // %seader" % mark_type,
|
||||
" mark(k%s%sdrMark);" % (name, mark_type)])
|
||||
output.write(f"k{name}{mark_type}drMark+")
|
||||
code["send"].extend([f" // {mark_type}eader",
|
||||
f" mark(k{name}{mark_type}drMark);"])
|
||||
code["recv"].extend([
|
||||
"",
|
||||
" // %seader" % mark_type,
|
||||
" if (!matchMark(results->rawbuf[offset++], k%s%sdrMark))" % (
|
||||
name, mark_type),
|
||||
f" // {mark_type}eader",
|
||||
" if (!matchMark(results->rawbuf[offset++],"
|
||||
f" k{name}{mark_type}drMark))",
|
||||
" return false;"])
|
||||
|
||||
# Handle header spaces.
|
||||
elif message.is_hdr_space(usec) and not message.is_one_space(usec):
|
||||
if binary64_value:
|
||||
code_info["lastspace"] = "k%sHdrSpace" % name
|
||||
code_info["lastspace"] = f"k{name}HdrSpace"
|
||||
message.section_count = message.section_count - 1
|
||||
code["send64+"].extend(message.add_data_byte_code(binary64_value, name,
|
||||
code_info))
|
||||
|
@ -529,39 +529,39 @@ def decode_data(message, defines, code, name="", output=sys.stdout):
|
|||
total_bits = total_bits + binary_value
|
||||
code["send"].extend(message.add_data_code(binary_value, name))
|
||||
code["recv"].extend(message.add_data_decode_code(binary_value, name))
|
||||
code_info["lastspace"] = "k%sHdrSpace" % name
|
||||
code_info["lastspace"] = f"k{name}HdrSpace"
|
||||
message.section_count = message.section_count + 1
|
||||
binary_value = binary64_value = add_bit(binary_value, "reset")
|
||||
output.write("UNEXPECTED->")
|
||||
state = "HS"
|
||||
output.write("k%sHdrSpace+" % name)
|
||||
code["send"].append(" space(k%sHdrSpace);" % name)
|
||||
output.write(f"k{name}HdrSpace+")
|
||||
code["send"].append(f" space(k{name}HdrSpace);")
|
||||
code["recv"].extend([
|
||||
" if (!matchSpace(results->rawbuf[offset++], k%sHdrSpace))" % name,
|
||||
f" if (!matchSpace(results->rawbuf[offset++], k{name}HdrSpace))",
|
||||
" return false;"])
|
||||
code_info["firstspace"] = "k%sHdrSpace" % name
|
||||
code_info["firstspace"] = f"k{name}HdrSpace"
|
||||
# Handle bit marks.
|
||||
elif message.is_bit_mark(usec) and count % 2:
|
||||
if state not in ("HS", "BS"):
|
||||
output.write("k%sBitMark(UNEXPECTED)" % name)
|
||||
output.write(f"k{name}BitMark(UNEXPECTED)")
|
||||
state = "BM"
|
||||
# Handle "zero" spaces
|
||||
elif message.is_zero_space(usec):
|
||||
if state != "BM":
|
||||
output.write("k%sZeroSpace(UNEXPECTED)" % name)
|
||||
output.write(f"k{name}ZeroSpace(UNEXPECTED)")
|
||||
state = "BS"
|
||||
binary_value = binary64_value = add_bit(binary_value, 0, output)
|
||||
# Handle "one" spaces
|
||||
elif message.is_one_space(usec):
|
||||
if state != "BM":
|
||||
output.write("k%sOneSpace(UNEXPECTED)" % name)
|
||||
output.write(f"k{name}OneSpace(UNEXPECTED)")
|
||||
state = "BS"
|
||||
binary_value = binary64_value = add_bit(binary_value, 1, output)
|
||||
elif message.is_gap(usec):
|
||||
if state != "BM":
|
||||
output.write("UNEXPECTED->")
|
||||
output.write("GAP(%d)" % usec)
|
||||
code_info["lastspace"] = "k%sSpaceGap" % name
|
||||
output.write(f"GAP({usec})")
|
||||
code_info["lastspace"] = f"k{name}SpaceGap"
|
||||
if binary64_value:
|
||||
code["send64+"].extend(message.add_data_byte_code(binary64_value, name,
|
||||
code_info))
|
||||
|
@ -579,19 +579,19 @@ def decode_data(message, defines, code, name="", output=sys.stdout):
|
|||
" // Gap"])
|
||||
code["send"].extend([" // Gap"])
|
||||
if state == "BM":
|
||||
code["send"].extend([" mark(k%sBitMark);" % name])
|
||||
code["send"].extend([f" mark(k{name}BitMark);"])
|
||||
code["recv"].extend([
|
||||
" if (!matchMark(results->rawbuf[offset++], k%sBitMark))" % name,
|
||||
f" if (!matchMark(results->rawbuf[offset++], k{name}BitMark))",
|
||||
" return false;"])
|
||||
code["send"].append(" space(k%sSpaceGap);" % name)
|
||||
code["send"].append(f" space(k{name}SpaceGap);")
|
||||
code["recv"].extend([
|
||||
" if (!matchSpace(results->rawbuf[offset++], k%sSpaceGap))" % name,
|
||||
f" if (!matchSpace(results->rawbuf[offset++], k{name}SpaceGap))",
|
||||
" return false;"])
|
||||
total_bits = total_bits + binary_value
|
||||
binary_value = binary64_value = add_bit(binary_value, "reset")
|
||||
state = "GS"
|
||||
else:
|
||||
output.write("UNKNOWN(%d)" % usec)
|
||||
output.write(f"UNKNOWN({usec})")
|
||||
state = "UNK"
|
||||
count = count + 1
|
||||
if binary64_value:
|
||||
|
@ -611,7 +611,7 @@ def decode_data(message, defines, code, name="", output=sys.stdout):
|
|||
code["recv"].extend([
|
||||
"",
|
||||
" // Success",
|
||||
" results->decode_type = decode_type_t::%s;" % def_name.upper(),
|
||||
f" results->decode_type = decode_type_t::{def_name.upper()};",
|
||||
" results->bits = nbits;",
|
||||
" results->value = data;",
|
||||
" results->command = 0;",
|
||||
|
@ -619,19 +619,18 @@ def decode_data(message, defines, code, name="", output=sys.stdout):
|
|||
code["recv64+"].extend([
|
||||
"",
|
||||
" // Success",
|
||||
" results->decode_type = decode_type_t::%s;" % def_name.upper(),
|
||||
f" results->decode_type = decode_type_t::{def_name.upper()};",
|
||||
" results->bits = nbits;"])
|
||||
|
||||
total_bits = total_bits + binary_value
|
||||
output.write("\nTotal Nr. of suspected bits: %d\n" % len(total_bits))
|
||||
defines.append("const uint16_t k%sBits = %d;"
|
||||
" // Move to IRremoteESP8266.h" % (name, len(total_bits)))
|
||||
output.write(f"\nTotal Nr. of suspected bits: {len(total_bits)}\n")
|
||||
defines.append(f"const uint16_t k{name}Bits = {len(total_bits)};"
|
||||
" // Move to IRremoteESP8266.h")
|
||||
if len(total_bits) > 64:
|
||||
defines.append("const uint16_t k%sStateLength = %d;"
|
||||
" // Move to IRremoteESP8266.h" %
|
||||
(name, len(total_bits) / 8))
|
||||
defines.append("const uint16_t k%sOverhead = %d;" %
|
||||
(name, message.rawlen - 2 * len(total_bits)))
|
||||
defines.append(f"const uint16_t k{name}StateLength = "
|
||||
f"{int(len(total_bits) / 8)}; // Move to IRremoteESP8266.h")
|
||||
defines.append(f"const uint16_t k{name}Overhead = "
|
||||
f"{message.rawlen - 2 * len(total_bits)};")
|
||||
return total_bits
|
||||
|
||||
|
||||
|
@ -645,9 +644,9 @@ def generate_code(defines, code, bits_str, name="", output=sys.stdout):
|
|||
output.write("\nGenerating a VERY rough code outline:\n\n"
|
||||
"// Copyright 2020 David Conran (crankyoldgit)\n"
|
||||
"/// @file\n"
|
||||
"/// @brief Support for %s protocol\n\n"
|
||||
f"/// @brief Support for {def_name} protocol\n\n"
|
||||
"// Supports:\n"
|
||||
"// Brand: %s, Model: TODO add device and remote\n\n"
|
||||
f"// Brand: {def_name}, Model: TODO add device and remote\n\n"
|
||||
'#include "IRrecv.h"\n'
|
||||
'#include "IRsend.h"\n'
|
||||
'#include "IRutils.h"\n\n'
|
||||
|
@ -656,9 +655,9 @@ def generate_code(defines, code, bits_str, name="", output=sys.stdout):
|
|||
"// See https://github.com/crankyoldgit/IRremoteESP8266/wiki/"
|
||||
"Adding-support-for-a-new-IR-protocol\n"
|
||||
"// for details of how to include this in the library."
|
||||
"\n" % (def_name, def_name))
|
||||
"\n")
|
||||
for line in defines:
|
||||
output.write("%s\n" % line)
|
||||
output.write(f"{line}\n")
|
||||
|
||||
if len(bits_str) > 64: # Will it fit in a uint64_t?
|
||||
output.write("// DANGER: More than 64 bits detected. A uint64_t for "
|
||||
|
@ -668,18 +667,21 @@ def generate_code(defines, code, bits_str, name="", output=sys.stdout):
|
|||
for line in code["sendcomhead"] + code["send"] + code["sendcomfoot"]:
|
||||
if line == SAFE64NOTE:
|
||||
line = "// Function should be safe up to 64 bits."
|
||||
output.write("%s\n" % line)
|
||||
output.write(f"{line}\n")
|
||||
|
||||
if len(bits_str) > 64: # Will it fit in a uint64_t?
|
||||
for line in code["sendcomhead"] + code["send64+"] + code["sendcomfoot"]:
|
||||
if line == SAFE64NOTE:
|
||||
line = "// Alternative >64bit function to send %s messages\n" % \
|
||||
def_name.upper() + "// Function should be safe over 64 bits."
|
||||
line = (f"// Alternative >64bit function to send {def_name.upper()}"
|
||||
" messages\n"
|
||||
"// Function should be safe over 64 bits.")
|
||||
elif line == CODEGEN:
|
||||
# pylint: disable=C0209
|
||||
line = "/// uint8_t data[k%sStateLength] = {0x%s};" % (
|
||||
name, ", 0x".join("%02X" % int(bits_str[i:i + 8], 2)
|
||||
for i in range(0, len(bits_str), 8)))
|
||||
output.write("%s\n" % line)
|
||||
# pylint: enable=C0209
|
||||
output.write(f"{line}\n")
|
||||
if len(bits_str) > 64: # Will it fit in a uint64_t?
|
||||
output.write("\n// DANGER: More than 64 bits detected. A uint64_t for "
|
||||
"'data' won't work!")
|
||||
|
@ -689,7 +691,7 @@ def generate_code(defines, code, bits_str, name="", output=sys.stdout):
|
|||
for line in code["recvcomhead"] + code["recv"] + code["recvcomfoot"]:
|
||||
if line == SAFE64NOTE:
|
||||
line = "// Function should be safe up to 64 bits."
|
||||
output.write("%s\n" % line)
|
||||
output.write(f"{line}\n")
|
||||
|
||||
# Display the > 64bit version's decode code
|
||||
if len(bits_str) > 64: # Is it too big for a uint64_t?
|
||||
|
@ -699,7 +701,7 @@ def generate_code(defines, code, bits_str, name="", output=sys.stdout):
|
|||
for line in code["recvcomhead"] + code["recv64+"] + code["recvcomfoot"]:
|
||||
if line == SAFE64NOTE:
|
||||
line = "// Function should be safe over 64 bits."
|
||||
output.write("%s\n" % line)
|
||||
output.write(f"{line}\n")
|
||||
|
||||
def add_rawdata_args(parser):
|
||||
"""Add the arguments for feeding in the rawdata string(s)."""
|
||||
|
|
|
@ -24,12 +24,26 @@ cat >${OUTPUT} << EOF
|
|||
// Constant text to be shared across all object files.
|
||||
// This means there is only one copy of the character/string/text etc.
|
||||
|
||||
#ifdef ESP8266
|
||||
class __FlashStringHelper;
|
||||
#define IRTEXT_CONST_PTR_CAST(PTR)\\
|
||||
reinterpret_cast<const __FlashStringHelper*>(PTR)
|
||||
#define IRTEXT_CONST_PTR(NAME) const __FlashStringHelper* const NAME
|
||||
#else // ESP8266
|
||||
#define IRTEXT_CONST_PTR_CAST(PTR) PTR
|
||||
#define IRTEXT_CONST_PTR(NAME) const char* const NAME
|
||||
#endif // ESP8266
|
||||
|
||||
EOF
|
||||
|
||||
# Parse and output contents of INPUT file.
|
||||
sed 's/ PROGMEM//' ${INPUT} | egrep "^(const )?char" | cut -f1 -d= |
|
||||
sed 's/ $/;/;s/^/extern /' | sort -u >> ${OUTPUT}
|
||||
|
||||
egrep '^\s{,10}IRTEXT_CONST_STRING\(' ${INPUT} | cut -f2 -d\( | cut -f1 -d, |
|
||||
sed 's/^/extern IRTEXT_CONST_PTR\(/;s/$/\);/' | sort -u >> ${OUTPUT}
|
||||
egrep '^\s{,10}IRTEXT_CONST_BLOB_DECL\(' ${INPUT} |
|
||||
cut -f2 -d\( | cut -f1 -d\) |
|
||||
sed 's/^/extern IRTEXT_CONST_PTR\(/;s/$/\);/' | sort -u >> ${OUTPUT}
|
||||
# Footer
|
||||
cat >> ${OUTPUT} << EOF
|
||||
|
||||
|
|
|
@ -31,7 +31,8 @@ cat << EndOfTextEndOfTextEndOfText
|
|||
EndOfTextEndOfTextEndOfText
|
||||
|
||||
CLASSES=$(egrep -h "^ *((enum|class) |} [a-zA-Z0-9_]+_t;$)" src/*.h |
|
||||
sed 's/^ *//;s/enum class//;s/\;$//' | cut -d' ' -f2 | sort -u)
|
||||
sed 's/^ *//;s/enum class//;s/\;$//' | cut -d' ' -f2 | sort -u |
|
||||
grep -v "^__")
|
||||
for i in ${CLASSES}; do
|
||||
echo -e "${i}\tKEYWORD1"
|
||||
done | sort -du
|
||||
|
@ -59,13 +60,15 @@ cat << EndOfTextEndOfTextEndOfText
|
|||
#######################################
|
||||
|
||||
EndOfTextEndOfTextEndOfText
|
||||
LITERALS=$(grep "^#define [A-Z]" src/*.cpp src/*.h |
|
||||
LITERALS=$(grep -h "^#define [A-Z]" src/*.cpp src/*.h |
|
||||
while read ignore define ignore; do
|
||||
echo ${define};
|
||||
done | sort -u |
|
||||
grep -v [\(\)] | grep -v ^_ | grep -v _\$ | grep -v VIRTUAL)
|
||||
CONSTS=$(grep "^const " src/*.cpp src/*.h |
|
||||
sed -E 's/\[.*\] =.*//;s/ =.*//;s/^.* \*?k/k/')
|
||||
CONSTS=$(grep -h "^const " src/*.cpp src/*.h |
|
||||
sed -E 's/\[.*\] =.*//;s/ =.*//;s/^.* \*?k/k/';
|
||||
grep -h "^IRTEXT_CONST_" src/*.cpp src/*.h |
|
||||
sed -E 's/IRTEXT_CONST_\S+\(//;s/,.*//;s/\).*//')
|
||||
ENUMS=$(cat src/*.h | while read a b; do
|
||||
if [[ ${a} == "};" ]]; then
|
||||
ENUM=0;
|
||||
|
@ -76,7 +79,7 @@ ENUMS=$(cat src/*.h | while read a b; do
|
|||
if [[ ${a} == "enum" ]]; then
|
||||
ENUM=1;
|
||||
fi;
|
||||
done)
|
||||
done | grep -v "^//")
|
||||
for i in ${LITERALS} ${CONSTS} ${ENUMS}; do
|
||||
echo -e "${i}\tLITERAL1"
|
||||
done | sort -u
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/python
|
||||
#!/usr/bin/python
|
||||
"""Convert IRremoteESP8266's Raw data output into Pronto Code."""
|
||||
#
|
||||
# Copyright 2020 David Conran
|
||||
|
@ -16,7 +16,7 @@ def parse_and_report(rawdata_str, hertz=38000, end_usecs=100000,
|
|||
# Parse the input.
|
||||
rawdata = convert_rawdata(rawdata_str)
|
||||
if verbose:
|
||||
output.write("Found %d timing entries.\n" % len(rawdata))
|
||||
output.write(f"Found {len(rawdata)} timing entries.\n")
|
||||
|
||||
# Do we need to pad out the rawdata to make it even in length?
|
||||
if end_usecs > 0 and len(rawdata) % 2 == 1:
|
||||
|
@ -26,29 +26,29 @@ def parse_and_report(rawdata_str, hertz=38000, end_usecs=100000,
|
|||
# Work out the frequency code.
|
||||
pronto_freq = int(1000000.0 / (hertz * 0.241246))
|
||||
if verbose:
|
||||
output.write("Pronto frequency is %X (%d Hz).\n" % (pronto_freq, hertz))
|
||||
result.append("%04X" % pronto_freq)
|
||||
output.write(f"Pronto frequency is {pronto_freq:X} ({hertz} Hz).\n")
|
||||
result.append(f"{pronto_freq:04X}")
|
||||
period = 1000000.0 / max(1, hertz)
|
||||
if verbose:
|
||||
output.write("Pronto period is %f uSecs.\n" % period)
|
||||
output.write(f"Pronto period is {period} uSecs.\n")
|
||||
# Add the lengths to the code.
|
||||
if use_initial:
|
||||
result.append("%04x" % int(len(rawdata) / 2)) # Initial burst code length
|
||||
result.append("%04x" % 0) # No Repeat code length
|
||||
result.append(f"{int(len(rawdata) / 2):04x}") # Initial burst code length
|
||||
result.append("0000") # No Repeat code length
|
||||
else:
|
||||
result.append("%04x" % 0) # No Initial burst code length
|
||||
result.append("%04x" % int(len(rawdata) / 2)) # Repeat code length
|
||||
result.append("0000") # No Initial burst code length
|
||||
result.append(f"{int(len(rawdata) / 2):04x}") # Repeat code length
|
||||
|
||||
# Add the data.
|
||||
if verbose:
|
||||
output.write("Raw data: %s " % rawdata)
|
||||
output.write(f"Raw data: {rawdata} ")
|
||||
for i in rawdata:
|
||||
result.append("%04x" % int(i / period))
|
||||
result.append(f"{int(i / period):04x}")
|
||||
if generate_code:
|
||||
output.write("uint16_t pronto[%d] = {0x%s};\n" % (len(result),
|
||||
", 0x".join(result)))
|
||||
output.write(f"uint16_t pronto[{len(result)}] = "
|
||||
f"{{0x{', 0x'.join(result)}}};\n")
|
||||
else:
|
||||
output.write("Pronto code = '%s'\n" % " ".join(result))
|
||||
output.write(f"Pronto code = '{' '.join(result)}'\n")
|
||||
# pylint: enable=too-many-arguments
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,426 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Generate SupportedProtocols.md by scraping source code files"""
|
||||
import pathlib
|
||||
import argparse
|
||||
import subprocess
|
||||
from io import StringIO
|
||||
import sys
|
||||
import re
|
||||
import time
|
||||
|
||||
CODE_URL = "https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_"
|
||||
|
||||
BRAND_MODEL = re.compile(r"""
|
||||
Brand:\s{1,20} # "Brand:" label followd by between 1 and 20 whitespace chars.
|
||||
\b(?P<brand>.{1,40})\b # The actual brand of the device, max 40 chars.
|
||||
\s{0,10}, # Followed by at most 10 whitespace chars, then a comma.
|
||||
\s{1,20} # The between 1 and 20 whitespace chars.
|
||||
Model:\s{1,20} # "Model:" label followd by between 1 and 20 whitespace chars.
|
||||
\b(?P<model>.{1,80}) # The model info of the device, max 80 chars.
|
||||
\s{0,5}$ # Followed by at most 5 whitespaces before the end of line.
|
||||
""", re.VERBOSE)
|
||||
ENUMS = re.compile(r"enum (\w{1,60}) {(.{1,5000}?)};", re.DOTALL)
|
||||
ENUM_ENTRY = re.compile(r"^\s{1,80}(\w{1,80})", re.MULTILINE)
|
||||
DECODED_PROTOCOLS = re.compile(r"""
|
||||
.{0,80} # Ignore upto an 80 char line of whitespace/code etc.
|
||||
# Now look for code that looks like we are assigning the Protocol type.
|
||||
# There are two typical styles used:
|
||||
(?:results->decode_type # The first style.
|
||||
| # Or
|
||||
typeguess) # The second style
|
||||
\s{0,5}=\s{0,5} # The assignment operator and potential whitespace
|
||||
(?:decode_type_t::)? # The protocol could have an optional type prefix.
|
||||
(\w{1,40}); # Finally, the last word of code should be the Protocol.
|
||||
""", re.VERBOSE)
|
||||
AC_FN = re.compile(r"ir_(.{1,80})\.h")
|
||||
AC_MODEL_ENUM_RE = re.compile(r"(.{1,40})_ac_remote_model_t")
|
||||
IRSEND_FN_RE = re.compile(r"IRsend\.h")
|
||||
ALL_FN = re.compile(r"ir_(.{1,80})\.(h|cpp)")
|
||||
|
||||
EXCLUDED_PROTOCOLS = ["UNKNOWN", "UNUSED", "kLastDecodeType", "typeguess"]
|
||||
EXCLUDED_ACS = ["Magiquest", "NEC"]
|
||||
|
||||
def getgitcommittime():
|
||||
"""Call git to get time of last commit
|
||||
"""
|
||||
try:
|
||||
label = subprocess.check_output(\
|
||||
["git", "show", "-s", "--format=%ct", "HEAD"]).strip()
|
||||
return int(label)
|
||||
except FileNotFoundError as err:
|
||||
print("Git failed, which is ok, no git binary found?:", err)
|
||||
return None
|
||||
except subprocess.SubprocessError as err:
|
||||
print("Git failed, which is ok, see output, maybe no git checkout?:", err)
|
||||
return None
|
||||
|
||||
def getmarkdownheader():
|
||||
"""Get the generated header
|
||||
"""
|
||||
srctime = getgitcommittime()
|
||||
# pylint: disable=C0209
|
||||
return """<!--- WARNING: Do NOT edit this file directly.
|
||||
It is generated by './tools/scrape_supported_devices.py'.
|
||||
Last generated: {} --->""".format(
|
||||
time.strftime("%a %d %b %Y %H:%M:%S +0000", time.gmtime(srctime)))
|
||||
# pylint: enable=C0209
|
||||
|
||||
|
||||
|
||||
def getallprotocols():
|
||||
"""Return all protocls configured in IRremoteESP8266.h
|
||||
"""
|
||||
irremote = ARGS.directory / "IRremoteESP8266.h"
|
||||
enums = getenums(irremote)["decode_type_t"]
|
||||
if not enums:
|
||||
errorexit("Error getting ENUMS from IRremoteESP8266.h")
|
||||
return enums
|
||||
|
||||
|
||||
def getdecodedprotocols():
|
||||
"""All protocols that include decoding support"""
|
||||
ret = set()
|
||||
for path in ARGS.directory.iterdir():
|
||||
if path.suffix != ".cpp":
|
||||
continue
|
||||
matches = DECODED_PROTOCOLS.finditer(path.open(encoding="utf-8").read())
|
||||
for match in matches:
|
||||
protocol = match.group(1)
|
||||
if protocol not in EXCLUDED_PROTOCOLS:
|
||||
ret.add(protocol)
|
||||
return ret
|
||||
|
||||
|
||||
def getallacs():
|
||||
"""All supported A/C codes"""
|
||||
ret = {}
|
||||
for path in ARGS.directory.iterdir():
|
||||
match = AC_FN.match(path.name)
|
||||
if match:
|
||||
acprotocol = match.group(1)
|
||||
rawmodels = getenums(path)
|
||||
models = set()
|
||||
for model in rawmodels:
|
||||
model = model.upper()
|
||||
model = model.replace(f"K{acprotocol.upper()}", "")
|
||||
if model and model not in EXCLUDED_PROTOCOLS:
|
||||
models.add(model)
|
||||
if acprotocol in ret:
|
||||
ret[acprotocol].update(models)
|
||||
else:
|
||||
ret[acprotocol] = models
|
||||
# Parse IRsend.h's enums
|
||||
match = IRSEND_FN_RE.match(path.name)
|
||||
if match:
|
||||
rawmodels = getenums(path)
|
||||
for acprotocol, acmodels in rawmodels.items():
|
||||
models = set()
|
||||
for model in acmodels:
|
||||
model = model.upper()
|
||||
model = model.replace(f"K{acprotocol.upper()}", "")
|
||||
if model and model not in EXCLUDED_PROTOCOLS:
|
||||
models.add(model)
|
||||
if acprotocol in ret:
|
||||
ret[acprotocol].update(models)
|
||||
else:
|
||||
ret[acprotocol] = models
|
||||
return ret
|
||||
|
||||
class FnSets():
|
||||
"""Container for getalldevices"""
|
||||
def __init__(self):
|
||||
self.allcodes = {}
|
||||
self.fnnomatch = set()
|
||||
self.allhfileprotos = set()
|
||||
self.fnhmatch = set()
|
||||
self.fncppmatch = set()
|
||||
|
||||
def add(self, supports, path):
|
||||
"""add the path to correct set based on supports"""
|
||||
if path.suffix == ".h":
|
||||
self.allhfileprotos.add(path.stem)
|
||||
if supports:
|
||||
if path.suffix == ".h":
|
||||
self.fnhmatch.add(path.stem)
|
||||
elif path.suffix == ".cpp":
|
||||
self.fncppmatch.add(path.stem)
|
||||
else:
|
||||
self.fnnomatch.add(path.stem)
|
||||
|
||||
def printwarnings(self):
|
||||
"""print warnings"""
|
||||
# all protos with support in .cpp file, when there is a .h file
|
||||
# meaning that the documentation should probably be moved to .h
|
||||
# in the future, with doxygen, that might change
|
||||
protosincppwithh = list(self.fncppmatch & self.allhfileprotos)
|
||||
if protosincppwithh:
|
||||
protosincppwithh.sort()
|
||||
print("The following files has supports section in .cpp, expected in .h")
|
||||
for path in protosincppwithh:
|
||||
print(f"\t{path}")
|
||||
|
||||
protosincppandh = list(self.fncppmatch & self.fnhmatch)
|
||||
if protosincppandh:
|
||||
protosincppandh.sort()
|
||||
print("The following files has supports section in both .h and .cpp")
|
||||
for path in protosincppandh:
|
||||
print(f"\t{path}")
|
||||
|
||||
nosupports = self.getnosupports()
|
||||
if nosupports:
|
||||
nosupports.sort()
|
||||
print("The following files had no supports section:")
|
||||
for path in nosupports:
|
||||
print(f"\t{path}")
|
||||
|
||||
return protosincppwithh or protosincppandh or nosupports
|
||||
|
||||
def getnosupports(self):
|
||||
"""get protos without supports sections"""
|
||||
return list(self.fnnomatch - self.fnhmatch - self.fncppmatch)
|
||||
|
||||
|
||||
def getalldevices():
|
||||
"""All devices and associated branding and model information (if available)
|
||||
"""
|
||||
sets = FnSets()
|
||||
for path in ARGS.directory.iterdir():
|
||||
match = ALL_FN.match(path.name)
|
||||
if not match:
|
||||
continue
|
||||
supports = extractsupports(path)
|
||||
sets.add(supports, path)
|
||||
protocol = match.group(1)
|
||||
for brand, model in supports:
|
||||
protocolbrand = (protocol, brand)
|
||||
pbset = sets.allcodes.get(protocolbrand, [])
|
||||
if model in pbset:
|
||||
print(f"Model {model} is duplicated for {protocol}, {brand}")
|
||||
sets.allcodes[protocolbrand] = pbset + [model]
|
||||
|
||||
for fnprotocol in sets.getnosupports():
|
||||
sets.allcodes[(fnprotocol[3:], "Unknown")] = []
|
||||
return sets
|
||||
|
||||
|
||||
def getenums(path):
|
||||
"""Returns the keys for the first enum type in path
|
||||
"""
|
||||
ret = {}
|
||||
for enums in ENUMS.finditer(path.open(encoding="utf-8").read()):
|
||||
if enums:
|
||||
enum_name = AC_MODEL_ENUM_RE.search(enums.group(1))
|
||||
if enum_name:
|
||||
enum_name = enum_name.group(1).capitalize()
|
||||
else:
|
||||
enum_name = enums.group(1)
|
||||
ret[enum_name] = set()
|
||||
for enum in ENUM_ENTRY.finditer(enums.group(2)):
|
||||
enum = enum.group(1)
|
||||
if enum in EXCLUDED_PROTOCOLS:
|
||||
continue
|
||||
ret[enum_name].add(enum)
|
||||
return ret
|
||||
|
||||
|
||||
ARGS = None
|
||||
|
||||
|
||||
def initargs():
|
||||
"""Init the command line arguments"""
|
||||
global ARGS # pylint: disable=global-statement
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"-n",
|
||||
"--noout",
|
||||
help="generate no output data, combine with --alert to only check",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--stdout",
|
||||
help="output to stdout rather than SupportedProtocols.md",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument("-v",
|
||||
"--verbose",
|
||||
help="increase output verbosity",
|
||||
action="store_true")
|
||||
parser.add_argument(
|
||||
"-a",
|
||||
"--alert",
|
||||
help="alert if a file does not have a supports section, "
|
||||
"non zero exit code if issues where found",
|
||||
action="store_true",
|
||||
)
|
||||
parser.add_argument(
|
||||
"directory",
|
||||
nargs="?",
|
||||
help="directory of the source git checkout",
|
||||
default=None,
|
||||
)
|
||||
ARGS = parser.parse_args()
|
||||
if ARGS.directory is None:
|
||||
src = pathlib.Path("../src")
|
||||
if not src.is_dir():
|
||||
src = pathlib.Path("./src")
|
||||
else:
|
||||
src = pathlib.Path(ARGS.directory) / "src"
|
||||
if not src.is_dir():
|
||||
errorexit(f"Directory not valid: {src!s}")
|
||||
ARGS.directory = src
|
||||
return ARGS
|
||||
|
||||
def getmdfile():
|
||||
"""Resolves SupportedProtocols.md path"""
|
||||
foutpath = ARGS.directory / "../SupportedProtocols.md"
|
||||
return foutpath.resolve()
|
||||
|
||||
def errorexit(msg):
|
||||
"""Print an error and exit on critical error"""
|
||||
sys.stderr.write(f"{msg}\n")
|
||||
sys.exit(1)
|
||||
|
||||
def extractsupports(path):
|
||||
"""Extract all of the Supports: sections and associated brands and models
|
||||
"""
|
||||
supports = []
|
||||
insupports = False
|
||||
for line in path.open(encoding="utf-8"):
|
||||
if not line.startswith("//"):
|
||||
continue
|
||||
line = line[2:].strip()
|
||||
if line == "Supports:":
|
||||
insupports = True
|
||||
continue
|
||||
if insupports:
|
||||
match = BRAND_MODEL.match(line)
|
||||
if match:
|
||||
supports.append((match.group("brand"), match.group("model")))
|
||||
else:
|
||||
insupports = False
|
||||
continue
|
||||
# search and inform about any legacy formated supports data
|
||||
elif any(x in line for x in [ \
|
||||
"seems compatible with",
|
||||
"be compatible with",
|
||||
"it working with here"]):
|
||||
print(f"\t{path.name} Legacy supports format found\n\t\t{line}")
|
||||
return supports
|
||||
|
||||
|
||||
def makeurl(txt, path):
|
||||
"""Make a Markup URL from given filename"""
|
||||
return f"[{txt}]({CODE_URL + path})"
|
||||
|
||||
|
||||
def outputprotocols(fout, protocols):
|
||||
"""For a given protocol set, sort and output the markdown"""
|
||||
protocols = list(protocols)
|
||||
protocols.sort()
|
||||
for protocol in protocols:
|
||||
fout.write(f"- {protocol}\n")
|
||||
|
||||
|
||||
def generate(fout):
|
||||
"""Generate data to fout
|
||||
return True on any issues (when alert is active)"""
|
||||
decodedprotocols = getdecodedprotocols()
|
||||
sendonly = getallprotocols() - decodedprotocols
|
||||
allacs = getallacs()
|
||||
|
||||
sets = getalldevices()
|
||||
allcodes = sets.allcodes
|
||||
allbrands = list(allcodes.keys())
|
||||
allbrands.sort()
|
||||
|
||||
fout.write("\n# IR Protocols supported by this library\n\n")
|
||||
fout.write(
|
||||
"| Protocol | Brand | Model | A/C Model | Detailed A/C Support |\n")
|
||||
fout.write("| --- | --- | --- | --- | --- |\n")
|
||||
|
||||
for protocolbrand in allbrands:
|
||||
protocol, brand = protocolbrand
|
||||
codes = allcodes[protocolbrand]
|
||||
codes.sort()
|
||||
acmodels = []
|
||||
acsupport = "-"
|
||||
if protocol in allacs:
|
||||
acmodels = list(allacs[protocol])
|
||||
acmodels.sort()
|
||||
brand = makeurl(brand, protocol + ".h")
|
||||
if protocol not in EXCLUDED_ACS:
|
||||
acsupport = "Yes"
|
||||
# pylint: disable=C0209
|
||||
fout.write("| {} | **{}** | {} | {} | {} |\n".format(
|
||||
makeurl(protocol, protocol + ".cpp"),
|
||||
brand,
|
||||
"<BR>".join(codes).replace("|", "\\|"),
|
||||
"<BR>".join(acmodels),
|
||||
acsupport,
|
||||
))
|
||||
# pylint: enable=C0209
|
||||
|
||||
fout.write("\n\n## Send only protocols:\n\n")
|
||||
outputprotocols(fout, sendonly)
|
||||
|
||||
fout.write("\n\n## Send & decodable protocols:\n\n")
|
||||
outputprotocols(fout, decodedprotocols)
|
||||
|
||||
return ARGS.alert and sets.printwarnings()
|
||||
|
||||
def generatenone():
|
||||
"""No out write
|
||||
return True on any issues"""
|
||||
return generate(StringIO())
|
||||
|
||||
def generatestdout():
|
||||
"""Standard out write
|
||||
return True on any issues"""
|
||||
fout = sys.stdout
|
||||
fout.write(getmarkdownheader())
|
||||
return generate(fout)
|
||||
|
||||
def generatefile():
|
||||
"""File write, extra detection of changes in existing file
|
||||
return True on any issues, but only if there is changes"""
|
||||
# get file path
|
||||
foutpath = getmdfile()
|
||||
if ARGS.verbose:
|
||||
print(f"Output path: {foutpath!s}")
|
||||
# write data to temp memorystream
|
||||
ftemp = StringIO()
|
||||
ret = generate(ftemp)
|
||||
# get old filedata, skipping header
|
||||
with getmdfile().open("r", encoding="utf-8") as forg:
|
||||
olddata = forg.readlines()[3:]
|
||||
# get new data, skip first empty line
|
||||
ftemp.seek(0)
|
||||
newdata = ftemp.readlines()[1:]
|
||||
# if new data is same as old we don't need to write anything
|
||||
if newdata == olddata:
|
||||
print("No changes, exit without write")
|
||||
return False
|
||||
# write output
|
||||
with foutpath.open("w", encoding="utf-8") as fout:
|
||||
fout.write(getmarkdownheader())
|
||||
fout.write(ftemp.getvalue())
|
||||
|
||||
return ret
|
||||
|
||||
def main():
|
||||
"""Default main function
|
||||
return True on any issues"""
|
||||
initargs()
|
||||
if ARGS.verbose:
|
||||
print(f"Looking for files in: {ARGS.directory.resolve()!s}")
|
||||
if ARGS.noout:
|
||||
return generatenone()
|
||||
if ARGS.stdout:
|
||||
return generatestdout()
|
||||
# default file
|
||||
return generatefile()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(1 if main() else 0)
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "IRremoteESP8266",
|
||||
"version": "2.7.19",
|
||||
"version": "2.8.0",
|
||||
"keywords": "infrared, ir, remote, esp8266, esp32",
|
||||
"description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)",
|
||||
"repository":
|
||||
|
@ -48,8 +48,6 @@
|
|||
"frameworks": "arduino",
|
||||
"platforms": ["espressif8266", "espressif32"],
|
||||
|
||||
|
||||
|
||||
"build": {
|
||||
"srcDir": "IRremoteESP8266/src",
|
||||
"flags": [ "-I$PROJECT_DIR/include", "-includetasmota_options.h" ]
|
||||
|
|
Loading…
Reference in New Issue