diff --git a/lib/IRremoteESP8266-2.6.5/.github/CONTRIBUTING.md b/lib/IRremoteESP8266-2.6.5/.github/CONTRIBUTING.md deleted file mode 100755 index 20bb97d94..000000000 --- a/lib/IRremoteESP8266-2.6.5/.github/CONTRIBUTING.md +++ /dev/null @@ -1,82 +0,0 @@ -# Contributing to the IRremoteESP8266 library - -:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: - -The following is a set of guidelines for contributing to the IRremoteESP8266 library, hosted on GitHub. These are guidelines, [not rules](http://imgur.com/mSHi8). Use your best judgment, and feel free to propose changes to this document in a pull request. - -#### Table Of Contents - -[Code of Conduct](#code-of-conduct) - -[How Can I Contribute?](#how-can-i-contribute) - * [Reporting Bugs](#reporting-bugs) - * [Pull Requests](#pull-requests) - -[Styleguides](#styleguides) - * [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) - * [Git Commit Messages](#git-commit-messages) - - -## Code of Conduct - -This project and everyone participating in it is governed by the principle of ["Be excellent to each other"](http://www.imdb.com/title/tt0096928/quotes). That's it. TL;DR: _Don't be a jerk._ - -## How Can I Contribute? - -### Reporting Bugs - -This section guides you through submitting a bug report for the library. Following these guidelines helps maintainers and the community understand your report :pencil:, reproduce the behavior :computer: :computer:, and find related reports :mag_right:. - -Before creating bug reports, please check [this list](#before-submitting-a-bug-report) as you might find out that you don't need to create one. When you are creating a bug report, please [include as much detail as possible](#how-do-i-submit-a-good-bug-report). Fill out [the required template](issue_template.md), the information it asks for helps us resolve issues faster. - -> **Note:** If you find a **Closed** issue that seems like it's the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one. - -#### Before Submitting A Bug Report - -* **Check the [Troubleshooting Guide](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Troubleshooting-Guide).** You might be able to find the cause of the problem and fix it yourself. Most importantly, check if you can reproduce the problem in the latest version (a.k.a. 'master') of the library. -* **Perform a [cursory search](https://github.com/issues?q=+is%3Aissue+repo%3Acrankyoldgit/IRremoteESP8266)** to see if the problem is already reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one. - -#### How Do I Submit A (Good) Bug Report? - -Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). Create an issue and provide the following information by filling in [the template](issue_template.md). - -Explain the problem and include any additional details to help maintainers reproduce the problem: - -* **Use a clear and descriptive title** for the issue to identify the problem. -* **Describe the exact steps which reproduce the problem** in as much detail as possible. -* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, use [Markdown code blocks](https://help.github.com/articles/markdown-basics/#multiple-lines). -* **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. -* **Explain which behavior you expected to see instead and why.** -* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below. - -Provide more context by answering these questions: - -* **Can you reproduce the problem in one of the code examples?** -* **Did the problem start happening recently** (e.g. after updating to a new version of Arduino or the library) or was this always a problem? -* If the problem started happening recently, **can you reproduce the problem in an older version of the library?** What's the most recent version in which the problem doesn't happen? You can download older versions of the library from [the releases page](https://github.com/crankyoldgit/IRremoteESP8266/releases). -* **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens. - -Include details about your configuration, circuit and environment: - -* **Which version of the library are you using?** You can get the exact version by inspecting the `library.json` file in the root directory of the library. -* **What board are you running this on?** - -### Pull Requests - -* Do not include issue numbers in the PR title -* Include as much data and comments as practicle. -* Follow the [C++ style guide](https://google.github.io/styleguide/cppguide.html). -* Please write or ensure Unit Tests cover the change you are making, if you can. -* End all files with a newline -* 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. -* State if you have tested this under real conditions if you have, and what other tests you may have carried out. - -### Git Commit Messages - -* Limit the first line to 72 characters or less -* Reference issues and pull requests liberally after the first line -* Humour is always acceptable. Be liberal with it. ;-) -* While not required, a comprehensive description of all the changes in the PR is best. diff --git a/lib/IRremoteESP8266-2.6.5/.github/Contributors.md b/lib/IRremoteESP8266-2.6.5/.github/Contributors.md deleted file mode 100755 index a4958fe70..000000000 --- a/lib/IRremoteESP8266-2.6.5/.github/Contributors.md +++ /dev/null @@ -1,20 +0,0 @@ -## Contributors of this project -### Main contributors & maintainers -- [Mark Szabo](https://github.com/markszabo/) : Initial IR sending on ESP8266 -- [Sébastien Warin](https://github.com/sebastienwarin/) (http://sebastien.warin.fr) : Initial IR receiving on ESP8266 -- [David Conran](https://github.com/crankyoldgit/) : ESP32 support and pretty much everything else. -- [Roi Dayan](https://github.com/roidayan/) -- [Marcos de Alcântara Marinho](https://github.com/marcosamarinho/) -- [Massimiliano Pinto](https://github.com/pintomax/) -- [Darsh Patel](https://github.com/darshkpatel/) -- [Jonny Graham](https://github.com/jonnygraham/) -- [Stu Fisher](https://github.com/stufisher/) -- [Jorge Cisneros](https://github.com/jorgecis/) -- [Denes Varga](https://github.com/denxhun/) -- [Brett T. Warden](https://github.com/bwarden/) -- [Fabien Valthier](https://github.com/hcoohb) -- [Ajay Pala](https://github.com/ajaypala/) - -All contributors can be found on the [contributors site](https://github.com/crankyoldgit/IRremoteESP8266/graphs/contributors). - -### Contributors of the [original project](https://github.com/z3t0/Arduino-IRremote) can be found on the [original project's contributors page](https://github.com/z3t0/Arduino-IRremote/blob/master/Contributors.md) diff --git a/lib/IRremoteESP8266-2.6.5/.github/issue_template.md b/lib/IRremoteESP8266-2.6.5/.github/issue_template.md deleted file mode 100755 index d9b80dab6..000000000 --- a/lib/IRremoteESP8266-2.6.5/.github/issue_template.md +++ /dev/null @@ -1,42 +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._ - -### 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._ diff --git a/lib/IRremoteESP8266-2.6.5/.gitignore b/lib/IRremoteESP8266-2.6.5/.gitignore deleted file mode 100755 index c02171953..000000000 --- a/lib/IRremoteESP8266-2.6.5/.gitignore +++ /dev/null @@ -1,53 +0,0 @@ -#----------------------------------------# -# .gitingore for IRremoteESP8266 library # -#----------------------------------------# - -### Files to ignore. - -## Editors -# vi/vim -**/*.swp - -# vscode -.vscode - -## Build environments -# Platformio -**/.pio/ -**/.pioenvs/ -**/.piolibdeps/ -**/.clang_complete -**/.gcc-flags.json -examples/**/lib -examples/**/.travis.yml -examples/**/.gitignore -lib/readme.txt -lib/googletest/**/* - -# GCC pre-compiled headers. -**/*.gch - -# Python compiled files -**/*.pyc - -# Unit Test builds -test/*.o -test/*.a -test/*_test - -# Tools builds -tools/*.o -tools/*.a -tools/gc_decode -tools/mode2_decode - -.pioenvs -.piolibdeps -.clang_complete -.gcc-flags.json - -#Cygwin builds -*.exe - -# Mac extended attributes -.DS_Store diff --git a/lib/IRremoteESP8266-2.6.5/.gitmodules b/lib/IRremoteESP8266-2.6.5/.gitmodules deleted file mode 100755 index c28fe0509..000000000 --- a/lib/IRremoteESP8266-2.6.5/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "lib/googletest"] - path = lib/googletest - url = https://github.com/google/googletest.git - branch = v1.8.x diff --git a/lib/IRremoteESP8266-2.6.5/.style.yapf b/lib/IRremoteESP8266-2.6.5/.style.yapf deleted file mode 100755 index 65fa0ee33..000000000 --- a/lib/IRremoteESP8266-2.6.5/.style.yapf +++ /dev/null @@ -1,3 +0,0 @@ -[style] -based_on_style: google -indent_width: 2 diff --git a/lib/IRremoteESP8266-2.6.5/.travis.yml b/lib/IRremoteESP8266-2.6.5/.travis.yml deleted file mode 100755 index e8bf3d832..000000000 --- a/lib/IRremoteESP8266-2.6.5/.travis.yml +++ /dev/null @@ -1,74 +0,0 @@ -language: c -env: - - BD=esp8266:esp8266:nodemcuv2:xtal=80,eesz=4M3M,ip=lm2f,exception=disabled - # - BD=esp8266:esp8266:d1_mini:xtal=80,eesz=4M3M,ip=lm2f,exception=disabled -before_install: - - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16" - - sleep 3 - - export DISPLAY=:1.0 - - wget http://downloads.arduino.cc/arduino-1.8.8-linux64.tar.xz - - tar xf arduino-1.8.8-linux64.tar.xz - - sudo mv arduino-1.8.8 /usr/local/share/arduino - - sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino - - wget https://raw.githubusercontent.com/google/styleguide/gh-pages/cpplint/cpplint.py -install: - - ln -s $PWD /usr/local/share/arduino/libraries/ - - git clone https://github.com/tzapu/WiFiManager.git /usr/local/share/arduino/libraries/WiFiManager - - git clone https://github.com/knolleary/pubsubclient.git /usr/local/share/arduino/libraries/PubSubClient - - git clone https://github.com/bblanchon/ArduinoJson.git --branch 5.x /usr/local/share/arduino/libraries/ArduinoJson - - arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json" --save-prefs - - arduino --install-boards esp8266:esp8266 - - arduino --board $BD --save-prefs - - arduino --pref "compiler.warning_level=all" --save-prefs - - sudo apt-get install jq - - sudo apt-get purge python-enum34 - - sudo apt-get install pylint3 -script: echo Running checks -notifications: - email: - on_success: change - on_failure: change -jobs: - include: - - script: - # Check that everything compiles. (Part 1) - - arduino --verify --board $BD $PWD/examples/IRrecvDemo/IRrecvDemo.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/IRGCSendDemo/IRGCSendDemo.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/IRGCTCPServer/IRGCTCPServer.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/IRServer/IRServer.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/IRrecvDumpV2/IRrecvDumpV2.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/IRsendDemo/IRsendDemo.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino 2> /dev/null - - script: - # Check that everything compiles. (Part 2) - - arduino --verify --board $BD $PWD/examples/IRsendProntoDemo/IRsendProntoDemo.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/LGACSend/LGACSend.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/TurnOnArgoAC/TurnOnArgoAC.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/IRMQTTServer/IRMQTTServer.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/ControlSamsungAC/ControlSamsungAC.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/DumbIRRepeater/DumbIRRepeater.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/SmartIRRepeater/SmartIRRepeater.ino 2> /dev/null - - arduino --verify --board $BD $PWD/examples/CommonAcControl/CommonAcControl.ino 2> /dev/null - - script: - # 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,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) diff --git a/lib/IRremoteESP8266-2.6.5/examples/CommonAcControl/CommonAcControl.ino b/lib/IRremoteESP8266-2.6.5/examples/CommonAcControl/CommonAcControl.ino deleted file mode 100755 index 6f0416b51..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/CommonAcControl/CommonAcControl.ino +++ /dev/null @@ -1,81 +0,0 @@ -/* Copyright 2019 David Conran -* -* This example code demonstrates how to use the "Common" IRac class to control -* various air conditions. The IRac class does not support all the features -* for every protocol. Some have more detailed support that what the "Common" -* interface offers, and some only have a limited subset of the "Common" options. -* -* This example code will: -* o Try to turn on, then off every fully supported A/C protocol we know of. -* o It will try to put the A/C unit into Cooling mode at 25C, with a medium -* fan speed, and no fan swinging. -* Note: Some protocols support multiple models, only the first model is tried. -* -*/ -#include -#include -#include -#include - -const uint16_t kIrLed = 4; // The ESP GPIO pin to use that controls the IR LED. -IRac ac(kIrLed); // Create a A/C object using GPIO to sending messages with. -stdAc::state_t state; // Where we will store the desired state of the A/C. -stdAc::state_t prev; // Where we will store the previous state of the A/C. - -void setup() { - Serial.begin(115200); - delay(200); - - // Set up what we want to send. - // See state_t, opmode_t, fanspeed_t, swingv_t, & swingh_t in IRsend.h for - // all the various options. - state.protocol = decode_type_t::DAIKIN; // Set a protocol to use. - state.model = 1; // Some A/C's have different models. Let's try using just 1. - state.mode = stdAc::opmode_t::kCool; // Run in cool mode initially. - state.celsius = true; // Use Celsius for units of temp. False = Fahrenheit - state.degrees = 25; // 25 degrees. - state.fanspeed = stdAc::fanspeed_t::kMedium; // Start with the fan at medium. - state.swingv = stdAc::swingv_t::kOff; // Don't swing the fan up or down. - state.swingh = stdAc::swingh_t::kOff; // Don't swing the fan left or right. - state.light = false; // Turn off any LED/Lights/Display that we can. - state.beep = false; // Turn off any beep from the A/C if we can. - state.econo = false; // Turn off any economy modes if we can. - state.filter = false; // Turn off any Ion/Mold/Health filters if we can. - state.turbo = false; // Don't use any turbo/powerful/etc modes. - state.quiet = false; // Don't use any quiet/silent/etc modes. - state.sleep = -1; // Don't set any sleep time or modes. - state.clean = false; // Turn off any Cleaning options if we can. - state.clock = -1; // Don't set any current time if we can avoid it. - state.power = false; // Initially start with the unit off. - - prev = state; // Make sure we have a valid previous state. -} - -void loop() { - // For every protocol the library has ... - for (int i = 1; i < kLastDecodeType; i++) { - decode_type_t protocol = (decode_type_t)i; - // If the protocol is supported by the IRac class ... - if (ac.isProtocolSupported(protocol)) { - state.protocol = protocol; // Change the protocol used. - - Serial.println("Protocol " + String(protocol) + " / " + - typeToString(protocol)); - state.power = true; // We want to turn on the A/C unit. - // Have the IRac class create and send a message. - // We need a `prev` state as some A/Cs use toggle messages. - // e.g. On & Off are the same message. When given the previous state, - // it will try to do the correct thing for you. - ac.sendAc(state, &prev); // Construct and send the message. - Serial.println("Sent a message to turn ON the A/C unit."); - prev = state; // Copy new state over the previous one. - delay(5000); // Wait 5 seconds. - state.power = false; // Now we want to turn the A/C off. - ac.sendAc(state, &prev); // Construct and send the message. - Serial.println("Sent a message to turn OFF the A/C unit."); - prev = state; // Copy new state over the previous one. - delay(1000); // Wait 1 second. - } - } - Serial.println("Starting from the begining again ..."); -} diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRGCTCPServer/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/IRGCTCPServer/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/IRGCTCPServer/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRServer/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/IRServer/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/IRServer/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRrecvDemo/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/IRrecvDemo/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/IRrecvDemo/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRrecvDump/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/IRrecvDump/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/IRrecvDump/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRrecvDumpV2/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/IRrecvDumpV2/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/IRrecvDumpV2/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRsendDemo/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/IRsendDemo/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/IRsendDemo/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRsendProntoDemo/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/IRsendProntoDemo/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/IRsendProntoDemo/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/JVCPanasonicSendDemo/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/JVCPanasonicSendDemo/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/JVCPanasonicSendDemo/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/LGACSend/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/LGACSend/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/LGACSend/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/SmartIRRepeater/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/SmartIRRepeater/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/SmartIRRepeater/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnArgoAC/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/TurnOnArgoAC/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/TurnOnArgoAC/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnDaikinAC/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/TurnOnDaikinAC/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/TurnOnDaikinAC/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnFujitsuAC/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/TurnOnFujitsuAC/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/TurnOnFujitsuAC/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnKelvinatorAC/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/TurnOnKelvinatorAC/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/TurnOnKelvinatorAC/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnMitsubishiAC/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/TurnOnMitsubishiAC/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/TurnOnMitsubishiAC/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnMitsubishiHeavyAc/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/TurnOnMitsubishiHeavyAc/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/TurnOnMitsubishiHeavyAc/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnPanasonicAC/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/TurnOnPanasonicAC/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/TurnOnPanasonicAC/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnToshibaAC/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/TurnOnToshibaAC/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/TurnOnToshibaAC/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnTrotecAC/platformio.ini b/lib/IRremoteESP8266-2.6.5/examples/TurnOnTrotecAC/platformio.ini deleted file mode 100755 index 1aba0afcc..000000000 --- a/lib/IRremoteESP8266-2.6.5/examples/TurnOnTrotecAC/platformio.ini +++ /dev/null @@ -1,18 +0,0 @@ -[platformio] -src_dir = . - -[env] -lib_extra_dirs = ../../ -lib_ldf_mode = deep+ -lib_ignore = examples -build_flags = - -[env:nodemcuv2] -platform = espressif8266 -framework = arduino -board = nodemcuv2 - -[env:esp32dev] -platform = espressif32 -framework = arduino -board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Hitachi.cpp b/lib/IRremoteESP8266-2.6.5/src/ir_Hitachi.cpp deleted file mode 100755 index 0550816a9..000000000 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Hitachi.cpp +++ /dev/null @@ -1,442 +0,0 @@ -// Copyright 2018 David Conran -// -// Code to emulate Hitachi protocol compatible devices. -// Should be compatible with: -// * Hitachi RAS-35THA6 remote -// - -#include "ir_Hitachi.h" -#include -#ifndef ARDUINO -#include -#endif -#include "IRrecv.h" -#include "IRremoteESP8266.h" -#include "IRsend.h" -#include "IRutils.h" - -// Constants -// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/417 -const uint16_t kHitachiAcHdrMark = 3300; -const uint16_t kHitachiAcHdrSpace = 1700; -const uint16_t kHitachiAc1HdrMark = 3400; -const uint16_t kHitachiAc1HdrSpace = 3400; -const uint16_t kHitachiAcBitMark = 400; -const uint16_t kHitachiAcOneSpace = 1250; -const uint16_t kHitachiAcZeroSpace = 500; -const uint32_t kHitachiAcMinGap = kDefaultMessageGap; // Just a guess. - -using irutils::addBoolToString; -using irutils::addIntToString; -using irutils::addLabeledString; -using irutils::addModeToString; -using irutils::addFanToString; -using irutils::addTempToString; - -#if (SEND_HITACHI_AC || SEND_HITACHI_AC2) -// Send a Hitachi A/C message. -// -// Args: -// data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=kHitachiAcStateLength) -// repeat: Nr. of times the message is to be repeated. (Default = 0). -// -// Status: ALPHA / Untested. -// -// Ref: -// https://github.com/crankyoldgit/IRremoteESP8266/issues/417 -void IRsend::sendHitachiAC(const unsigned char data[], const uint16_t nbytes, - const uint16_t repeat) { - if (nbytes < kHitachiAcStateLength) - return; // Not enough bytes to send a proper message. - sendGeneric(kHitachiAcHdrMark, kHitachiAcHdrSpace, kHitachiAcBitMark, - kHitachiAcOneSpace, kHitachiAcBitMark, kHitachiAcZeroSpace, - kHitachiAcBitMark, kHitachiAcMinGap, data, nbytes, 38, true, - repeat, 50); -} -#endif // (SEND_HITACHI_AC || SEND_HITACHI_AC2) - -#if SEND_HITACHI_AC1 -// Send a Hitachi A/C 13-byte message. -// -// For devices: -// Hitachi A/C Series VI (Circa 2007) / Remote: LT0541-HTA -// -// Args: -// data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=kHitachiAc1StateLength) -// repeat: Nr. of times the message is to be repeated. (Default = 0). -// -// Status: BETA / Appears to work. -// -// Ref: -// https://github.com/crankyoldgit/IRremoteESP8266/issues/453 -// Basically the same as sendHitatchiAC() except different size and header. -void IRsend::sendHitachiAC1(const unsigned char data[], const uint16_t nbytes, - const uint16_t repeat) { - if (nbytes < kHitachiAc1StateLength) - return; // Not enough bytes to send a proper message. - sendGeneric(kHitachiAc1HdrMark, kHitachiAc1HdrSpace, kHitachiAcBitMark, - kHitachiAcOneSpace, kHitachiAcBitMark, kHitachiAcZeroSpace, - kHitachiAcBitMark, kHitachiAcMinGap, data, nbytes, 38, true, - repeat, 50); -} -#endif // SEND_HITACHI_AC1 - -#if SEND_HITACHI_AC2 -// Send a Hitachi A/C 53-byte message. -// -// For devices: -// Hitachi A/C Series VI (Circa 2007) / Remote: LT0541-HTA -// -// Args: -// data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=kHitachiAc2StateLength) -// repeat: Nr. of times the message is to be repeated. (Default = 0). -// -// Status: BETA / Appears to work. -// -// Ref: -// https://github.com/crankyoldgit/IRremoteESP8266/issues/417 -// Basically the same as sendHitatchiAC() except different size. -void IRsend::sendHitachiAC2(const unsigned char data[], const uint16_t nbytes, - const uint16_t repeat) { - if (nbytes < kHitachiAc2StateLength) - return; // Not enough bytes to send a proper message. - sendHitachiAC(data, nbytes, repeat); -} -#endif // SEND_HITACHI_AC2 - -// Class for handling the remote control on a Hitachi 28 byte A/C message. -// Inspired by: -// https://github.com/ToniA/arduino-heatpumpir/blob/master/HitachiHeatpumpIR.cpp - -IRHitachiAc::IRHitachiAc(const uint16_t pin, const bool inverted, - const bool use_modulation) - : _irsend(pin, inverted, use_modulation) { stateReset(); } - -void IRHitachiAc::stateReset(void) { - remote_state[0] = 0x80; - remote_state[1] = 0x08; - remote_state[2] = 0x0C; - remote_state[3] = 0x02; - remote_state[4] = 0xFD; - remote_state[5] = 0x80; - remote_state[6] = 0x7F; - remote_state[7] = 0x88; - remote_state[8] = 0x48; - remote_state[9] = 0x10; - for (uint8_t i = 10; i < kHitachiAcStateLength; i++) remote_state[i] = 0x00; - remote_state[14] = 0x60; - remote_state[15] = 0x60; - remote_state[24] = 0x80; - setTemp(23); -} - -void IRHitachiAc::begin(void) { _irsend.begin(); } - -uint8_t IRHitachiAc::calcChecksum(const uint8_t state[], - const uint16_t length) { - int8_t sum = 62; - for (uint16_t i = 0; i < length - 1; i++) sum -= reverseBits(state[i], 8); - return reverseBits((uint8_t)sum, 8); -} - -void IRHitachiAc::checksum(const uint16_t length) { - remote_state[length - 1] = calcChecksum(remote_state, length); -} - -bool IRHitachiAc::validChecksum(const uint8_t state[], const uint16_t length) { - if (length < 2) return true; // Assume true for lengths that are too short. - return (state[length - 1] == calcChecksum(state, length)); -} - -uint8_t *IRHitachiAc::getRaw(void) { - checksum(); - return remote_state; -} - -void IRHitachiAc::setRaw(const uint8_t new_code[], const uint16_t length) { - for (uint8_t i = 0; i < length && i < kHitachiAcStateLength; i++) - remote_state[i] = new_code[i]; -} - -#if SEND_HITACHI_AC -void IRHitachiAc::send(const uint16_t repeat) { - checksum(); - _irsend.sendHitachiAC(remote_state, kHitachiAcStateLength, repeat); -} -#endif // SEND_HITACHI_AC - -bool IRHitachiAc::getPower(void) { return (remote_state[17] & 0x01); } - -void IRHitachiAc::setPower(const bool on) { - if (on) - remote_state[17] |= 0x01; - else - remote_state[17] &= 0xFE; -} - -void IRHitachiAc::on(void) { setPower(true); } - -void IRHitachiAc::off(void) { setPower(false); } - -uint8_t IRHitachiAc::getMode(void) { return reverseBits(remote_state[10], 8); } - -void IRHitachiAc::setMode(const uint8_t mode) { - uint8_t newmode = mode; - switch (mode) { - case kHitachiAcFan: - // Fan mode sets a special temp. - setTemp(64); - break; - case kHitachiAcAuto: - case kHitachiAcHeat: - case kHitachiAcCool: - case kHitachiAcDry: - break; - default: - newmode = kHitachiAcAuto; - } - remote_state[10] = reverseBits(newmode, 8); - if (mode != kHitachiAcFan) setTemp(_previoustemp); - setFan(getFan()); // Reset the fan speed after the mode change. -} - -uint8_t IRHitachiAc::getTemp(void) { - return reverseBits(remote_state[11], 8) >> 1; -} - -void IRHitachiAc::setTemp(const uint8_t celsius) { - uint8_t temp; - if (celsius != 64) _previoustemp = celsius; - switch (celsius) { - case 64: - temp = celsius; - break; - default: - temp = std::min(celsius, kHitachiAcMaxTemp); - temp = std::max(temp, kHitachiAcMinTemp); - } - remote_state[11] = reverseBits(temp << 1, 8); - if (temp == kHitachiAcMinTemp) - remote_state[9] = 0x90; - else - remote_state[9] = 0x10; -} - -uint8_t IRHitachiAc::getFan(void) { return reverseBits(remote_state[13], 8); } - -void IRHitachiAc::setFan(const uint8_t speed) { - uint8_t fanmin = kHitachiAcFanAuto; - uint8_t fanmax = kHitachiAcFanHigh; - switch (getMode()) { - case kHitachiAcDry: // Only 2 x low speeds in Dry mode. - fanmin = kHitachiAcFanLow; - fanmax = kHitachiAcFanLow + 1; - break; - case kHitachiAcFan: - fanmin = kHitachiAcFanLow; // No Auto in Fan mode. - break; - } - uint8_t newspeed = std::max(speed, fanmin); - newspeed = std::min(newspeed, fanmax); - remote_state[13] = reverseBits(newspeed, 8); -} - -bool IRHitachiAc::getSwingVertical(void) { return remote_state[14] & 0x80; } - -void IRHitachiAc::setSwingVertical(const bool on) { - if (on) - remote_state[14] |= 0x80; - else - remote_state[14] &= 0x7F; -} - -bool IRHitachiAc::getSwingHorizontal(void) { return remote_state[15] & 0x80; } - -void IRHitachiAc::setSwingHorizontal(const bool on) { - if (on) - remote_state[15] |= 0x80; - else - remote_state[15] &= 0x7F; -} - - -// Convert a standard A/C mode into its native mode. -uint8_t IRHitachiAc::convertMode(const stdAc::opmode_t mode) { - switch (mode) { - case stdAc::opmode_t::kCool: - return kHitachiAcCool; - case stdAc::opmode_t::kHeat: - return kHitachiAcHeat; - case stdAc::opmode_t::kDry: - return kHitachiAcDry; - case stdAc::opmode_t::kFan: - return kHitachiAcFan; - default: - return kHitachiAcAuto; - } -} - -// Convert a standard A/C Fan speed into its native fan speed. -uint8_t IRHitachiAc::convertFan(const stdAc::fanspeed_t speed) { - switch (speed) { - case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kHitachiAcFanLow; - case stdAc::fanspeed_t::kMedium: - return kHitachiAcFanLow + 1; - case stdAc::fanspeed_t::kHigh: - return kHitachiAcFanHigh - 1; - case stdAc::fanspeed_t::kMax: - return kHitachiAcFanHigh; - default: - return kHitachiAcFanAuto; - } -} - -// Convert a native mode to it's common equivalent. -stdAc::opmode_t IRHitachiAc::toCommonMode(const uint8_t mode) { - switch (mode) { - case kHitachiAcCool: return stdAc::opmode_t::kCool; - case kHitachiAcHeat: return stdAc::opmode_t::kHeat; - case kHitachiAcDry: return stdAc::opmode_t::kDry; - case kHitachiAcFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; - } -} - -// Convert a native fan speed to it's common equivalent. -stdAc::fanspeed_t IRHitachiAc::toCommonFanSpeed(const uint8_t speed) { - switch (speed) { - case kHitachiAcFanHigh: return stdAc::fanspeed_t::kMax; - case kHitachiAcFanHigh - 1: return stdAc::fanspeed_t::kHigh; - case kHitachiAcFanLow + 1: return stdAc::fanspeed_t::kMedium; - case kHitachiAcFanLow: return stdAc::fanspeed_t::kLow; - default: return stdAc::fanspeed_t::kAuto; - } -} - -// Convert the A/C state to it's common equivalent. -stdAc::state_t IRHitachiAc::toCommon(void) { - stdAc::state_t result; - result.protocol = decode_type_t::HITACHI_AC; - result.model = -1; // No models used. - result.power = this->getPower(); - result.mode = this->toCommonMode(this->getMode()); - result.celsius = true; - result.degrees = this->getTemp(); - result.fanspeed = this->toCommonFanSpeed(this->getFan()); - result.swingv = this->getSwingVertical() ? stdAc::swingv_t::kAuto : - stdAc::swingv_t::kOff; - result.swingh = this->getSwingHorizontal() ? stdAc::swingh_t::kAuto : - stdAc::swingh_t::kOff; - // Not supported. - result.quiet = false; - result.turbo = false; - result.clean = false; - result.econo = false; - result.filter = false; - result.light = false; - result.beep = false; - result.sleep = -1; - result.clock = -1; - return result; -} - -// Convert the internal state into a human readable string. -String IRHitachiAc::toString(void) { - String result = ""; - result.reserve(110); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); - result += addModeToString(getMode(), kHitachiAcAuto, kHitachiAcCool, - kHitachiAcHeat, kHitachiAcDry, kHitachiAcFan); - result += addTempToString(getTemp()); - result += addFanToString(getFan(), kHitachiAcFanHigh, kHitachiAcFanLow, - kHitachiAcFanAuto, kHitachiAcFanAuto, - kHitachiAcFanMed); - result += addBoolToString(getSwingVertical(), F("Swing (Vertical)")); - result += addBoolToString(getSwingHorizontal(), F("Swing (Horizontal)")); - return result; -} - -#if (DECODE_HITACHI_AC || DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2) -// Decode the supplied Hitachi A/C message. -// -// Args: -// results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. -// Typically kHitachiAcBits, kHitachiAc1Bits, kHitachiAc2Bits -// strict: Flag indicating if we should perform strict matching. -// Returns: -// boolean: True if it can decode it, false if it can't. -// -// Status: ALPHA / Untested. -// -// Supported devices: -// Hitachi A/C Series VI (Circa 2007) / Remote: LT0541-HTA -// -// Ref: -// https://github.com/crankyoldgit/IRremoteESP8266/issues/417 -// https://github.com/crankyoldgit/IRremoteESP8266/issues/453 -bool IRrecv::decodeHitachiAC(decode_results *results, const uint16_t nbits, - const bool strict) { - const uint8_t k_tolerance = _tolerance + 5; - if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) - return false; // Can't possibly be a valid HitachiAC message. - if (strict) { - switch (nbits) { - case kHitachiAcBits: - case kHitachiAc1Bits: - case kHitachiAc2Bits: - break; // Okay to continue. - default: - return false; // Not strictly a Hitachi message. - } - } - uint16_t offset = kStartOffset; - uint16_t hmark; - uint32_t hspace; - if (nbits == kHitachiAc1Bits) { - hmark = kHitachiAc1HdrMark; - hspace = kHitachiAc1HdrSpace; - } else { - hmark = kHitachiAcHdrMark; - hspace = kHitachiAcHdrSpace; - } - // Match Header + Data + Footer - if (!matchGeneric(results->rawbuf + offset, results->state, - results->rawlen - offset, nbits, - hmark, hspace, - kHitachiAcBitMark, kHitachiAcOneSpace, - kHitachiAcBitMark, kHitachiAcZeroSpace, - kHitachiAcBitMark, kHitachiAcMinGap, true, - k_tolerance)) return false; - - // Compliance - if (strict) { - if (nbits / 8 == kHitachiAcStateLength && - !IRHitachiAc::validChecksum(results->state, kHitachiAcStateLength)) - return false; - } - - // Success - switch (nbits) { - case kHitachiAc1Bits: - results->decode_type = HITACHI_AC1; - break; - case kHitachiAc2Bits: - results->decode_type = HITACHI_AC2; - break; - case kHitachiAcBits: - default: - results->decode_type = HITACHI_AC; - } - 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_HITACHI_AC || DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2) diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Mitsubishi.cpp b/lib/IRremoteESP8266-2.6.5/src/ir_Mitsubishi.cpp deleted file mode 100755 index c78b1d21a..000000000 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Mitsubishi.cpp +++ /dev/null @@ -1,811 +0,0 @@ -// Copyright 2009 Ken Shirriff -// Copyright 2017-2018 David Conran -// Copyright 2018 Denes Varga - -// Mitsubishi - -#include "ir_Mitsubishi.h" -#include -#ifndef ARDUINO -#include -#endif -#include "IRrecv.h" -#include "IRsend.h" -#include "IRutils.h" - -// Mitsubishi (TV) decoding added from https://github.com/z3t0/Arduino-IRremote -// Mitsubishi (TV) sending & Mitsubishi A/C support added by David Conran - -// Constants -// Mitsubishi TV -// period time is 1/33000Hz = 30.303 uSeconds (T) -// Ref: -// GlobalCache's Control Tower's Mitsubishi TV data. -// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Mitsubishi.cpp -const uint16_t kMitsubishiTick = 30; -const uint16_t kMitsubishiBitMarkTicks = 10; -const uint16_t kMitsubishiBitMark = kMitsubishiBitMarkTicks * kMitsubishiTick; -const uint16_t kMitsubishiOneSpaceTicks = 70; -const uint16_t kMitsubishiOneSpace = kMitsubishiOneSpaceTicks * kMitsubishiTick; -const uint16_t kMitsubishiZeroSpaceTicks = 30; -const uint16_t kMitsubishiZeroSpace = - kMitsubishiZeroSpaceTicks * kMitsubishiTick; -const uint16_t kMitsubishiMinCommandLengthTicks = 1786; -const uint16_t kMitsubishiMinCommandLength = - kMitsubishiMinCommandLengthTicks * kMitsubishiTick; -const uint16_t kMitsubishiMinGapTicks = 936; -const uint16_t kMitsubishiMinGap = kMitsubishiMinGapTicks * kMitsubishiTick; - -// Mitsubishi Projector (HC3000) -// Ref: -// https://github.com/crankyoldgit/IRremoteESP8266/issues/441 - -const uint16_t kMitsubishi2HdrMark = 8400; -const uint16_t kMitsubishi2HdrSpace = kMitsubishi2HdrMark / 2; -const uint16_t kMitsubishi2BitMark = 560; -const uint16_t kMitsubishi2ZeroSpace = 520; -const uint16_t kMitsubishi2OneSpace = kMitsubishi2ZeroSpace * 3; -const uint16_t kMitsubishi2MinGap = 28500; - -// Mitsubishi A/C -// Ref: -// https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266.ino#L84 - -const uint16_t kMitsubishiAcHdrMark = 3400; -const uint16_t kMitsubishiAcHdrSpace = 1750; -const uint16_t kMitsubishiAcBitMark = 450; -const uint16_t kMitsubishiAcOneSpace = 1300; -const uint16_t kMitsubishiAcZeroSpace = 420; -const uint16_t kMitsubishiAcRptMark = 440; -const uint16_t kMitsubishiAcRptSpace = 17100; - -using irutils::addBoolToString; -using irutils::addFanToString; -using irutils::addIntToString; -using irutils::addLabeledString; -using irutils::addModeToString; -using irutils::addTempToString; -using irutils::minsToString; - -#if SEND_MITSUBISHI -// Send a Mitsubishi message -// -// Args: -// data: Contents of the message to be sent. -// nbits: Nr. of bits of data to be sent. Typically kMitsubishiBits. -// repeat: Nr. of additional times the message is to be sent. -// -// Status: ALPHA / untested. -// -// Notes: -// This protocol appears to have no header. -// Ref: -// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Mitsubishi.cpp -// GlobalCache's Control Tower's Mitsubishi TV data. -void IRsend::sendMitsubishi(uint64_t data, uint16_t nbits, uint16_t repeat) { - sendGeneric(0, 0, // No Header - kMitsubishiBitMark, kMitsubishiOneSpace, kMitsubishiBitMark, - kMitsubishiZeroSpace, kMitsubishiBitMark, kMitsubishiMinGap, - kMitsubishiMinCommandLength, data, nbits, 33, true, repeat, 50); -} -#endif // SEND_MITSUBISHI - -#if DECODE_MITSUBISHI -// Decode the supplied Mitsubishi message. -// -// Args: -// results: Ptr to the data to decode and where to store the decode result. -// nbits: Nr. of data bits to expect. -// strict: Flag indicating if we should perform strict matching. -// Returns: -// boolean: True if it can decode it, false if it can't. -// -// Status: BETA / previously working. -// -// Notes: -// This protocol appears to have no header. -// -// Ref: -// GlobalCache's Control Tower's Mitsubishi TV data. -bool IRrecv::decodeMitsubishi(decode_results *results, uint16_t nbits, - bool strict) { - if (strict && nbits != kMitsubishiBits) - return false; // Request is out of spec. - - uint16_t offset = kStartOffset; - uint64_t data = 0; - - // Match Data + Footer - if (!matchGeneric(results->rawbuf + offset, &data, - results->rawlen - offset, nbits, - 0, 0, // No header - kMitsubishiBitMark, kMitsubishiOneSpace, - kMitsubishiBitMark, kMitsubishiZeroSpace, - kMitsubishiBitMark, kMitsubishiMinGap, - true, 30)) return false; - // Success - results->decode_type = MITSUBISHI; - results->bits = nbits; - results->value = data; - results->address = 0; - results->command = 0; - return true; -} -#endif // DECODE_MITSUBISHI - -#if SEND_MITSUBISHI2 -// Send a Mitsubishi2 message -// -// Args: -// data: Contents of the message to be sent. -// nbits: Nr. of bits of data to be sent. Typically kMitsubishiBits. -// repeat: Nr. of additional times the message is to be sent. -// -// Status: ALPHA / untested. -// -// Notes: -// Based on a Mitsubishi HC3000 projector's remote. -// This protocol appears to have a manditory in-protocol repeat. -// That is in *addition* to the entire message needing to be sent twice -// for the device to accept the command. That is separate from the repeat. -// i.e. Allegedly, the real remote requires the "Off" button pressed twice. -// You will need to add a suitable gap yourself. -// Ref: -// https://github.com/crankyoldgit/IRremoteESP8266/issues/441 -void IRsend::sendMitsubishi2(uint64_t data, uint16_t nbits, uint16_t repeat) { - for (uint16_t i = 0; i <= repeat; i++) { - // First half of the data. - sendGeneric(kMitsubishi2HdrMark, kMitsubishi2HdrSpace, kMitsubishi2BitMark, - kMitsubishi2OneSpace, kMitsubishi2BitMark, - kMitsubishi2ZeroSpace, kMitsubishi2BitMark, - kMitsubishi2HdrSpace, data >> (nbits / 2), nbits / 2, 33, true, - 0, 50); - // Second half of the data. - sendGeneric(0, 0, // No header for the second data block - kMitsubishi2BitMark, kMitsubishi2OneSpace, kMitsubishi2BitMark, - kMitsubishi2ZeroSpace, kMitsubishi2BitMark, kMitsubishi2MinGap, - data & ((1 << (nbits / 2)) - 1), nbits / 2, 33, true, 0, 50); - } -} -#endif // SEND_MITSUBISHI2 - -#if DECODE_MITSUBISHI2 -// Decode the supplied Mitsubishi2 message. -// -// Args: -// results: Ptr to the data to decode and where to store the decode result. -// nbits: Nr. of data bits to expect. -// strict: Flag indicating if we should perform strict matching. -// Returns: -// boolean: True if it can decode it, false if it can't. -// -// Status: BETA / Works with simulated data. -// -// Notes: -// Hardware supported: -// * Mitsubishi HC3000 projector's remote. -// -// Ref: -// https://github.com/crankyoldgit/IRremoteESP8266/issues/441 -bool IRrecv::decodeMitsubishi2(decode_results *results, uint16_t nbits, - bool strict) { - if (results->rawlen < 2 * nbits + kHeader + (kFooter * 2) - 1) - return false; // Shorter than shortest possibly expected. - if (strict && nbits != kMitsubishiBits) - return false; // Request is out of spec. - - uint16_t offset = kStartOffset; - results->value = 0; - - // Header - if (!matchMark(results->rawbuf[offset++], kMitsubishi2HdrMark)) return false; - if (!matchSpace(results->rawbuf[offset++], kMitsubishi2HdrSpace)) - return false; - for (uint8_t i = 0; i < 2; i++) { - // Match Data + Footer - uint16_t used; - uint64_t data = 0; - used = matchGeneric(results->rawbuf + offset, &data, - results->rawlen - offset, nbits / 2, - 0, 0, // No header - kMitsubishi2BitMark, kMitsubishi2OneSpace, - kMitsubishi2BitMark, kMitsubishi2ZeroSpace, - kMitsubishi2BitMark, kMitsubishi2HdrSpace, - i % 2); - if (!used) return false; - offset += used; - results->value <<= (nbits / 2); - results->value += data; - } - - // Success - results->decode_type = MITSUBISHI2; - results->bits = nbits; - results->address = results->value >> (nbits / 2); - results->command = results->value & ((1 << (nbits / 2)) - 1); - return true; -} -#endif // DECODE_MITSUBISHI2 - -#if SEND_MITSUBISHI_AC -// Send a Mitsubishi A/C message. -// -// Args: -// data: An array of bytes containing the IR command. -// nbytes: Nr. of bytes of data in the array. (>=kMitsubishiACStateLength) -// repeat: Nr. of times the message is to be repeated. -// (Default = kMitsubishiACMinRepeat). -// -// Status: BETA / Appears to be working. -// -void IRsend::sendMitsubishiAC(const unsigned char data[], const uint16_t nbytes, - const uint16_t repeat) { - if (nbytes < kMitsubishiACStateLength) - return; // Not enough bytes to send a proper message. - - sendGeneric(kMitsubishiAcHdrMark, kMitsubishiAcHdrSpace, kMitsubishiAcBitMark, - kMitsubishiAcOneSpace, kMitsubishiAcBitMark, - kMitsubishiAcZeroSpace, kMitsubishiAcRptMark, - kMitsubishiAcRptSpace, data, nbytes, 38, false, repeat, 50); -} -#endif // SEND_MITSUBISHI_AC - -#if DECODE_MITSUBISHI_AC -// Decode the supplied Mitsubishi message. -// -// Args: -// results: Ptr to the data to decode and where to store the decode result. -// nbits: Nr. of data bits to expect. -// strict: Flag indicating if we should perform strict matching. -// Returns: -// boolean: True if it can decode it, false if it can't. -// -// Status: ALPHA / Under development -// -// Ref: -// https://www.analysir.com/blog/2015/01/06/reverse-engineering-mitsubishi-ac-infrared-protocol/ -bool IRrecv::decodeMitsubishiAC(decode_results *results, uint16_t nbits, - bool strict) { - if (results->rawlen < ((kMitsubishiACBits * 2) + 2)) { - DPRINTLN("Shorter than shortest possibly expected."); - return false; // Shorter than shortest possibly expected. - } - if (strict && nbits != kMitsubishiACBits) { - DPRINTLN("Request is out of spec."); - return false; // Request is out of spec. - } - uint16_t offset = kStartOffset; - for (uint8_t i = 0; i < kMitsubishiACStateLength; i++) { - results->state[i] = 0; - } - bool failure = false; - uint8_t rep = 0; - do { - failure = false; - // Header: - // Sometime happens that junk signals arrives before the real message - bool headerFound = false; - while (!headerFound && - offset < (results->rawlen - (kMitsubishiACBits * 2 + 2))) { - headerFound = - matchMark(results->rawbuf[offset++], kMitsubishiAcHdrMark) && - matchSpace(results->rawbuf[offset++], kMitsubishiAcHdrSpace); - } - if (!headerFound) { - DPRINTLN("Header mark not found."); - failure = true; - } - // Decode byte-by-byte: - match_result_t data_result; - for (uint8_t i = 0; i < kMitsubishiACStateLength && !failure; i++) { - results->state[i] = 0; - data_result = - matchData(&(results->rawbuf[offset]), 8, kMitsubishiAcBitMark, - kMitsubishiAcOneSpace, kMitsubishiAcBitMark, - kMitsubishiAcZeroSpace, _tolerance, kMarkExcess, false); - if (data_result.success == false) { - failure = true; - DPRINT("Byte decode failed at #"); - DPRINTLN((uint16_t)i); - } else { - results->state[i] = data_result.data; - offset += data_result.used; - DPRINT((uint16_t)results->state[i]); - DPRINT(","); - } - DPRINTLN(""); - } - // HEADER validation: - if (failure || results->state[0] != 0x23 || results->state[1] != 0xCB || - results->state[2] != 0x26 || results->state[3] != 0x01 || - results->state[4] != 0x00) { - DPRINTLN("Header mismatch."); - failure = true; - } else { - // DATA part: - - // FOOTER checksum: - if (IRMitsubishiAC::calculateChecksum(results->state) != - results->state[kMitsubishiACStateLength - 1]) { - DPRINTLN("Checksum error."); - failure = true; - } - } - if (rep != kMitsubishiACMinRepeat && failure) { - bool repeatMarkFound = false; - while (!repeatMarkFound && - offset < (results->rawlen - (kMitsubishiACBits * 2 + 4))) { - repeatMarkFound = - matchMark(results->rawbuf[offset++], kMitsubishiAcRptMark) && - matchSpace(results->rawbuf[offset++], kMitsubishiAcRptSpace); - } - if (!repeatMarkFound) { - DPRINTLN("First attempt failure and repeat mark not found."); - return false; - } - } - rep++; - // Check if the repeat is correct if we need strict decode: - if (strict && !failure) { - DPRINTLN("Strict repeat check enabled."); - // Repeat mark and space: - if (!matchMark(results->rawbuf[offset++], kMitsubishiAcRptMark) || - !matchSpace(results->rawbuf[offset++], kMitsubishiAcRptSpace)) { - DPRINTLN("Repeat mark error."); - return false; - } - // Header mark and space: - if (!matchMark(results->rawbuf[offset++], kMitsubishiAcHdrMark) || - !matchSpace(results->rawbuf[offset++], kMitsubishiAcHdrSpace)) { - DPRINTLN("Repeat header error."); - return false; - } - // Payload: - for (uint8_t i = 0; i < kMitsubishiACStateLength; i++) { - data_result = - matchData(&(results->rawbuf[offset]), 8, kMitsubishiAcBitMark, - kMitsubishiAcOneSpace, kMitsubishiAcBitMark, - kMitsubishiAcZeroSpace, _tolerance, kMarkExcess, false); - if (data_result.success == false || - data_result.data != results->state[i]) { - DPRINTLN("Repeat payload error."); - return false; - } - offset += data_result.used; - } - } // strict repeat check - } while (failure && rep <= kMitsubishiACMinRepeat); - results->decode_type = MITSUBISHI_AC; - results->bits = kMitsubishiACStateLength * 8; - return true; -} -#endif // DECODE_MITSUBISHI_AC - -// Code to emulate Mitsubishi A/C IR remote control unit. -// 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. -// -// Equipment it seems compatible with: -// * -// Initialise the object. -IRMitsubishiAC::IRMitsubishiAC(const uint16_t pin, const bool inverted, - const bool use_modulation) - : _irsend(pin, inverted, use_modulation) { this->stateReset(); } - -// Reset the state of the remote to a known good state/sequence. -void IRMitsubishiAC::stateReset(void) { - // The state of the IR remote in IR code form. - // Known good state obtained from: - // https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266.ino#L108 - // Note: Can't use the following because it requires -std=c++11 - // uint8_t known_good_state[kMitsubishiACStateLength] = { - // 0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x06, 0x30, 0x45, 0x67, 0x00, - // 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F}; - remote_state[0] = 0x23; - remote_state[1] = 0xCB; - remote_state[2] = 0x26; - remote_state[3] = 0x01; - remote_state[4] = 0x00; - remote_state[5] = 0x20; - remote_state[6] = 0x08; - remote_state[7] = 0x06; - remote_state[8] = 0x30; - remote_state[9] = 0x45; - remote_state[10] = 0x67; - for (uint8_t i = 11; i < kMitsubishiACStateLength - 1; i++) - remote_state[i] = 0; - remote_state[kMitsubishiACStateLength - 1] = 0x1F; - this->checksum(); // Calculate the checksum -} - -// Configure the pin for output. -void IRMitsubishiAC::begin(void) { _irsend.begin(); } - -#if SEND_MITSUBISHI_AC -// Send the current desired state to the IR LED. -void IRMitsubishiAC::send(const uint16_t repeat) { - this->checksum(); // Ensure correct checksum before sending. - _irsend.sendMitsubishiAC(remote_state, kMitsubishiACStateLength, repeat); -} -#endif // SEND_MITSUBISHI_AC - -// Return a pointer to the internal state date of the remote. -uint8_t *IRMitsubishiAC::getRaw(void) { - this->checksum(); - return remote_state; -} - -void IRMitsubishiAC::setRaw(const uint8_t *data) { - for (uint8_t i = 0; i < (kMitsubishiACStateLength - 1); i++) { - remote_state[i] = data[i]; - } - this->checksum(); -} - -// Calculate the checksum for the current internal state of the remote. -void IRMitsubishiAC::checksum(void) { - remote_state[17] = this->calculateChecksum(remote_state); -} - -uint8_t IRMitsubishiAC::calculateChecksum(const uint8_t *data) { - uint8_t sum = 0; - // Checksum is simple addition of all previous bytes stored - // as an 8 bit value. - for (uint8_t i = 0; i < 17; i++) sum += data[i]; - return sum & 0xFFU; -} - -// Set the requested power state of the A/C to off. -void IRMitsubishiAC::on(void) { - // state = ON; - remote_state[5] |= kMitsubishiAcPower; -} - -// Set the requested power state of the A/C to off. -void IRMitsubishiAC::off(void) { - // state = OFF; - remote_state[5] &= ~kMitsubishiAcPower; -} - -// Set the requested power state of the A/C. -void IRMitsubishiAC::setPower(bool on) { - if (on) - this->on(); - else - this->off(); -} - -// Return the requested power state of the A/C. -bool IRMitsubishiAC::getPower(void) { - return ((remote_state[5] & kMitsubishiAcPower) != 0); -} - -// Set the temp. in deg C -void IRMitsubishiAC::setTemp(const uint8_t degrees) { - uint8_t temp = std::max((uint8_t)kMitsubishiAcMinTemp, degrees); - temp = std::min((uint8_t)kMitsubishiAcMaxTemp, temp); - remote_state[7] = temp - kMitsubishiAcMinTemp; -} - -// Return the set temp. in deg C -uint8_t IRMitsubishiAC::getTemp(void) { - return (remote_state[7] + kMitsubishiAcMinTemp); -} - -// Set the speed of the fan, 0-6. -// 0 is auto, 1-5 is the speed, 6 is silent. -void IRMitsubishiAC::setFan(const uint8_t speed) { - uint8_t fan = speed; - // Bounds check - if (fan > kMitsubishiAcFanSilent) - fan = kMitsubishiAcFanMax; // Set the fan to maximum if out of range. - if (fan == kMitsubishiAcFanAuto) { // Automatic is a special case. - remote_state[9] = 0b10000000 | (remote_state[9] & 0b01111000); - return; - } else if (fan >= kMitsubishiAcFanMax) { - fan--; // There is no spoon^H^H^Heed 5 (max), pretend it doesn't exist. - } - remote_state[9] &= 0b01111000; // Clear the previous state - remote_state[9] |= fan; -} - -// Return the requested state of the unit's fan. -uint8_t IRMitsubishiAC::getFan(void) { - uint8_t fan = remote_state[9] & 0b111; - if (fan == kMitsubishiAcFanMax) return kMitsubishiAcFanSilent; - return fan; -} - -// Return the requested climate operation mode of the a/c unit. -uint8_t IRMitsubishiAC::getMode(void) { return (remote_state[6]); } - -// Set the requested climate operation mode of the a/c unit. -void IRMitsubishiAC::setMode(const uint8_t mode) { - // If we get an unexpected mode, default to AUTO. - switch (mode) { - case kMitsubishiAcAuto: - remote_state[8] = 0b00110000; - break; - case kMitsubishiAcCool: - remote_state[8] = 0b00110110; - break; - case kMitsubishiAcDry: - remote_state[8] = 0b00110010; - break; - case kMitsubishiAcHeat: - remote_state[8] = 0b00110000; - break; - default: - this->setMode(kMitsubishiAcAuto); - return; - } - remote_state[6] = mode; -} - -// Set the requested vane operation mode of the a/c unit. -void IRMitsubishiAC::setVane(const uint8_t position) { - uint8_t pos = std::min(position, (uint8_t)0b111); // bounds check - pos |= 0b1000; - pos <<= 3; - remote_state[9] &= 0b11000111; // Clear the previous setting. - remote_state[9] |= pos; -} - -// Set the requested wide-vane operation mode of the a/c unit. -void IRMitsubishiAC::setWideVane(const uint8_t position) { - uint8_t pos = std::min(position, kMitsubishiAcWideVaneAuto); // bounds check - pos <<= 4; - remote_state[8] &= 0b00001111; // Clear the previous setting. - remote_state[8] |= pos; -} - -// Return the requested vane operation mode of the a/c unit. -uint8_t IRMitsubishiAC::getVane(void) { - return ((remote_state[9] & 0b00111000) >> 3); -} - -// Return the requested wide vane operation mode of the a/c unit. -uint8_t IRMitsubishiAC::getWideVane(void) { - return (remote_state[8] >> 4); -} - -// Return the clock setting of the message. 1=1/6 hour. e.g. 4pm = 48 -uint8_t IRMitsubishiAC::getClock(void) { return remote_state[10]; } - -// Set the current time. 1 = 1/6 hour. e.g. 6am = 36. -void IRMitsubishiAC::setClock(const uint8_t clock) { - remote_state[10] = clock; -} - -// Return the desired start time. 1 = 1/6 hour. e.g. 1am = 6 -uint8_t IRMitsubishiAC::getStartClock(void) { return remote_state[12]; } - -// Set the desired start time of the AC. 1 = 1/6 hour. e.g. 8pm = 120 -void IRMitsubishiAC::setStartClock(const uint8_t clock) { - remote_state[12] = clock; -} - -// Return the desired stop time of the AC. 1 = 1/6 hour. e.g 10pm = 132 -uint8_t IRMitsubishiAC::getStopClock(void) { return remote_state[11]; } - -// Set the desired stop time of the AC. 1 = 1/6 hour. e.g 10pm = 132 -void IRMitsubishiAC::setStopClock(const uint8_t clock) { - remote_state[11] = clock; -} - -// Return the timer setting. Possible values: kMitsubishiAcNoTimer, -// kMitsubishiAcStartTimer, kMitsubishiAcStopTimer, -// kMitsubishiAcStartStopTimer -uint8_t IRMitsubishiAC::getTimer(void) { return remote_state[13] & 0b111; } - -// Set the timer setting. Possible values: kMitsubishiAcNoTimer, -// kMitsubishiAcStartTimer, kMitsubishiAcStopTimer, -// kMitsubishiAcStartStopTimer -void IRMitsubishiAC::setTimer(uint8_t timer) { - remote_state[13] = timer & 0b111; -} - -// Convert a standard A/C mode into its native mode. -uint8_t IRMitsubishiAC::convertMode(const stdAc::opmode_t mode) { - switch (mode) { - case stdAc::opmode_t::kCool: - return kMitsubishiAcCool; - case stdAc::opmode_t::kHeat: - return kMitsubishiAcHeat; - case stdAc::opmode_t::kDry: - return kMitsubishiAcDry; - default: - return kMitsubishiAcAuto; - } -} - -// Convert a standard A/C Fan speed into its native fan speed. -uint8_t IRMitsubishiAC::convertFan(const stdAc::fanspeed_t speed) { - switch (speed) { - case stdAc::fanspeed_t::kMin: - return kMitsubishiAcFanSilent; - case stdAc::fanspeed_t::kLow: - return kMitsubishiAcFanRealMax - 3; - case stdAc::fanspeed_t::kMedium: - return kMitsubishiAcFanRealMax - 2; - case stdAc::fanspeed_t::kHigh: - return kMitsubishiAcFanRealMax - 1; - case stdAc::fanspeed_t::kMax: - return kMitsubishiAcFanRealMax; - default: - return kMitsubishiAcFanAuto; - } -} - -// Convert a standard A/C vertical swing into its native setting. -uint8_t IRMitsubishiAC::convertSwingV(const stdAc::swingv_t position) { - switch (position) { - case stdAc::swingv_t::kHighest: - return kMitsubishiAcVaneAutoMove - 6; - case stdAc::swingv_t::kHigh: - return kMitsubishiAcVaneAutoMove - 5; - case stdAc::swingv_t::kMiddle: - return kMitsubishiAcVaneAutoMove - 4; - case stdAc::swingv_t::kLow: - return kMitsubishiAcVaneAutoMove - 3; - case stdAc::swingv_t::kLowest: - return kMitsubishiAcVaneAutoMove - 2; - case stdAc::swingv_t::kAuto: - return kMitsubishiAcVaneAutoMove; - default: - return kMitsubishiAcVaneAuto; - } -} - -// Convert a standard A/C wide wane swing into its native setting. -uint8_t IRMitsubishiAC::convertSwingH(const stdAc::swingh_t position) { - switch (position) { - case stdAc::swingh_t::kLeftMax: - return kMitsubishiAcWideVaneAuto - 7; - case stdAc::swingh_t::kLeft: - return kMitsubishiAcWideVaneAuto - 6; - case stdAc::swingh_t::kMiddle: - return kMitsubishiAcWideVaneAuto - 5; - case stdAc::swingh_t::kRight: - return kMitsubishiAcWideVaneAuto - 4; - case stdAc::swingh_t::kRightMax: - return kMitsubishiAcWideVaneAuto - 3; - case stdAc::swingh_t::kWide: - return kMitsubishiAcWideVaneAuto - 2; - case stdAc::swingh_t::kAuto: - return kMitsubishiAcWideVaneAuto; - default: - return kMitsubishiAcWideVaneAuto - 5; - } -} - -// Convert a native mode to it's common equivalent. -stdAc::opmode_t IRMitsubishiAC::toCommonMode(const uint8_t mode) { - switch (mode) { - case kMitsubishiAcCool: return stdAc::opmode_t::kCool; - case kMitsubishiAcHeat: return stdAc::opmode_t::kHeat; - case kMitsubishiAcDry: return stdAc::opmode_t::kDry; - default: return stdAc::opmode_t::kAuto; - } -} - -// Convert a native fan speed to it's common equivalent. -stdAc::fanspeed_t IRMitsubishiAC::toCommonFanSpeed(const uint8_t speed) { - switch (speed) { - case kMitsubishiAcFanRealMax: return stdAc::fanspeed_t::kMax; - case kMitsubishiAcFanRealMax - 1: return stdAc::fanspeed_t::kHigh; - case kMitsubishiAcFanRealMax - 2: return stdAc::fanspeed_t::kMedium; - case kMitsubishiAcFanRealMax - 3: return stdAc::fanspeed_t::kLow; - case kMitsubishiAcFanSilent: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; - } -} - -// Convert a native vertical swing to it's common equivalent. -stdAc::swingv_t IRMitsubishiAC::toCommonSwingV(const uint8_t pos) { - switch (pos) { - case 1: return stdAc::swingv_t::kHighest; - case 2: return stdAc::swingv_t::kHigh; - case 3: return stdAc::swingv_t::kMiddle; - case 4: return stdAc::swingv_t::kLow; - case 5: return stdAc::swingv_t::kLowest; - default: return stdAc::swingv_t::kAuto; - } -} - -// Convert a native horizontal swing to it's common equivalent. -stdAc::swingh_t IRMitsubishiAC::toCommonSwingH(const uint8_t pos) { - switch (pos) { - case 1: return stdAc::swingh_t::kLeftMax; - case 2: return stdAc::swingh_t::kLeft; - case 3: return stdAc::swingh_t::kMiddle; - case 4: return stdAc::swingh_t::kRight; - case 5: return stdAc::swingh_t::kRightMax; - case 6: return stdAc::swingh_t::kWide; - default: return stdAc::swingh_t::kAuto; - } -} - -// Convert the A/C state to it's common equivalent. -stdAc::state_t IRMitsubishiAC::toCommon(void) { - stdAc::state_t result; - result.protocol = decode_type_t::MITSUBISHI_AC; - result.model = -1; // No models used. - result.power = this->getPower(); - result.mode = this->toCommonMode(this->getMode()); - result.celsius = true; - result.degrees = this->getTemp(); - result.fanspeed = this->toCommonFanSpeed(this->getFan()); - result.swingv = this->toCommonSwingV(this->getVane()); - result.swingh = this->toCommonSwingH(this->getWideVane()); - result.quiet = this->getFan() == kMitsubishiAcFanSilent; - // Not supported. - result.turbo = false; - result.clean = false; - result.econo = false; - result.filter = false; - result.light = false; - result.beep = false; - result.sleep = -1; - result.clock = -1; - return result; -} - -// Convert the internal state into a human readable string. -String IRMitsubishiAC::toString(void) { - String result = ""; - result.reserve(110); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); - result += addModeToString(getMode(), kMitsubishiAcAuto, kMitsubishiAcCool, - kMitsubishiAcHeat, kMitsubishiAcDry, - kMitsubishiAcAuto); - result += addTempToString(getTemp()); - result += addFanToString(getFan(), kMitsubishiAcFanRealMax, - kMitsubishiAcFanRealMax - 3, - kMitsubishiAcFanAuto, kMitsubishiAcFanQuiet, - kMitsubishiAcFanRealMax - 2); - result += F(", Vane: "); - switch (this->getVane()) { - case MITSUBISHI_AC_VANE_AUTO: - result += F("AUTO"); - break; - case MITSUBISHI_AC_VANE_AUTO_MOVE: - result += F("AUTO MOVE"); - break; - default: - result += uint64ToString(this->getVane()); - } - result += F(", Wide Vane: "); - switch (this->getWideVane()) { - case kMitsubishiAcWideVaneAuto: - result += F("AUTO"); - break; - default: - result += uint64ToString(this->getWideVane()); - } - result += addLabeledString(minsToString(getClock() * 10), F("Time")); - result += addLabeledString(minsToString(getStartClock() * 10), F("On timer")); - result += addLabeledString(minsToString(getStopClock() * 10), F("Off timer")); - result += F(", Timer: "); - switch (this->getTimer()) { - case kMitsubishiAcNoTimer: - result += '-'; - break; - case kMitsubishiAcStartTimer: - result += F("Start"); - break; - case kMitsubishiAcStopTimer: - result += F("Stop"); - break; - case kMitsubishiAcStartStopTimer: - result += F("Start+Stop"); - break; - default: - result += F("? ("); - result += this->getTimer(); - result += F(")\n"); - } - return result; -} diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Mitsubishi.h b/lib/IRremoteESP8266-2.6.5/src/ir_Mitsubishi.h deleted file mode 100755 index ac67082dc..000000000 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Mitsubishi.h +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2009 Ken Shirriff -// Copyright 2017 David Conran - -// Mitsubishi - -// Supports: -// Brand: Mitsubishi, Model: TV -// Brand: Mitsubishi, Model: HC3000 Projector - -#ifndef IR_MITSUBISHI_H_ -#define IR_MITSUBISHI_H_ - -#define __STDC_LIMIT_MACROS -#include -#ifndef UNIT_TEST -#include -#endif -#include "IRremoteESP8266.h" -#include "IRsend.h" -#ifdef UNIT_TEST -#include "IRsend_test.h" -#endif - -// Mitsubishi (TV) decoding added from https://github.com/z3t0/Arduino-IRremote -// Mitsubishi (TV) sending & Mitsubishi A/C support added by David Conran - -// Constants -const uint8_t kMitsubishiAcAuto = 0x20; -const uint8_t kMitsubishiAcCool = 0x18; -const uint8_t kMitsubishiAcDry = 0x10; -const uint8_t kMitsubishiAcHeat = 0x08; -const uint8_t kMitsubishiAcPower = 0x20; -const uint8_t kMitsubishiAcFanAuto = 0; -const uint8_t kMitsubishiAcFanMax = 5; -const uint8_t kMitsubishiAcFanRealMax = 4; -const uint8_t kMitsubishiAcFanSilent = 6; -const uint8_t kMitsubishiAcFanQuiet = kMitsubishiAcFanSilent; -const uint8_t kMitsubishiAcMinTemp = 16; // 16C -const uint8_t kMitsubishiAcMaxTemp = 31; // 31C -const uint8_t kMitsubishiAcVaneAuto = 0; -const uint8_t kMitsubishiAcVaneAutoMove = 7; -const uint8_t kMitsubishiAcNoTimer = 0; -const uint8_t kMitsubishiAcStartTimer = 5; -const uint8_t kMitsubishiAcStopTimer = 3; -const uint8_t kMitsubishiAcStartStopTimer = 7; -const uint8_t kMitsubishiAcWideVaneAuto = 8; - -// Legacy defines (Deprecated) -#define MITSUBISHI_AC_VANE_AUTO_MOVE kMitsubishiAcVaneAutoMove -#define MITSUBISHI_AC_VANE_AUTO kMitsubishiAcVaneAuto -#define MITSUBISHI_AC_POWER kMitsubishiAcPower -#define MITSUBISHI_AC_MIN_TEMP kMitsubishiAcMinTemp -#define MITSUBISHI_AC_MAX_TEMP kMitsubishiAcMaxTemp -#define MITSUBISHI_AC_HEAT kMitsubishiAcHeat -#define MITSUBISHI_AC_FAN_SILENT kMitsubishiAcFanSilent -#define MITSUBISHI_AC_FAN_REAL_MAX kMitsubishiAcFanRealMax -#define MITSUBISHI_AC_FAN_MAX kMitsubishiAcFanMax -#define MITSUBISHI_AC_FAN_AUTO kMitsubishiAcFanAuto -#define MITSUBISHI_AC_DRY kMitsubishiAcDry -#define MITSUBISHI_AC_COOL kMitsubishiAcCool -#define MITSUBISHI_AC_AUTO kMitsubishiAcAuto - -class IRMitsubishiAC { - public: - explicit IRMitsubishiAC(const uint16_t pin, const bool inverted = false, - const bool use_modulation = true); - - static uint8_t calculateChecksum(const uint8_t* data); - - void stateReset(void); -#if SEND_MITSUBISHI_AC - void send(const uint16_t repeat = kMitsubishiACMinRepeat); - uint8_t calibrate(void) { return _irsend.calibrate(); } -#endif // SEND_MITSUBISHI_AC - void begin(void); - void on(void); - void off(void); - void setPower(const bool on); - bool getPower(void); - void setTemp(const uint8_t degrees); - uint8_t getTemp(void); - void setFan(const uint8_t speed); - uint8_t getFan(void); - void setMode(const uint8_t mode); - uint8_t getMode(void); - void setVane(const uint8_t position); - void setWideVane(const uint8_t position); - uint8_t getVane(void); - uint8_t getWideVane(void); - uint8_t* getRaw(void); - void setRaw(const uint8_t* data); - uint8_t getClock(void); - void setClock(const uint8_t clock); - uint8_t getStartClock(void); - void setStartClock(const uint8_t clock); - uint8_t getStopClock(void); - void setStopClock(const uint8_t clock); - uint8_t getTimer(void); - void setTimer(const uint8_t timer); - uint8_t convertMode(const stdAc::opmode_t mode); - uint8_t convertFan(const stdAc::fanspeed_t speed); - uint8_t convertSwingV(const stdAc::swingv_t position); - 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); - stdAc::state_t toCommon(void); - String toString(void); -#ifndef UNIT_TEST - - private: - IRsend _irsend; -#else - IRsendTest _irsend; -#endif - uint8_t remote_state[kMitsubishiACStateLength]; - void checksum(void); -}; - -#endif // IR_MITSUBISHI_H_ diff --git a/lib/IRremoteESP8266-2.6.5/tools/auto_analyse_raw_data.py b/lib/IRremoteESP8266-2.6.5/tools/auto_analyse_raw_data.py deleted file mode 100755 index 8a2e45794..000000000 --- a/lib/IRremoteESP8266-2.6.5/tools/auto_analyse_raw_data.py +++ /dev/null @@ -1,432 +0,0 @@ -#!/usr/bin/python -"""Attempt an automatic analysis of IRremoteESP8266's Raw data output. - Makes suggestions on key values and tried to break down the message - into likely chunks.""" -# -# Copyright 2018 David Conran -import argparse -import sys - - -class RawIRMessage(): - """Basic analyse functions & structure for raw IR messages.""" - - # pylint: disable=too-many-instance-attributes - - def __init__(self, margin, timings, output=sys.stdout, verbose=True): - self.hdr_mark = None - self.hdr_space = None - self.bit_mark = None - self.zero_space = None - self.one_space = None - self.gaps = [] - self.margin = margin - self.marks = [] - self.mark_buckets = {} - self.spaces = [] - self.space_buckets = {} - self.output = output - self.verbose = verbose - if len(timings) <= 3: - raise ValueError("Too few message timings supplied.") - self.timings = timings - self._generate_timing_candidates() - self._calc_values() - - def _generate_timing_candidates(self): - """Determine the likely values from the given data.""" - count = 0 - for usecs in self.timings: - count = count + 1 - if count % 2: - self.marks.append(usecs) - else: - self.spaces.append(usecs) - self.marks, self.mark_buckets = self.reduce_list(self.marks) - self.spaces, self.space_buckets = self.reduce_list(self.spaces) - - def reduce_list(self, items): - """Reduce a list of numbers into buckets that are at least margin apart.""" - result = [] - last = -1 - buckets = {} - for item in sorted(items, reverse=True): - if last == -1 or item < last - self.margin: - result.append(item) - last = item - buckets[last] = [item] - else: - buckets[last].append(item) - return result, buckets - - def _usec_compare(self, seen, expected): - """Compare two usec values and see if they match within a - subtractive margin.""" - return expected - self.margin < seen <= expected - - def _usec_compares(self, usecs, expecteds): - """Compare a usec value to a list of values and return True - if they are within a subtractive margin.""" - for expected in expecteds: - if self._usec_compare(usecs, expected): - return True - return False - - def display_binary(self, binary_str): - """Display common representations of the suppied binary string.""" - num = int(binary_str, 2) - bits = len(binary_str) - rev_binary_str = binary_str[::-1] - rev_num = int(rev_binary_str, 2) - self.output.write("\n Bits: %d\n" - " Hex: %s (MSB first)\n" - " %s (LSB first)\n" - " Dec: %s (MSB first)\n" - " %s (LSB first)\n" - " Bin: 0b%s (MSB first)\n" - " 0b%s (LSB first)\n" % - (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)) - - def add_data_code(self, bin_str, footer=True): - """Add the common "data" sequence of code to send the bulk of a message.""" - # pylint: disable=no-self-use - code = [] - code.append(" // Data") - code.append(" // e.g. data = 0x%X, nbits = %d" % (int(bin_str, 2), - len(bin_str))) - code.append(" sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, " - "nbits, true);") - if footer: - code.append(" // Footer") - code.append(" mark(kBitMark);") - 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))) - # Largest mark is likely the kHdrMark - self.hdr_mark = self.marks[0] - # The bit mark is likely to be the smallest mark. - self.bit_mark = self.marks[-1] - - if self.is_space_encoded() and len(self.spaces) >= 3: - if self.verbose and len(self.marks) > 2: - self.output.write("DANGER: Unexpected and unused mark timings!") - # We should have 3 space candidates at least. - # They should be: zero_space (smallest), one_space, & hdr_space (largest) - spaces = list(self.spaces) - self.zero_space = spaces.pop() - self.one_space = spaces.pop() - self.hdr_space = spaces.pop() - # Rest are probably message gaps - self.gaps = spaces - - def is_space_encoded(self): - """Make an educated guess if the message is space encoded.""" - return len(self.spaces) > len(self.marks) - - def is_hdr_mark(self, usec): - """Is usec the header mark?""" - return self._usec_compare(usec, self.hdr_mark) - - def is_hdr_space(self, usec): - """Is usec the header space?""" - return self._usec_compare(usec, self.hdr_space) - - def is_bit_mark(self, usec): - """Is usec the bit mark?""" - return self._usec_compare(usec, self.bit_mark) - - def is_one_space(self, usec): - """Is usec the one space?""" - return self._usec_compare(usec, self.one_space) - - def is_zero_space(self, usec): - """Is usec the zero_space?""" - return self._usec_compare(usec, self.zero_space) - - def is_gap(self, usec): - """Is usec the a space gap?""" - return self._usec_compares(usec, self.gaps) - - -def avg_list(items): - """Return the average of a list of numbers.""" - if items: - return int(sum(items) / len(items)) - return 0 - - -def add_bit(so_far, bit, output=sys.stdout): - """Add a bit to the end of the bits collected so far.""" - if bit == "reset": - return "" - output.write(str(bit)) # This effectively displays in LSB first order. - return so_far + str(bit) # Storing it in MSB first order. - - -def convert_rawdata(data_str): - """Parse a C++ rawdata declaration into a list of values.""" - start = data_str.find('{') - end = data_str.find('}') - if end == -1: - end = len(data_str) - if start > end: - raise ValueError("Raw Data not parsible due to parentheses placement.") - data_str = data_str[start + 1:end] - results = [] - for timing in [x.strip() for x in data_str.split(',')]: - try: - results.append(int(timing)) - except ValueError: - raise ValueError( - "Raw Data contains a non-numeric value of '%s'." % timing) - return results - - -def dump_constants(message, defines, output=sys.stdout): - """Dump the key constants and generate the C++ #defines.""" - hdr_mark = avg_list(message.mark_buckets[message.hdr_mark]) - bit_mark = avg_list(message.mark_buckets[message.bit_mark]) - hdr_space = avg_list(message.space_buckets[message.hdr_space]) - one_space = avg_list(message.space_buckets[message.one_space]) - zero_space = avg_list(message.space_buckets[message.zero_space]) - - output.write("Guessing key value:\n" - "kHdrMark = %d\n" - "kHdrSpace = %d\n" - "kBitMark = %d\n" - "kOneSpace = %d\n" - "kZeroSpace = %d\n" % (hdr_mark, hdr_space, bit_mark, one_space, - zero_space)) - defines.append("const uint16_t kHdrMark = %d;" % hdr_mark) - defines.append("const uint16_t kBitMark = %d;" % bit_mark) - defines.append("const uint16_t kHdrSpace = %d;" % hdr_space) - defines.append("const uint16_t kOneSpace = %d;" % one_space) - defines.append("const uint16_t kZeroSpace = %d;" % zero_space) - - avg_gaps = [avg_list(message.space_buckets[x]) for x in message.gaps] - if len(message.gaps) == 1: - output.write("kSpaceGap = %d\n" % avg_gaps[0]) - defines.append("const uint16_t kSpaceGap = %d;" % 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("kSpaceGap%d = %d\n" % (count, gap)) - defines.append("const uint16_t kSpaceGap%d = %d;" % (count, gap)) - - -def parse_and_report(rawdata_str, margin, gen_code=False, output=sys.stdout): - """Analyse the rawdata c++ definition of a IR message.""" - defines = [] - function_code = [] - - # Parse the input. - rawdata = convert_rawdata(rawdata_str) - - output.write("Found %d timing entries.\n" % len(rawdata)) - - message = RawIRMessage(margin, rawdata, output) - output.write("\nGuessing encoding type:\n") - if message.is_space_encoded(): - output.write("Looks like it uses space encoding. Yay!\n\n") - dump_constants(message, defines, output) - else: - output.write("Sorry, it looks like it is Mark encoded. " - "I can't do that yet. Exiting.\n") - sys.exit(1) - total_bits = decode_data(message, defines, function_code, output) - if gen_code: - generate_irsend_code(defines, function_code, total_bits, output) - - -def decode_data(message, defines, function_code, output=sys.stdout): - """Decode the data sequence with the given values in mind.""" - # pylint: disable=too-many-branches,too-many-statements - - # Now we have likely candidates for the key values, go through the original - # sequence and break it up and indicate accordingly. - - output.write("\nDecoding protocol based on analysis so far:\n\n") - state = "" - count = 1 - total_bits = "" - binary_value = add_bit("", "reset") - - function_code.extend([ - "// Function should be safe up to 64 bits.", - "void IRsend::sendXyz(const uint64_t data, const uint16_t" - " nbits, const uint16_t repeat) {", - " enableIROut(38); // A guess. Most common frequency.", - " for (uint16_t r = 0; r <= repeat; r++) {" - ]) - - for usec in message.timings: - if (message.is_hdr_mark(usec) and count % 2 and - not message.is_bit_mark(usec)): - state = "HM" - if binary_value: - message.display_binary(binary_value) - function_code.extend(message.add_data_code(binary_value, False)) - total_bits = total_bits + binary_value - binary_value = add_bit(binary_value, "reset") - output.write("kHdrMark+") - function_code.extend([" // Header", " mark(kHdrMark);"]) - elif message.is_hdr_space(usec) and not message.is_one_space(usec): - if state != "HM": - if binary_value: - message.display_binary(binary_value) - total_bits = total_bits + binary_value - function_code.extend(message.add_data_code(binary_value)) - binary_value = add_bit(binary_value, "reset") - output.write("UNEXPECTED->") - state = "HS" - output.write("kHdrSpace+") - function_code.append(" space(kHdrSpace);") - elif message.is_bit_mark(usec) and count % 2: - if state not in ("HS", "BS"): - output.write("kBitMark(UNEXPECTED)") - state = "BM" - elif message.is_zero_space(usec): - if state != "BM": - output.write("kZeroSpace(UNEXPECTED)") - state = "BS" - binary_value = add_bit(binary_value, 0, output) - elif message.is_one_space(usec): - if state != "BM": - output.write("kOneSpace(UNEXPECTED)") - state = "BS" - binary_value = add_bit(binary_value, 1, output) - elif message.is_gap(usec): - if state != "BM": - output.write("UNEXPECTED->") - state = "GS" - output.write("GAP(%d)" % usec) - if binary_value: - message.display_binary(binary_value) - function_code.extend(message.add_data_code(binary_value)) - else: - function_code.extend([" // Gap", " mark(kBitMark);"]) - function_code.append(" space(kSpaceGap);") - total_bits = total_bits + binary_value - binary_value = add_bit(binary_value, "reset") - else: - output.write("UNKNOWN(%d)" % usec) - state = "UNK" - count = count + 1 - if binary_value: - message.display_binary(binary_value) - function_code.extend(message.add_data_code(binary_value)) - function_code.extend([ - " space(100000); // A 100% made up guess of the gap" - " between messages.", " }", "}" - ]) - - total_bits = total_bits + binary_value - output.write("\nTotal Nr. of suspected bits: %d\n" % len(total_bits)) - defines.append("const uint16_t kXyzBits = %d;" % len(total_bits)) - if len(total_bits) > 64: - defines.append("const uint16_t kXyzStateLength = %d;" % - (len(total_bits) / 8)) - return total_bits - - -def generate_irsend_code(defines, normal, bits_str, output=sys.stdout): - """Output the estimated C++ code to reproduce the IR message.""" - output.write("\nGenerating a VERY rough code outline:\n\n" - "// WARNING: This probably isn't directly usable." - " It's a guide only.\n") - for line in defines: - output.write("%s\n" % line) - - if len(bits_str) > 64: # Will it fit in a uint64_t? - output.write("// DANGER: More than 64 bits detected. A uint64_t for " - "'data' won't work!\n") - # Display the "normal" version's code incase there are some - # oddities in it. - for line in normal: - output.write("%s\n" % line) - - if len(bits_str) > 64: # Will it fit in a uint64_t? - output.write("\n\n// Alternative >64 bit Function\n" - "void IRsend::sendXyz(uint8_t data[], uint16_t nbytes," - " uint16_t repeat) {\n" - " // nbytes should typically be kXyzStateLength\n" - " // data should typically be:\n" - " // uint8_t data[kXyzStateLength] = {0x%s};\n" - " // data[] is assumed to be in MSB order for this code.\n" - " for (uint16_t r = 0; r <= repeat; r++) {\n" - " sendGeneric(kHdrMark, kHdrSpace,\n" - " kBitMark, kOneSpace,\n" - " kBitMark, kZeroSpace,\n" - " kBitMark,\n" - " 100000, // 100%% made-up guess at the" - " message gap.\n" - " data, nbytes,\n" - " 38000, // Complete guess of the modulation" - " frequency.\n" - " true, 0, 50);\n" - " }\n" - "}\n" % ", 0x".join("%02X" % int(bits_str[i:i + 8], 2) - for i in range(0, len(bits_str), 8))) - - -def main(): - """Parse the commandline arguments and call the method.""" - arg_parser = argparse.ArgumentParser( - description="Read an IRremoteESP8266 rawData declaration and tries to " - "analyse it.", - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - arg_parser.add_argument( - "-g", - "--code", - action="store_true", - default=False, - dest="gen_code", - help="Generate a C++ code outline to aid making an IRsend function.") - arg_group = arg_parser.add_mutually_exclusive_group(required=True) - arg_group.add_argument( - "rawdata", - help="A rawData line from IRrecvDumpV2. e.g. 'uint16_t rawbuf[37] = {" - "7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494, " - "520, 494, 1482, 494, 1482, 494, 3978, 494, 520, 494, 520, 494, 520, " - "494, 520, 520, 520, 494, 520, 494, 520, 494, 520, 494};'", - nargs="?") - arg_group.add_argument( - "-f", "--file", help="Read in a rawData line from the file.") - arg_parser.add_argument( - "-r", - "--range", - type=int, - help="Max number of micro-seconds difference between values to consider" - " it the same value.", - dest="margin", - default=200) - arg_group.add_argument( - "--stdin", - help="Read in a rawData line from STDIN.", - action="store_true", - default=False) - arg_options = arg_parser.parse_args() - - if arg_options.stdin: - data = sys.stdin.read() - elif arg_options.file: - with open(arg_options.file) as input_file: - data = input_file.read() - else: - data = arg_options.rawdata - parse_and_report(data, arg_options.margin, arg_options.gen_code) - - -if __name__ == '__main__': - main() diff --git a/lib/IRremoteESP8266-2.6.5/tools/auto_analyse_raw_data_test.py b/lib/IRremoteESP8266-2.6.5/tools/auto_analyse_raw_data_test.py deleted file mode 100755 index 5d5504ffc..000000000 --- a/lib/IRremoteESP8266-2.6.5/tools/auto_analyse_raw_data_test.py +++ /dev/null @@ -1,492 +0,0 @@ -#!/usr/bin/python3 -"""Unit tests for auto_analyse_raw_data.py""" -from io import StringIO -import unittest -import auto_analyse_raw_data as analyse - - -class TestRawIRMessage(unittest.TestCase): - """Unit tests for the RawIRMessage class.""" - - # pylint: disable=too-many-public-methods - - def test_display_binary(self): - """Test the display_binary() method.""" - output = StringIO() - message = analyse.RawIRMessage(100, [8000, 4000, 500, 500, 500], output, - False) - self.assertEqual(output.getvalue(), '') - message.display_binary("10101010") - message.display_binary("0000000000000000") - message.display_binary("00010010001101000101011001111000") - self.assertEqual(output.getvalue(), '\n' - ' Bits: 8\n' - ' Hex: 0xAA (MSB first)\n' - ' 0x55 (LSB first)\n' - ' Dec: 170 (MSB first)\n' - ' 85 (LSB first)\n' - ' Bin: 0b10101010 (MSB first)\n' - ' 0b01010101 (LSB first)\n' - '\n' - ' Bits: 16\n' - ' Hex: 0x0000 (MSB first)\n' - ' 0x0000 (LSB first)\n' - ' Dec: 0 (MSB first)\n' - ' 0 (LSB first)\n' - ' Bin: 0b0000000000000000 (MSB first)\n' - ' 0b0000000000000000 (LSB first)\n' - '\n' - ' Bits: 32\n' - ' Hex: 0x12345678 (MSB first)\n' - ' 0x1E6A2C48 (LSB first)\n' - ' Dec: 305419896 (MSB first)\n' - ' 510274632 (LSB first)\n' - ' Bin: 0b00010010001101000101011001111000 (MSB first)\n' - ' 0b00011110011010100010110001001000 (LSB first)\n') - - -class TestAutoAnalyseRawData(unittest.TestCase): - """Unit tests for the functions in AutoAnalyseRawData.""" - - # pylint: disable=too-many-public-methods - - def test_dump_constants_simple(self): - """Simple tests for the dump_constants() function.""" - ignore = StringIO() - output = StringIO() - defs = [] - message = analyse.RawIRMessage(200, [ - 7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494, - 520, 494, 1482, 494, 1482, 494, 3978, 494, 520, 494, 520, 494, 520, 494, - 520, 520, 520, 494, 520, 494, 520, 494, 1482, 494 - ], ignore) - analyse.dump_constants(message, defs, output) - self.assertEqual(defs, [ - 'const uint16_t kHdrMark = 7930;', 'const uint16_t kBitMark = 496;', - 'const uint16_t kHdrSpace = 3965;', 'const uint16_t kOneSpace = 1485;', - 'const uint16_t kZeroSpace = 520;' - ]) - self.assertEqual(output.getvalue(), 'Guessing key value:\n' - 'kHdrMark = 7930\n' - 'kHdrSpace = 3965\n' - 'kBitMark = 496\n' - 'kOneSpace = 1485\n' - 'kZeroSpace = 520\n') - - def test_dump_constants_aircon(self): - """More complex tests for the dump_constants() function.""" - ignore = StringIO() - output = StringIO() - defs = [] - message = analyse.RawIRMessage(200, [ - 9008, 4496, 644, 1660, 676, 530, 648, 558, 672, 1636, 646, 1660, 644, - 556, 650, 584, 626, 560, 644, 580, 628, 1680, 624, 560, 648, 1662, 644, - 582, 648, 536, 674, 530, 646, 580, 628, 560, 670, 532, 646, 562, 644, - 556, 672, 536, 648, 1662, 646, 1660, 652, 554, 644, 558, 672, 538, 644, - 560, 668, 560, 648, 1638, 668, 536, 644, 1660, 668, 532, 648, 560, 648, - 1660, 674, 554, 622, 19990, 646, 580, 624, 1660, 648, 556, 648, 558, - 674, 556, 622, 560, 644, 564, 668, 536, 646, 1662, 646, 1658, 672, 534, - 648, 558, 644, 562, 648, 1662, 644, 584, 622, 558, 648, 562, 668, 534, - 670, 536, 670, 532, 672, 536, 646, 560, 646, 558, 648, 558, 670, 534, - 650, 558, 646, 560, 646, 560, 668, 1638, 646, 1662, 646, 1660, 646, - 1660, 648 - ], ignore) - analyse.dump_constants(message, defs, output) - self.assertEqual(defs, [ - 'const uint16_t kHdrMark = 9008;', 'const uint16_t kBitMark = 650;', - 'const uint16_t kHdrSpace = 4496;', 'const uint16_t kOneSpace = 1657;', - 'const uint16_t kZeroSpace = 554;', 'const uint16_t kSpaceGap = 19990;' - ]) - self.assertEqual(output.getvalue(), 'Guessing key value:\n' - 'kHdrMark = 9008\n' - 'kHdrSpace = 4496\n' - 'kBitMark = 650\n' - 'kOneSpace = 1657\n' - 'kZeroSpace = 554\n' - 'kSpaceGap = 19990\n') - - def test_convert_rawdata(self): - """Tests for the convert_rawdata() function.""" - # trivial cases - self.assertEqual(analyse.convert_rawdata("0"), [0]) - with self.assertRaises(ValueError) as context: - analyse.convert_rawdata("") - self.assertEqual(str(context.exception), - "Raw Data contains a non-numeric value of ''.") - - # Single parenthesis - self.assertEqual(analyse.convert_rawdata("foo {10"), [10]) - self.assertEqual(analyse.convert_rawdata("20} bar"), [20]) - - # No parentheses - self.assertEqual(analyse.convert_rawdata("10,20 , 30"), [10, 20, 30]) - - # Dual parentheses - self.assertEqual(analyse.convert_rawdata("{10,20 , 30}"), [10, 20, 30]) - self.assertEqual(analyse.convert_rawdata("foo{10,20}bar"), [10, 20]) - - # Many parentheses - self.assertEqual(analyse.convert_rawdata("foo{10,20}{bar}"), [10, 20]) - self.assertEqual(analyse.convert_rawdata("foo{10,20}{bar}}{"), [10, 20]) - - # Bad parentheses - with self.assertRaises(ValueError) as context: - analyse.convert_rawdata("}10{") - self.assertEqual(str(context.exception), - "Raw Data not parsible due to parentheses placement.") - - # Non base-10 values - with self.assertRaises(ValueError) as context: - analyse.convert_rawdata("10, 20, foo, bar, 30") - self.assertEqual(str(context.exception), - "Raw Data contains a non-numeric value of 'foo'.") - - # A messy usual "good" case. - input_str = """uint16_t rawbuf[6] = { - 9008, 4496, 644, - 1660, 676, - - 530} - ;""" - self.assertEqual( - analyse.convert_rawdata(input_str), [9008, 4496, 644, 1660, 676, 530]) - - def test_parse_and_report(self): - """Tests for the parse_and_report() function.""" - - # Without code generation. - output = StringIO() - input_str = """ - uint16_t rawbuf[139] = {9008, 4496, 644, 1660, 676, 530, 648, 558, 672, - 1636, 646, 1660, 644, 556, 650, 584, 626, 560, 644, 580, 628, 1680, - 624, 560, 648, 1662, 644, 582, 648, 536, 674, 530, 646, 580, 628, - 560, 670, 532, 646, 562, 644, 556, 672, 536, 648, 1662, 646, 1660, - 652, 554, 644, 558, 672, 538, 644, 560, 668, 560, 648, 1638, 668, - 536, 644, 1660, 668, 532, 648, 560, 648, 1660, 674, 554, 622, 19990, - 646, 580, 624, 1660, 648, 556, 648, 558, 674, 556, 622, 560, 644, - 564, 668, 536, 646, 1662, 646, 1658, 672, 534, 648, 558, 644, 562, - 648, 1662, 644, 584, 622, 558, 648, 562, 668, 534, 670, 536, 670, - 532, 672, 536, 646, 560, 646, 558, 648, 558, 670, 534, 650, 558, - 646, 560, 646, 560, 668, 1638, 646, 1662, 646, 1660, 646, 1660, - 648};""" - analyse.parse_and_report(input_str, 200, False, output) - self.assertEqual( - output.getvalue(), 'Found 139 timing entries.\n' - 'Potential Mark Candidates:\n' - '[9008, 676]\n' - 'Potential Space Candidates:\n' - '[19990, 4496, 1680, 584]\n' - '\n' - 'Guessing encoding type:\n' - 'Looks like it uses space encoding. Yay!\n' - '\n' - 'Guessing key value:\n' - 'kHdrMark = 9008\n' - 'kHdrSpace = 4496\n' - 'kBitMark = 650\n' - 'kOneSpace = 1657\n' - 'kZeroSpace = 554\n' - 'kSpaceGap = 19990\n' - '\n' - 'Decoding protocol based on analysis so far:\n' - '\n' - 'kHdrMark+kHdrSpace+10011000010100000000011000001010010GAP(19990)\n' - ' Bits: 35\n' - ' Hex: 0x4C2803052 (MSB first)\n' - ' 0x250600A19 (LSB first)\n' - ' Dec: 20443050066 (MSB first)\n' - ' 9938405913 (LSB first)\n' - ' Bin: 0b10011000010100000000011000001010010 (MSB first)\n' - ' 0b01001010000011000000000101000011001 (LSB first)\n' - 'kBitMark(UNEXPECTED)01000000110001000000000000001111\n' - ' Bits: 32\n' - ' Hex: 0x40C4000F (MSB first)\n' - ' 0xF0002302 (LSB first)\n' - ' Dec: 1086586895 (MSB first)\n' - ' 4026540802 (LSB first)\n' - ' Bin: 0b01000000110001000000000000001111 (MSB first)\n' - ' 0b11110000000000000010001100000010 (LSB first)\n' - '\n' - 'Total Nr. of suspected bits: 67\n') - - # With code generation. - output = StringIO() - input_str = """ - uint16_t rawbuf[37] = {7930, 3952, 494, 1482, 520, 1482, 494, - 1508, 494, 520, 494, 1482, 494, 520, 494, 1482, 494, 1482, 494, - 3978, 494, 520, 494, 520, 494, 520, 494, 520, 520, 520, 494, 520, - 494, 520, 494, 1482, 494};""" - analyse.parse_and_report(input_str, 200, True, output) - self.assertEqual( - output.getvalue(), 'Found 37 timing entries.\n' - 'Potential Mark Candidates:\n' - '[7930, 520]\n' - 'Potential Space Candidates:\n' - '[3978, 1508, 520]\n' - '\n' - 'Guessing encoding type:\n' - 'Looks like it uses space encoding. Yay!\n' - '\n' - 'Guessing key value:\n' - 'kHdrMark = 7930\n' - 'kHdrSpace = 3965\n' - 'kBitMark = 496\n' - 'kOneSpace = 1485\n' - 'kZeroSpace = 520\n' - '\n' - 'Decoding protocol based on analysis so far:\n' - '\n' - 'kHdrMark+kHdrSpace+11101011\n' - ' Bits: 8\n' - ' Hex: 0xEB (MSB first)\n' - ' 0xD7 (LSB first)\n' - ' Dec: 235 (MSB first)\n' - ' 215 (LSB first)\n' - ' Bin: 0b11101011 (MSB first)\n' - ' 0b11010111 (LSB first)\n' - 'UNEXPECTED->kHdrSpace+00000001\n' - ' Bits: 8\n' - ' Hex: 0x01 (MSB first)\n' - ' 0x80 (LSB first)\n' - ' Dec: 1 (MSB first)\n' - ' 128 (LSB first)\n' - ' Bin: 0b00000001 (MSB first)\n' - ' 0b10000000 (LSB first)\n' - '\n' - 'Total Nr. of suspected bits: 16\n' - '\n' - 'Generating a VERY rough code outline:\n' - '\n' - "// WARNING: This probably isn't directly usable. It's a guide only.\n" - 'const uint16_t kHdrMark = 7930;\n' - 'const uint16_t kBitMark = 496;\n' - 'const uint16_t kHdrSpace = 3965;\n' - 'const uint16_t kOneSpace = 1485;\n' - 'const uint16_t kZeroSpace = 520;\n' - 'const uint16_t kXyzBits = 16;\n' - '// Function should be safe up to 64 bits.\n' - 'void IRsend::sendXyz(const uint64_t data, const uint16_t nbits,' - ' const uint16_t repeat) {\n' - ' enableIROut(38); // A guess. Most common frequency.\n' - ' for (uint16_t r = 0; r <= repeat; r++) {\n' - ' // Header\n' - ' mark(kHdrMark);\n' - ' space(kHdrSpace);\n' - ' // Data\n' - ' // e.g. data = 0xEB, nbits = 8\n' - ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' - ' true);\n' - ' // Footer\n' - ' mark(kBitMark);\n' - ' space(kHdrSpace);\n' - ' // Data\n' - ' // e.g. data = 0x1, nbits = 8\n' - ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' - ' true);\n' - ' // Footer\n' - ' mark(kBitMark);\n' - ' space(100000); // A 100% made up guess of the gap between' - ' messages.\n' - ' }\n' - '}\n') - - def test_unusual_gaps(self): - """Tests for unusual Space Gaps in parse_and_report() function.""" - - # Tests for unusual Gaps. (Issue #482) - output = StringIO() - input_str = """ - uint16_t rawbuf[272] = {3485, 3512, 864, 864, 864, 2620, 864, 864, - 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, - 864, 2620, 864, 864, 864, 2620, 864, 2620, 864, 2620, 864, 2620, - 864, 2620, 864, 864, 864, 2620, 864, 864, 864, 864, 864, 864, - 864, 864, 864, 864, 864, 864, 864, 864, 864, 2620, 864, 864, - 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, - 3485, 3512, 864, 864, 864, 2620, 864, 864, 864, 2620, 864, 2620, - 864, 2620, 864, 2620, 864, 2620, 864, 864, 864, 2620, 864, 864, - 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, - 864, 2620, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, - 864, 864, 864, 864, 2620, 864, 864, 864, 864, 864, 864, 864, 864, - 864, 864, 864, 864, - 3485, 3512, 864, 13996, - 3485, 3512, 864, 864, 864, 864, 864, 2620, 864, 864, 864, 2620, - 864, 2620, 864, 2620, 864, 2620, 864, 864, 864, 864, 864, 2620, - 864, 864, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, - 864, 2620, 864, 2620, 864, 864, 864, 2620, 864, 2620, 864, 864, - 864, 864, 864, 864, 864, 2620, 864, 2620, 864, 864, 864, 2620, - 864, 2620, 864, 864, 864, 864, - 3485, 3512, 864, 864, 864, 864, 864, 2620, 864, 864, 864, 2620, - 864, 2620, 864, 2620, 864, 2620, 864, 864, 864, 864, 864, 2620, - 864, 864, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, - 864, 2620, 864, 2620, 864, 864, 864, 2620, 864, 2620, 864, 864, - 864, 864, 864, 864, 864, 2620, 864, 2620, 864, 864, 864, 2620, - 864, 2620, 864, 864, 864, 864, 3485, 3512, 864, 13996};""" - analyse.parse_and_report(input_str, 200, True, output) - self.assertEqual( - output.getvalue(), 'Found 272 timing entries.\n' - 'Potential Mark Candidates:\n' - '[3485, 864]\n' - 'Potential Space Candidates:\n' - '[13996, 3512, 2620, 864]\n' - '\n' - 'Guessing encoding type:\n' - 'Looks like it uses space encoding. Yay!\n' - '\n' - 'Guessing key value:\n' - 'kHdrMark = 3485\n' - 'kHdrSpace = 3512\n' - 'kBitMark = 864\n' - 'kOneSpace = 2620\n' - 'kZeroSpace = 864\n' - 'kSpaceGap = 13996\n' - '\n' - 'Decoding protocol based on analysis so far:\n' - '\n' - 'kHdrMark+kHdrSpace+01011111010111110100000001000000\n' - ' Bits: 32\n' - ' Hex: 0x5F5F4040 (MSB first)\n' - ' 0x0202FAFA (LSB first)\n' - ' Dec: 1600077888 (MSB first)\n' - ' 33749754 (LSB first)\n' - ' Bin: 0b01011111010111110100000001000000 (MSB first)\n' - ' 0b00000010000000101111101011111010 (LSB first)\n' - 'kHdrMark+kHdrSpace+01011111010111110100000001000000\n' - ' Bits: 32\n' - ' Hex: 0x5F5F4040 (MSB first)\n' - ' 0x0202FAFA (LSB first)\n' - ' Dec: 1600077888 (MSB first)\n' - ' 33749754 (LSB first)\n' - ' Bin: 0b01011111010111110100000001000000 (MSB first)\n' - ' 0b00000010000000101111101011111010 (LSB first)\n' - 'kHdrMark+kHdrSpace+GAP(13996)' - 'kHdrMark+kHdrSpace+00101111001011110110110001101100\n' - ' Bits: 32\n' - ' Hex: 0x2F2F6C6C (MSB first)\n' - ' 0x3636F4F4 (LSB first)\n' - ' Dec: 791637100 (MSB first)\n' - ' 909571316 (LSB first)\n' - ' Bin: 0b00101111001011110110110001101100 (MSB first)\n' - ' 0b00110110001101101111010011110100 (LSB first)\n' - 'kHdrMark+kHdrSpace+00101111001011110110110001101100\n' - ' Bits: 32\n' - ' Hex: 0x2F2F6C6C (MSB first)\n' - ' 0x3636F4F4 (LSB first)\n' - ' Dec: 791637100 (MSB first)\n' - ' 909571316 (LSB first)\n' - ' Bin: 0b00101111001011110110110001101100 (MSB first)\n' - ' 0b00110110001101101111010011110100 (LSB first)\n' - 'kHdrMark+kHdrSpace+GAP(13996)\n' - 'Total Nr. of suspected bits: 128\n' - '\n' - 'Generating a VERY rough code outline:\n' - '\n' - "// WARNING: This probably isn't directly usable. It's a guide only.\n" - 'const uint16_t kHdrMark = 3485;\n' - 'const uint16_t kBitMark = 864;\n' - 'const uint16_t kHdrSpace = 3512;\n' - 'const uint16_t kOneSpace = 2620;\n' - 'const uint16_t kZeroSpace = 864;\n' - 'const uint16_t kSpaceGap = 13996;\n' - 'const uint16_t kXyzBits = 128;\n' - 'const uint16_t kXyzStateLength = 16;\n' - "// DANGER: More than 64 bits detected. A uint64_t for 'data' won't" - ' work!\n' - '// Function should be safe up to 64 bits.\n' - 'void IRsend::sendXyz(const uint64_t data, const uint16_t nbits,' - ' const uint16_t repeat) {\n' - ' enableIROut(38); // A guess. Most common frequency.\n' - ' for (uint16_t r = 0; r <= repeat; r++) {\n' - ' // Header\n' - ' mark(kHdrMark);\n' - ' space(kHdrSpace);\n' - ' // Data\n' - ' // e.g. data = 0x5F5F4040, nbits = 32\n' - ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' - ' true);\n' - ' // Header\n' - ' mark(kHdrMark);\n' - ' space(kHdrSpace);\n' - ' // Data\n' - ' // e.g. data = 0x5F5F4040, nbits = 32\n' - ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' - ' true);\n' - ' // Header\n' - ' mark(kHdrMark);\n' - ' space(kHdrSpace);\n' - ' // Gap\n' - ' mark(kBitMark);\n' - ' space(kSpaceGap);\n' - ' // Header\n' - ' mark(kHdrMark);\n' - ' space(kHdrSpace);\n' - ' // Data\n' - ' // e.g. data = 0x2F2F6C6C, nbits = 32\n' - ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' - ' true);\n' - ' // Header\n' - ' mark(kHdrMark);\n' - ' space(kHdrSpace);\n' - ' // Data\n' - ' // e.g. data = 0x2F2F6C6C, nbits = 32\n' - ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits,' - ' true);\n' - ' // Header\n' - ' mark(kHdrMark);\n' - ' space(kHdrSpace);\n' - ' // Gap\n' - ' mark(kBitMark);\n' - ' space(kSpaceGap);\n' - ' space(100000); // A 100% made up guess of the gap between' - ' messages.\n' - ' }\n' - '}\n' - '\n' - '\n' - '// Alternative >64 bit Function\n' - 'void IRsend::sendXyz(uint8_t data[], uint16_t nbytes, uint16_t repeat)' - ' {\n' - ' // nbytes should typically be kXyzStateLength\n' - ' // data should typically be:\n' - ' // uint8_t data[kXyzStateLength] = {0x5F, 0x5F, 0x40, 0x40, 0x5F,' - ' 0x5F, 0x40, 0x40, 0x2F, 0x2F, 0x6C, 0x6C, 0x2F, 0x2F, 0x6C, 0x6C};\n' - ' // data[] is assumed to be in MSB order for this code.\n' - ' for (uint16_t r = 0; r <= repeat; r++) {\n' - ' sendGeneric(kHdrMark, kHdrSpace,\n' - ' kBitMark, kOneSpace,\n' - ' kBitMark, kZeroSpace,\n' - ' kBitMark,\n' - ' 100000, // 100% made-up guess at the message gap.\n' - ' data, nbytes,\n' - ' 38000, // Complete guess of the modulation' - ' frequency.\n' - ' true, 0, 50);\n' - ' }\n' - '}\n') - - def test_reduce_list(self): - """Tests for the reduce_list method.""" - - ignore = StringIO() - message = analyse.RawIRMessage(200, [ - 7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494, - 520, 494, 1482, 494, 1482, 494, 3978, 494, 520, 494, 520, 494, 520, 494, - 520, 520, 520, 494, 520, 494, 520, 494, 1482, 494 - ], ignore) - test_space_data = [4496, 1660, 530, 558, 1636, 1660, 556] - result_list, result_dict = message.reduce_list(test_space_data) - self.assertEqual([4496, 1660, 558], result_list) - self.assertEqual({ - 558: [558, 556, 530], - 1660: [1660, 1660, 1636], - 4496: [4496] - }, result_dict) - - def test_avg_list(self): - """Tests for the avg_list method.""" - - self.assertEqual(0, analyse.avg_list([])) - self.assertEqual(23, analyse.avg_list([10, 20, 40])) - - -if __name__ == '__main__': - unittest.main(verbosity=2) diff --git a/lib/IRremoteESP8266-2.6.5/CPPLINT.cfg b/lib/IRremoteESP8266-2.7.0/CPPLINT.cfg old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/CPPLINT.cfg rename to lib/IRremoteESP8266-2.7.0/CPPLINT.cfg diff --git a/lib/IRremoteESP8266-2.6.5/LICENSE.txt b/lib/IRremoteESP8266-2.7.0/LICENSE.txt old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/LICENSE.txt rename to lib/IRremoteESP8266-2.7.0/LICENSE.txt diff --git a/lib/IRremoteESP8266-2.6.5/README.md b/lib/IRremoteESP8266-2.7.0/README.md old mode 100755 new mode 100644 similarity index 90% rename from lib/IRremoteESP8266-2.6.5/README.md rename to lib/IRremoteESP8266-2.7.0/README.md index c4cb31515..c609eb632 --- a/lib/IRremoteESP8266-2.6.5/README.md +++ b/lib/IRremoteESP8266-2.7.0/README.md @@ -9,8 +9,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.6.5 Now Available -Version 2.6.4 of the library is now [available](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes. +## v2.7.0 Now Available +Version 2.7.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. @@ -25,12 +25,12 @@ The most likely externally used `#define`s have been _aliased_ for limited backward compatibility for projects using the old style. Going forward, only the new `kConstantName` style will be supported for new protocol additions. -In the unlikely case it does break your code, then you may have been referencing +In the unlikely case, it does break your code, then you may have been referencing something you likely should not have. You should be able to quickly determine the new name from the old. e.g. `CONSTANT_NAME` to `kConstantName`. Use common sense or examining the library's code if this does affect code. -## Supported protocols +## Supported Protocols You can find the details of which protocols & devices are supported [here](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/SupportedProtocols.md). @@ -55,22 +55,22 @@ Some common answers to common questions and problems are on our [F.A.Q. wiki pag 1. Restart your Arduino IDE. 1. Check out the examples. -##### Using Git to install library ( Linux ) +##### Using Git to install the library ( Linux ) ``` cd ~/Arduino/libraries git clone https://github.com/crankyoldgit/IRremoteESP8266.git ``` -###### To Update to the latest version of the library +###### To update to the latest version of the library ``` cd ~/Arduino/libraries/IRremoteESP8266 && git pull ``` ## Contributing If you want to [contribute](.github/CONTRIBUTING.md#how-can-i-contribute) to this project, consider: -- [Report](.github/CONTRIBUTING.md#reporting-bugs) bugs and errors +- [Reporting](.github/CONTRIBUTING.md#reporting-bugs) bugs and errors - Ask for enhancements - Improve our documentation -- [Create issues](.github/CONTRIBUTING.md#reporting-bugs) and [pull requests](.github/CONTRIBUTING.md#pull-requests) +- [Creating issues](.github/CONTRIBUTING.md#reporting-bugs) and [pull requests](.github/CONTRIBUTING.md#pull-requests) - Tell other people about this library ## Contributors diff --git a/lib/IRremoteESP8266-2.7.0/README_fr.md b/lib/IRremoteESP8266-2.7.0/README_fr.md new file mode 100644 index 000000000..38581eeb0 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/README_fr.md @@ -0,0 +1,83 @@ +# IRremote ESP8266 Library + +[![Build Status](https://travis-ci.org/crankyoldgit/IRremoteESP8266.svg?branch=master)](https://travis-ci.org/crankyoldgit/IRremoteESP8266) +[![arduino-library-badge](https://www.ardu-badge.com/badge/IRremoteESP8266.svg?)](https://www.ardu-badge.com/IRremoteESP8266) +[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/crankyoldgit/IRremoteESP8266.svg)](http://isitmaintained.com/project/crankyoldgit/IRremoteESP8266 "Average time to resolve an issue") +[![Percentage of issues still open](http://isitmaintained.com/badge/open/crankyoldgit/IRremoteESP8266.svg)](http://isitmaintained.com/project/crankyoldgit/IRremoteESP8266 "Percentage of issues still open") +[![GitLicense](https://gitlicense.com/badge/crankyoldgit/IRremoteESP8266)](https://gitlicense.com/license/crankyoldgit/IRremoteESP8266) + +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.0 disponible +Version 2.7.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. + +#### Mise à jour depuis pre-v2.5 +La librairie à changer, elle n'utilise plus les constantes déclarées comme `#define` mais comme : +[const](https://google.github.io/styleguide/cppguide.html#Constant_Names) avec le nom approprié par le langage +[C++ style guide](https://google.github.io/styleguide/cppguide.html). +Il se peut que d'ancien programme ne compile pas. +Le cas le plus utilisé de `#define`s à été remplacé par _aliased_ pour limiter +la compatibilité de revenir en arrière pour les vieux projet. En revenant en arrière seulement la +nouvelle `kConstantName` style est supporté. + +Dans le cas peu probable, votre code serait cassé, alors vous avez peut-être fait référence à +quelque chose que vous ne devriez probablement pas avoir.Vous devez être capable de determiner le nouveau nom +qui remplacera l'ancien. exemple : `CONSTANT_NAME` par `kConstantName`. +Si vous avez un problème examinez le code pour trouver le problème. + +## Protocoles supportés +Vous pouvez trouver le détails des protocoles et machines supportés +[here](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/SupportedProtocols.md). + +## Dépannage +Avant de reporter un probème ou de demander de l'aide, essayez de suivre notre [guide de dépannage](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Troubleshooting-Guide) first. + +## Questions fréquentes +Les questions les plus fréquentes sont ici, avec des réponses [F.A.Q. wiki page](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Frequently-Asked-Questions). + +## Installation +##### Officiel releases avec l'Arduino IDE v1.8+ (Windows & Linux) +1. Cliquez sur _"Sketch"_ -> _"Include Library"_ -> _"Manage Libraries..."_ Menu items. +1. Entrez `IRremoteESP8266` dans le _"Filter your search..."_ barre de recherche en haut à droite. +1. Cliquez sur le IRremoteESP8266 pour avoir les résultats de la recherche. +1. Selectionnez la version que vous voulez installer et cliquez sur _"Install"_. + +##### Installation manuelle pour Windows +1. cliquez le boutton sur _"Clone or Download"_ , et _"[Download ZIP](https://github.com/crankyoldgit/IRremoteESP8266/archive->master.zip)"_ on the page. +1. Extraire l'archive. +1. renommez le fichier par _"IRremoteESP8266"_. +1. déplacer le fichier dans votre fichier de bibliothèques. (Pour windows : `C:\Users\VOTRE_NOM\Documents\Arduino\libraries\`) +1. Redemarrez arduino IDE. +1. Regardez les exemples. + +##### En utilisant GIT ( Linux ) +``` +cd ~/Arduino/libraries +git clone https://github.com/crankyoldgit/IRremoteESP8266.git +``` +###### Pour se mettre à jour +``` +cd ~/Arduino/libraries/IRremoteESP8266 && git pull +``` + +## Contribution +Si vous voulez [contribuer](.github/CONTRIBUTING.md#how-can-i-contribute) au projet, pour les erreurs: +- [Reporting](.github/CONTRIBUTING.md#reporting-bugs) bug et erreurs +- Demander des améliorations +- Améliorer notre documentation +- [Création d'issues](.github/CONTRIBUTING.md#reporting-bugs) et [pull requests](.github/CONTRIBUTING.md#pull-requests) +- Parlez de cettre librairie à d'autres personnes + +## Contributeurs +disponible [ici](.github/Contributors.md) + +## Historique de la bibliothèque +Elle est basée sur le travail de Shirriff (https://github.com/shirriff/Arduino-IRremote/) + +[Mark Szabo](https://github.com/crankyoldgit/IRremoteESP8266) à mis a jour la IRsend class pour qu'elle soit fonctionnelle sur ESP8266 et [Sebastien Warin](https://github.com/sebastienwarin/IRremoteESP8266) s'est occupé de la partie réception et décodage (IRrecv class). + +Comme pour la version 2.0, la bibliothèque à été completement réécrite avec les ressources sur ESP8266. diff --git a/lib/IRremoteESP8266-2.6.5/ReleaseNotes.md b/lib/IRremoteESP8266-2.7.0/ReleaseNotes.md old mode 100755 new mode 100644 similarity index 86% rename from lib/IRremoteESP8266-2.6.5/ReleaseNotes.md rename to lib/IRremoteESP8266-2.7.0/ReleaseNotes.md index 5672d2483..cdc5ad4a2 --- a/lib/IRremoteESP8266-2.6.5/ReleaseNotes.md +++ b/lib/IRremoteESP8266-2.7.0/ReleaseNotes.md @@ -1,5 +1,76 @@ # Release Notes +## _v2.7.0 (20191030)_ + +**[Bug Fixes]** +- auto_analyse: Fix > 64 bit send code generation. (#976) +- auto_analyse: Fix missing arguments in generated code for send64+ (#972) +- IRsendProntoDemo: Fix compile issue on ESP32 platform. (#938) +- IRMQTTServer: Fix compile error when `MQTT_ENABLE` is false. (#933) + +**[Features]** +- Add Hitachi 424 bit A/C support. (#975, #980, #981) +- Experimental detailed support for `DAIKIN152` (#971) +- Mitsubishi 112bit A/C support (#947, #968) +- gc_decode: Adding Support for Decoding codes in raw code format (#963) +- Refactor to use common routines/macros to handle bit manipulation. (#934) +- Use centralised common strings. Saves ~1.5k of program space. (#946) +- Add Internationalisation (i18n) / Locale support. (#946, #955, #966) + - `de-CH`: Swiss German. (#949, #954) + - `de-DE`: German. (#946, #950, #952) + - `en-AU`: English/Australia (Default locale) (#946) + - `en-IE`: English/Ireland (#946) + - `en-UK`: English/United Kingdom (#946) + - `en-US`: English/United States (#946) + - `es-ES`: Spanish. (#953) + - `fr-FR`: French. (#962) +- Port CI pipeline to PlatformIO (#936) + +**[Misc]** +- Add DAIKIN128 & DAIKIN152 to `decodeToState()` (#982) +- auto_analyse: Produce better code when leader is detected. (#977) +- Coolix A/C improvements (#944) +- A/C setRaw/getRaw/stateReset() cleanup. (#967) +- Add documentation on how to use & support the i18n aspects of the library. +- Make travis checks faster. (#957) +- Translate README.md to french (#959) +- Fixed Coolix kCoolixDefaultState (#941) +- Improve generation of list of pio projects. (#940) + + +## _v2.6.6 (20190923)_ + +**[Bug Fixes]** +- Ensure `begin()` is called for every supported common a/c. (#905, #899) +- IRMQTTServer: Fix JSON state parsing. (#896) +- IRMQTTServer: Fix compilation error when `MQTT_CLIMATE_JSON` is `true`. (#893) + +**[Features]** +- Mitsubishi136: Full A/C support. (#898, #890) +- Fujitsu: Add support for ARRY4 remote. (#895) +- Web-AC-control: Add new WebUI example sketch. (#880, #886) +- Improve Common A/C API (#913) +- IRMQTTServer: Support for multiple climates. (#903) +- IRMQTTServer: Add TX channel support for HTTP interface. (#929) +- IRMQTTServer: Add option to clear retained settings. (#917) +- auto_analyse_raw_data.py: Add decode code generation. (#909) +- auto_analyse_raw_data.py: General improvements (#906) + +**[Misc]** +- IRMQTTServer: Use latest API for common A/C. (#928) +- IRMQTTServer: Add flag & documentation for Home Assistant mode. (#919) +- IRMQTTServer: Move from ArduinoJson v5 to v6. (#878) +- IRMQTTServer: Use retain for discovery message. (#881) +- Goodweather: Adjust timings & minor fixes. (#924) +- PanasonicAc: Add better SwingV support for common a/c framework. (#923) +- Daikin2: Corrections for common A/C interface. (#910) +- MitsubishiAC: Improve decoding. (#914) +- Fujitsu: Disable horiz swing for ARRY4. (#907) +- SamsungAc: Only send power on/off code if it's needed. (#884) +- Teco: Add timer support. (#883) +- More consistent A/C `::toString()` output. (#920) + + ## _v2.6.5 (20190828)_ **[Bug Fixes]** diff --git a/lib/IRremoteESP8266-2.6.5/SupportedProtocols.md b/lib/IRremoteESP8266-2.7.0/SupportedProtocols.md old mode 100755 new mode 100644 similarity index 89% rename from lib/IRremoteESP8266-2.6.5/SupportedProtocols.md rename to lib/IRremoteESP8266-2.7.0/SupportedProtocols.md index c9d286973..afd31587e --- a/lib/IRremoteESP8266-2.6.5/SupportedProtocols.md +++ b/lib/IRremoteESP8266-2.7.0/SupportedProtocols.md @@ -1,6 +1,6 @@ + Last generated: Wed Oct 30 13:41:10 2019 ---> # IR Protocols supported by this library | Protocol | Brand | Model | A/C Model | Detailed A/C Support | @@ -11,21 +11,22 @@ | [Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.cpp) | **Carrier/Surrey** | 42QG5A55970 remote
53NGK009/012 Inverter
619EGX0090E0 A/C
619EGX0120E0 A/C
619EGX0180E0 A/C
619EGX0220E0 A/C | | - | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Beko](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | BINR 070/071 split-type A/C
BINR 070/071 split-type A/C
RG57K7(B)/BGEF Remote
RG57K7(B)/BGEF Remote | | Yes | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | MS12FU-10HRDN1-QRD0GW(B) A/C
MS12FU-10HRDN1-QRD0GW(B) A/C
MSABAU-07HRFN1-QRD0GW A/C (circa 2016)
MSABAU-07HRFN1-QRD0GW A/C (circa 2016)
RG52D/BGE Remote
RG52D/BGE Remote | | Yes | +| [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Tokio](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | AATOEMF17-12CHR1SW split-type RG51|50/BGE Remote
AATOEMF17-12CHR1SW split-type RG51|50/BGE Remote | | Yes | | [Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.cpp) | **[Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.h)** | 17 Series A/C (DAIKIN128)
ARC423A5 remote
ARC433** remote
ARC433B69 remote
ARC477A1 remote
ARC480A5 remote (DAIKIN152)
BRC4C153 remote
BRC52B63 remote (DAIKIN128)
FTE12HV2S A/C
FTXB09AXVJU A/C (DAIKIN128)
FTXB12AXVJU A/C (DAIKIN128)
FTXZ25NV1B A/C
FTXZ35NV1B A/C
FTXZ50NV1B A/C | | Yes | | [Denon](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Denon.cpp) | **Unknown** | | | - | | [Dish](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Dish.cpp) | **DISH NETWORK** | echostar 301 | | - | | [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
YKR-T/011 remote | | Yes | -| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AR-DB1 remote
AR-RAE1E remote
AR-RAH2E remote
AR-REB1E remote
AST9RSGCW A/C
ASYG30LFCA A/C
ASYG7LMCA A/C | ARDB1
ARJW2
ARRAH2E
ARREB1E | 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)** | AR-JW2 remote | ARDB1
ARJW2
ARRAH2E
ARREB1E | Yes | +| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AGTV14LAC A/C
AR-DB1 remote
AR-DL10 remote
AR-RAC1E remote
AR-RAE1E remote
AR-RAH2E remote
AR-REB1E remote
AR-RY4 remote
AST9RSGCW A/C
ASTB09LBC A/C
ASU30C1 A/C
ASYG30LFCA A/C
ASYG7LMCA A/C | | 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)** | AR-JW2 remote | | Yes | | [GICable](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GICable.cpp) | **Unknown** | | | - | | [GlobalCache](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GlobalCache.cpp) | **Unknown** | | | - | | [Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.cpp) | **[Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.h)** | ZH/JT-03 remote | | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[EKOKAI](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | A/C | YAW1F
YBOFB | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YBOFB remote
YBOFB2 remote | YAW1F
YBOFB | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[RusClimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | EACS/I-09HAR_X/N3 A/C
YAW1F remote | YAW1F
YBOFB | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Ultimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | Heat Pump | YAW1F
YBOFB | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[EKOKAI](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | A/C | | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YBOFB remote
YBOFB2 remote | | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[RusClimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | EACS/I-09HAR_X/N3 A/C
YAW1F remote | | 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 | | 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
HSU07-HEA03 remote
YR-W02 remote | | 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)** | LT0541-HTA remote
RAS-35THA6 remote
Series VI A/C (Circa 2007) | | 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)** | LT0541-HTA remote
RAR-8P2 remote
RAS-35THA6 remote
RAS-AJ25H A/C
Series VI A/C (Circa 2007) | | Yes | | [Inax](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Inax.cpp) | **Lixil** | Inax DT-BA283 Toilet | | - | | [JVC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_JVC.cpp) | **Unknown** | | | - | | [Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.h)** | YAPOF3 remote | | Yes | @@ -39,12 +40,13 @@ | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Comfee](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | MPD1-12CRN7 A/C | | Yes | | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Keystone](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG57H4(B)BGEF remote | | Yes | | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Pioneer System](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RUBO18GMFILCAD A/C (18K BTU)
RYBO12GMFILCAD A/C (12K BTU) | | 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
TV | | 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
KM14A 0179213 remote
MS-GK24VA A/C
TV | | 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
KPOA remote
MSH-A24WV / MUH-A24WV A/C
PEAD-RP71JAA Ducted A/C | | 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
RLA502A700B remote
SRKxxZJ-S A/C
SRKxxZM-S A/C
SRKxxZMXA-S A/C | | Yes | | [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Yamaha](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | RAV561 remote
RXV585B A/V Receiver | | Yes | | [Neoclima](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Neoclima.cpp) | **[Neoclima](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Neoclima.h)** | NS-09AHTI A/C
NS-09AHTI A/C
ZH/TY-01 remote
ZH/TY-01 remote | | Yes | | [Nikai](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Nikai.cpp) | **Unknown** | | | - | -| [Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.cpp) | **[Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.h)** | A75C2311 remote (CKP)
A75C3704 remote
A75C3747 remote
A75C3747 remote
A75C3747 remote
A75C3747 remote
CKP series A/C
CS-ME10CKPG A/C
CS-ME12CKPG A/C
CS-ME14CKPG A/C
CS-YW9MKD A/C
CS-Z9RKR A/C
DKE series A/C
JKE series A/C
NKE series A/C
RKR series A/C
TV | CKP
DKE
JKE
LKE
NKE
RKR | Yes | +| [Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.cpp) | **[Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.h)** | A75C2311 remote (CKP)
A75C3704 remote
A75C3747 remote
A75C3747 remote
A75C3747 remote
A75C3747 remote
CKP series A/C
CS-ME10CKPG A/C
CS-ME12CKPG A/C
CS-ME14CKPG A/C
CS-YW9MKD A/C
CS-Z9RKR A/C
DKE series A/C
JKE series A/C
NKE series A/C
RKR series A/C
TV | | Yes | | [Pioneer](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Pioneer.cpp) | **Unknown** | | | - | | [Pronto](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Pronto.cpp) | **Unknown** | | | - | | [RC5_RC6](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_RC5_RC6.cpp) | **Unknown** | | | - | @@ -59,16 +61,18 @@ | [Toshiba](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Toshiba.cpp) | **[Toshiba](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Toshiba.h)** | Akita EVO II
RAS 18SKP-ES
RAS-B13N3KV2
RAS-B13N3KVP-E
WC-L03SE
WH-TA04NE | | Yes | | [Trotec](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Trotec.cpp) | **[Unknown](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Trotec.h)** | | | Yes | | [Vestel](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Vestel.cpp) | **[Vestel](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Vestel.h)** | BIOX CXP-9 A/C (9K BTU) | | Yes | -| [Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.cpp) | **[Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.h)** | DG11J1-04 remote
DG11J1-3A remote
DG11J1-91 remote
SPIS409L A/C
SPIS412L A/C
SPIW409L A/C
SPIW412L A/C
SPIW418L A/C | DG11J13A
DG11J191 | Yes | +| [Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.cpp) | **[Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.h)** | DG11J1-04 remote
DG11J1-3A remote
DG11J1-91 remote
SPIS409L A/C
SPIS412L A/C
SPIW409L A/C
SPIW412L A/C
SPIW418L A/C | | Yes | | [Whynter](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whynter.cpp) | **Whynter** | ARC-110WD A/C | | - | ## Send only protocols: - GLOBALCACHE +- MITSUBISHI112 - PRONTO - RAW - SHERWOOD +- TCL112AC ## Send & decodable protocols: @@ -97,6 +101,7 @@ - HITACHI_AC - HITACHI_AC1 - HITACHI_AC2 +- HITACHI_AC424 - INAX - JVC - KELVINATOR @@ -108,6 +113,7 @@ - MAGIQUEST - MIDEA - MITSUBISHI +- MITSUBISHI136 - MITSUBISHI2 - MITSUBISHI_AC - MITSUBISHI_HEAVY_152 @@ -132,10 +138,10 @@ - SHARP - SHARP_AC - SONY -- TCL112AC - TECO - TOSHIBA_AC - TROTEC - VESTEL_AC - WHIRLPOOL_AC - WHYNTER +- typeguess diff --git a/lib/IRremoteESP8266-2.7.0/examples/CommonAcControl/CommonAcControl.ino b/lib/IRremoteESP8266-2.7.0/examples/CommonAcControl/CommonAcControl.ino new file mode 100644 index 000000000..4e11e631d --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/CommonAcControl/CommonAcControl.ino @@ -0,0 +1,72 @@ +/* Copyright 2019 David Conran +* +* This example code demonstrates how to use the "Common" IRac class to control +* various air conditions. The IRac class does not support all the features +* for every protocol. Some have more detailed support that what the "Common" +* interface offers, and some only have a limited subset of the "Common" options. +* +* This example code will: +* o Try to turn on, then off every fully supported A/C protocol we know of. +* o It will try to put the A/C unit into Cooling mode at 25C, with a medium +* fan speed, and no fan swinging. +* Note: Some protocols support multiple models, only the first model is tried. +* +*/ +#include +#include +#include +#include + +const uint16_t kIrLed = 4; // The ESP GPIO pin to use that controls the IR LED. +IRac ac(kIrLed); // Create a A/C object using GPIO to sending messages with. + +void setup() { + Serial.begin(115200); + delay(200); + + // Set up what we want to send. + // See state_t, opmode_t, fanspeed_t, swingv_t, & swingh_t in IRsend.h for + // all the various options. + ac.next.protocol = decode_type_t::DAIKIN; // Set a protocol to use. + ac.next.model = 1; // Some A/Cs have different models. Try just the first. + ac.next.mode = stdAc::opmode_t::kCool; // Run in cool mode initially. + ac.next.celsius = true; // Use Celsius for temp units. False = Fahrenheit + ac.next.degrees = 25; // 25 degrees. + ac.next.fanspeed = stdAc::fanspeed_t::kMedium; // Start the fan at medium. + ac.next.swingv = stdAc::swingv_t::kOff; // Don't swing the fan up or down. + ac.next.swingh = stdAc::swingh_t::kOff; // Don't swing the fan left or right. + ac.next.light = false; // Turn off any LED/Lights/Display that we can. + ac.next.beep = false; // Turn off any beep from the A/C if we can. + ac.next.econo = false; // Turn off any economy modes if we can. + ac.next.filter = false; // Turn off any Ion/Mold/Health filters if we can. + ac.next.turbo = false; // Don't use any turbo/powerful/etc modes. + ac.next.quiet = false; // Don't use any quiet/silent/etc modes. + ac.next.sleep = -1; // Don't set any sleep time or modes. + ac.next.clean = false; // Turn off any Cleaning options if we can. + ac.next.clock = -1; // Don't set any current time if we can avoid it. + ac.next.power = false; // Initially start with the unit off. + + Serial.println("Try to turn on & off every supported A/C type ..."); +} + +void loop() { + // For every protocol the library has ... + for (int i = 1; i < kLastDecodeType; i++) { + decode_type_t protocol = (decode_type_t)i; + // If the protocol is supported by the IRac class ... + if (ac.isProtocolSupported(protocol)) { + Serial.println("Protocol " + String(protocol) + " / " + + typeToString(protocol) + " is supported."); + ac.next.protocol = protocol; // Change the protocol used. + ac.next.power = true; // We want to turn on the A/C unit. + Serial.println("Sending a message to turn ON the A/C unit."); + ac.sendAc(); // Have the IRac class create and send a message. + delay(5000); // Wait 5 seconds. + ac.next.power = false; // Now we want to turn the A/C off. + Serial.println("Send a message to turn OFF the A/C unit."); + ac.sendAc(); // Send the message. + delay(1000); // Wait 1 second. + } + } + Serial.println("Starting from the begining again ..."); +} diff --git a/lib/IRremoteESP8266-2.6.5/examples/CommonAcControl/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/CommonAcControl/platformio.ini old mode 100755 new mode 100644 similarity index 86% rename from lib/IRremoteESP8266-2.6.5/examples/CommonAcControl/platformio.ini rename to lib/IRremoteESP8266-2.7.0/examples/CommonAcControl/platformio.ini index 1aba0afcc..e6f6320da --- a/lib/IRremoteESP8266-2.6.5/examples/CommonAcControl/platformio.ini +++ b/lib/IRremoteESP8266-2.7.0/examples/CommonAcControl/platformio.ini @@ -5,14 +5,13 @@ src_dir = . lib_extra_dirs = ../../ lib_ldf_mode = deep+ lib_ignore = examples -build_flags = +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU [env:nodemcuv2] platform = espressif8266 -framework = arduino board = nodemcuv2 [env:esp32dev] platform = espressif32 -framework = arduino board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/ControlSamsungAC/ControlSamsungAC.ino b/lib/IRremoteESP8266-2.7.0/examples/ControlSamsungAC/ControlSamsungAC.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/ControlSamsungAC/ControlSamsungAC.ino rename to lib/IRremoteESP8266-2.7.0/examples/ControlSamsungAC/ControlSamsungAC.ino diff --git a/lib/IRremoteESP8266-2.6.5/examples/ControlSamsungAC/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/ControlSamsungAC/platformio.ini old mode 100755 new mode 100644 similarity index 86% rename from lib/IRremoteESP8266-2.6.5/examples/ControlSamsungAC/platformio.ini rename to lib/IRremoteESP8266-2.7.0/examples/ControlSamsungAC/platformio.ini index 1aba0afcc..e6f6320da --- a/lib/IRremoteESP8266-2.6.5/examples/ControlSamsungAC/platformio.ini +++ b/lib/IRremoteESP8266-2.7.0/examples/ControlSamsungAC/platformio.ini @@ -5,14 +5,13 @@ src_dir = . lib_extra_dirs = ../../ lib_ldf_mode = deep+ lib_ignore = examples -build_flags = +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU [env:nodemcuv2] platform = espressif8266 -framework = arduino board = nodemcuv2 [env:esp32dev] platform = espressif32 -framework = arduino board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/DumbIRRepeater/DumbIRRepeater.ino b/lib/IRremoteESP8266-2.7.0/examples/DumbIRRepeater/DumbIRRepeater.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/DumbIRRepeater/DumbIRRepeater.ino rename to lib/IRremoteESP8266-2.7.0/examples/DumbIRRepeater/DumbIRRepeater.ino diff --git a/lib/IRremoteESP8266-2.6.5/examples/DumbIRRepeater/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/DumbIRRepeater/platformio.ini old mode 100755 new mode 100644 similarity index 86% rename from lib/IRremoteESP8266-2.6.5/examples/DumbIRRepeater/platformio.ini rename to lib/IRremoteESP8266-2.7.0/examples/DumbIRRepeater/platformio.ini index 1aba0afcc..e6f6320da --- a/lib/IRremoteESP8266-2.6.5/examples/DumbIRRepeater/platformio.ini +++ b/lib/IRremoteESP8266-2.7.0/examples/DumbIRRepeater/platformio.ini @@ -5,14 +5,13 @@ src_dir = . lib_extra_dirs = ../../ lib_ldf_mode = deep+ lib_ignore = examples -build_flags = +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU [env:nodemcuv2] platform = espressif8266 -framework = arduino board = nodemcuv2 [env:esp32dev] platform = espressif32 -framework = arduino board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRGCSendDemo/IRGCSendDemo.ino b/lib/IRremoteESP8266-2.7.0/examples/IRGCSendDemo/IRGCSendDemo.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/IRGCSendDemo/IRGCSendDemo.ino rename to lib/IRremoteESP8266-2.7.0/examples/IRGCSendDemo/IRGCSendDemo.ino diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRGCSendDemo/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/IRGCSendDemo/platformio.ini old mode 100755 new mode 100644 similarity index 86% rename from lib/IRremoteESP8266-2.6.5/examples/IRGCSendDemo/platformio.ini rename to lib/IRremoteESP8266-2.7.0/examples/IRGCSendDemo/platformio.ini index 1aba0afcc..e6f6320da --- a/lib/IRremoteESP8266-2.6.5/examples/IRGCSendDemo/platformio.ini +++ b/lib/IRremoteESP8266-2.7.0/examples/IRGCSendDemo/platformio.ini @@ -5,14 +5,13 @@ src_dir = . lib_extra_dirs = ../../ lib_ldf_mode = deep+ lib_ignore = examples -build_flags = +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU [env:nodemcuv2] platform = espressif8266 -framework = arduino board = nodemcuv2 [env:esp32dev] platform = espressif32 -framework = arduino board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRGCTCPServer/IRGCTCPServer.ino b/lib/IRremoteESP8266-2.7.0/examples/IRGCTCPServer/IRGCTCPServer.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/IRGCTCPServer/IRGCTCPServer.ino rename to lib/IRremoteESP8266-2.7.0/examples/IRGCTCPServer/IRGCTCPServer.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/IRGCTCPServer/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/IRGCTCPServer/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/IRGCTCPServer/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRMQTTServer/IRMQTTServer.h b/lib/IRremoteESP8266-2.7.0/examples/IRMQTTServer/IRMQTTServer.h old mode 100755 new mode 100644 similarity index 88% rename from lib/IRremoteESP8266-2.6.5/examples/IRMQTTServer/IRMQTTServer.h rename to lib/IRremoteESP8266-2.7.0/examples/IRMQTTServer/IRMQTTServer.h index 73821dc05..eb5a4e37f --- a/lib/IRremoteESP8266-2.6.5/examples/IRMQTTServer/IRMQTTServer.h +++ b/lib/IRremoteESP8266-2.7.0/examples/IRMQTTServer/IRMQTTServer.h @@ -68,7 +68,7 @@ const IPAddress kSubnetMask = IPAddress(255, 255, 255, 0); #endif // USE_STATIC_IP // See: https://github.com/tzapu/WiFiManager#filter-networks for these settings. -#define HIDE_DUPLIATE_NETWORKS false // Should WifiManager hide duplicate SSIDs +#define HIDE_DUPLICATE_NETWORKS false // Make WifiManager hide duplicate SSIDs // #define MIN_SIGNAL_STRENGTH 20 // Minimum WiFi signal stength (percentage) // before we will connect. // The unset default is 8%. @@ -100,6 +100,11 @@ const uint32_t kMqttReconnectTime = 5000; // Delay(ms) between reconnect tries. #define MQTT_CLIMATE_STAT "stat" // Sub-topic for the climate stat topics. // Enable sending/receiving climate via JSON. `true` cost ~5k of program space. #define MQTT_CLIMATE_JSON false +// Use Home Assistant-style operation modes. +// i.e. Change the climate mode to "off" when turning the power "off". +// See: https://www.home-assistant.io/components/climate.mqtt/#modes +// Change to false, if your home automation system doesn't like this. +#define MQTT_CLIMATE_HA_MODE true // Do we send an IR message when we reboot and recover the existing A/C state? // If set to `false` you may miss requested state changes while the ESP was // down. If set to `true`, it will resend the previous desired state sent to the @@ -109,9 +114,15 @@ const uint32_t kMqttReconnectTime = 5000; // Delay(ms) between reconnect tries. #define QOS 1 // MQTT broker should queue up any unreceived messages for us // #define QOS 0 // MQTT broker WON'T queue up messages for us. Fire & Forget. + // Enable(true)/Disable(false) the option to send a MQTT Discovery message for -// the AirCon/Climate system to Home Assistant. `false` saves ~1.5k. +// the AirCon/Climate system to Home Assistant. Note: `false` saves ~1.5k. #define MQTT_DISCOVERY_ENABLE true +// Enable(true)/Disable(false) the option to clear any settings stored in MQTT +// for this device's current config. e.g. Climate states using MQTT retain. +// In theory, you shouldn't need this as you can always clean up by hand, hence +// it is disabled by default. Note: `false` saves ~1.2k. +#define MQTT_CLEAR_ENABLE false #endif // MQTT_ENABLE // ------------------------ IR Capture Settings -------------------------------- @@ -195,6 +206,7 @@ const uint16_t kMinUnknownSize = 2 * 10; #define KEY_CODE "code" #define KEY_BITS "bits" #define KEY_REPEAT "repeats" +#define KEY_CHANNEL "channel" // Which IR TX channel to send on. // GPIO html/config keys #define KEY_TX_GPIO "tx" @@ -209,6 +221,11 @@ const uint8_t kPortLength = 5; // Largest value of uint16_t is "65535". const uint8_t kUsernameLength = 15; const uint8_t kPasswordLength = 20; +// -------------------------- Json Settings ------------------------------------ + +const uint16_t kJsonConfigMaxSize = 512; // Bytes +const uint16_t kJsonAcStateMaxSize = 1024; // Bytes + // -------------------------- Debug Settings ----------------------------------- // Debug output is disabled if any of the IR pins are on the TX (D1) pin. // See `isSerialGpioUsedByIr()`. @@ -220,7 +237,7 @@ const uint8_t kPasswordLength = 20; // ----------------- End of User Configuration Section ------------------------- // Constants -#define _MY_VERSION_ "v1.3.4" +#define _MY_VERSION_ "v1.4.4" const uint8_t kRebootTime = 15; // Seconds const uint8_t kQuickDisplayTime = 2; // Seconds @@ -267,10 +284,13 @@ const char* kUrlGpioSet = "/gpio/set"; const char* kUrlInfo = "/info"; const char* kUrlReboot = "/quitquitquit"; const char* kUrlWipe = "/reset"; +const char* kUrlClearMqtt = "/clear_retained"; #if MQTT_ENABLE const uint32_t kBroadcastPeriodMs = MQTTbroadcastInterval * 1000; // mSeconds. -const uint32_t kStatListenPeriodMs = 5 * 1000; // mSeconds +// How long should we listen to recover for previous states? +// 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 kPauseChar = 'P'; @@ -290,6 +310,12 @@ const char* kClimateTopics = "|" KEY_JSON #endif // MQTT_CLIMATE_JSON ")
"; +const char* kMqttTopics[] = { + KEY_PROTOCOL, KEY_MODEL, KEY_POWER, KEY_MODE, KEY_TEMP, KEY_FANSPEED, + KEY_SWINGV, KEY_SWINGH, KEY_QUIET, KEY_TURBO, KEY_LIGHT, KEY_BEEP, + KEY_ECONO, KEY_SLEEP, KEY_FILTER, KEY_CLEAN, KEY_CELSIUS, KEY_RESEND, + KEY_JSON}; // KEY_JSON needs to be the last one. + void mqttCallback(char* topic, byte* payload, unsigned int length); String listOfCommandTopics(void); @@ -303,12 +329,13 @@ void receivingMQTT(String const topic_name, String const callback_str); void callback(char* topic, byte* payload, unsigned int length); void sendMQTTDiscovery(const char *topic); void doBroadcast(TimerMs *timer, const uint32_t interval, - const stdAc::state_t state, const bool retain, + IRac *climates[], const bool retain, const bool force); #if MQTT_CLIMATE_JSON -stdAc::state_t jsonToState(const stdAc::state_t current, const String str); +stdAc::state_t jsonToState(const stdAc::state_t current, const char *str); void sendJsonState(const stdAc::state_t state, const String topic, - const bool retain = false, const bool ha_mode = true); + const bool retain = false, + const bool ha_mode = MQTT_CLIMATE_HA_MODE); #endif // MQTT_CLIMATE_JSON #endif // MQTT_ENABLE #if REPORT_VCC @@ -327,6 +354,7 @@ String gpioToString(const int16_t gpio); uint8_t getDefaultIrSendIdx(void); IRsend* getDefaultIrSendPtr(void); int8_t getDefaultTxGpio(void); +String genStatTopic(const uint16_t channel = 0); String listOfTxGpios(void); bool hasUnsafeHTMLChars(String input); String htmlHeader(const String title, const String h1_text = ""); @@ -382,12 +410,11 @@ bool sendInt(const String topic, const int32_t num, const bool retain); bool sendBool(const String topic, const bool on, const bool retain); bool sendString(const String topic, const String str, const bool retain); bool sendFloat(const String topic, const float_t temp, const bool retain); -stdAc::state_t updateClimate(stdAc::state_t current, const String str, - const String prefix, const String payload); +void updateClimate(stdAc::state_t *current, const String str, + const String prefix, const String payload); bool cmpClimate(const stdAc::state_t a, const stdAc::state_t b); -bool sendClimate(const stdAc::state_t prev, const stdAc::state_t next, - const String topic_prefix, const bool retain, +bool sendClimate(const String topic_prefix, const bool retain, const bool forceMQTT, const bool forceIR, - const bool enableIR = true); + const bool enableIR = true, IRac *ac = NULL); bool decodeCommonAc(const decode_results *decode); #endif // EXAMPLES_IRMQTTSERVER_IRMQTTSERVER_H_ diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRMQTTServer/IRMQTTServer.ino b/lib/IRremoteESP8266-2.7.0/examples/IRMQTTServer/IRMQTTServer.ino old mode 100755 new mode 100644 similarity index 84% rename from lib/IRremoteESP8266-2.6.5/examples/IRMQTTServer/IRMQTTServer.ino rename to lib/IRremoteESP8266-2.7.0/examples/IRMQTTServer/IRMQTTServer.ino index 730a8965f..6373181a0 --- a/lib/IRremoteESP8266-2.6.5/examples/IRMQTTServer/IRMQTTServer.ino +++ b/lib/IRremoteESP8266-2.7.0/examples/IRMQTTServer/IRMQTTServer.ino @@ -31,7 +31,7 @@ * * - Arduino IDE: * o Install the following libraries via Library Manager - * - ArduinoJson (https://arduinojson.org/) (Version >= 5.0 and < 6.0) + * - ArduinoJson (https://arduinojson.org/) (Version >= 6.0) * - PubSubClient (https://pubsubclient.knolleary.net/) * - WiFiManager (https://github.com/tzapu/WiFiManager) * (ESP8266: Version >= 0.14, ESP32: 'development' branch.) @@ -72,10 +72,14 @@ * http:///ir?type=31&code=40000,1,1,96,24,24,24,48,24,24,24,24,24,48,24,24,24,24,24,48,24,24,24,24,24,24,24,24,1058 * http:///ir?type=18&code=190B8050000000E0190B8070000010f0 * http:///ir?repeats=1&type=25&code=0000,006E,0022,0002,0155,00AA,0015,0040,0015,0040,0015,0015,0015,0015,0015,0015,0015,0015,0015,0015,0015,0040,0015,0040,0015,0015,0015,0040,0015,0015,0015,0015,0015,0015,0015,0040,0015,0015,0015,0015,0015,0040,0015,0040,0015,0015,0015,0015,0015,0015,0015,0015,0015,0015,0015,0040,0015,0015,0015,0015,0015,0040,0015,0040,0015,0040,0015,0040,0015,0040,0015,0640,0155,0055,0015,0E40 + * If you have enabled more than 1 TX GPIO, you can use the "channel" argument: + * http:///ir?channel=0&type=7&code=E0E09966 + * http:///ir?channel=1&type=7&code=E0E09966 * * or * - * Send a MQTT message to the topic 'ir_server/send' (or 'ir_server/send_0' etc) + * Send a MQTT message to the topic 'ir_server/send' + * (or 'ir_server/send_1' etc if you have enabled more than 1 TX GPIO) * using the following format (Order is important): * protocol_num,hexcode * e.g. 7,E0E09966 @@ -177,10 +181,13 @@ * * ### via MQTT: * The code listen for commands (via wildcard) on the MQTT topics at the - * `ir_server/ac/cmnd/+` level, such as: + * `ir_server/ac/cmnd/+` level (or ir_server/ac_1/cmnd/+` if multiple TX GPIOs) + * such as: * i.e. protocol, model, power, mode, temp, fanspeed, swingv, swingh, quiet, * turbo, light, beep, econo, sleep, filter, clean, use_celsius - * e.g. ir_server/ac/cmnd/power, ir_server/ac/cmnd/temp, etc. + * e.g. ir_server/ac/cmnd/power, ir_server/ac/cmnd/temp, + * ir_server/ac_0/cmnd/mode, ir_server/ac_2/cmnd/fanspeed, etc. + * It will process them, and if successful and it caused a change, it will * acknowledge this via the relevant state topic for that command. * e.g. If the aircon/climate changes from power off to power on, it will @@ -262,14 +269,30 @@ * temp_step: 1 * retain: false * + * #### Home Assistant MQTT Discovery + * There is an option for this: 'Send MQTT Discovery' under the 'Admin' menu. + * It will produce a single MQTT Cliamte Discovery message for Home Assistant + * provided you have everything configured correctly here and in HA. + * This message has MQTT RETAIN set on it, so it only ever needs to be sent + * once or if the config details change etc. + * + * If you no longer want it, manually remove it from your MQTT broker. + * e.g. + * `mosquitto_pub -t homeassistant/climate/ir_server/config -n -r -d` + * + * NOTE: If you have multiple TX GPIOs configured, it *ONLY* works for the + * first TX GPIO climate. You will need to manually configure the others. + * * ### via HTTP: * Use the "http:///aircon/set" URL and pass on * the arguments as needed to control your device. See the `KEY_*` #defines * in the code for all the parameters. * i.e. protocol, model, power, mode, temp, fanspeed, swingv, swingh, quiet, - * turbo, light, beep, econo, sleep, filter, clean, use_celsius + * turbo, light, beep, econo, sleep, filter, clean, use_celsius, channel * Example: - * http:///aircon/set?protocol=PANASONIC_AC&model=LKE&power=on&mode=auto&fanspeed=min&temp=23 + * http:///aircon/set?channel=0&protocol=PANASONIC_AC&model=LKE&power=on&mode=auto&fanspeed=min&temp=23 + * + * NOTE: If you don't set the channel, the first GPIO (Channel 0) is used. * * ## Debugging & Logging * If DEBUG is turned on, there is additional information printed on the Serial @@ -388,9 +411,9 @@ uint32_t irRecvCounter = 0; #endif // IR_RX // Climate stuff -stdAc::state_t climate; -stdAc::state_t climate_prev; -IRac *commonAc = NULL; +IRac *climate[kNrOfIrTxGpios]; +String channel_re = "("; // 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. uint32_t irClimateCounter = 0; // How many have we sent? @@ -423,7 +446,6 @@ String MqttLog; // Topic we send log messages to. String MqttLwt; // Topic for the Last Will & Testament. String MqttClimate; // Sub-topic for the climate topics. String MqttClimateCmnd; // Sub-topic for the climate command topics. -String MqttClimateStat; // Sub-topic for the climate stat topics. #if MQTT_DISCOVERY_ENABLE String MqttDiscovery; #endif // MQTT_DISCOVERY_ENABLE @@ -434,8 +456,10 @@ String MqttClientId; bool lockMqttBroadcast = true; TimerMs lastBroadcast = TimerMs(); // When we last sent a broadcast. bool hasBroadcastBeenSent = false; +#if MQTT_DISCOVERY_ENABLE TimerMs lastDiscovery = TimerMs(); // When we last sent a Discovery. bool hasDiscoveryBeenSent = false; +#endif // MQTT_DISCOVERY_ENABLE TimerMs statListenTime = TimerMs(); // How long we've been listening for. #endif // MQTT_ENABLE @@ -455,7 +479,7 @@ bool isSerialGpioUsedByIr(void) { return true; // Serial port is in use by IR capture. Abort. } #endif // IR_RX - for (uint8_t i = 0; i < kNrOfIrTxGpios; i++) + for (uint16_t i = 0; i < kNrOfIrTxGpios; i++) switch (txGpioTable[i]) { #if defined(ESP32) case kSerialRxGpio: @@ -467,6 +491,8 @@ bool isSerialGpioUsedByIr(void) { } // Debug messages get sent to the serial port. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" void debug(const char *str) { #if DEBUG if (isSerialGpioUsedByIr()) return; // Abort. @@ -474,6 +500,7 @@ void debug(const char *str) { Serial.printf("%07u.%03u: %s\n", now / 1000, now % 1000, str); #endif // DEBUG } +#pragma GCC diagnostic pop // callback notifying us of the need to save the wifi config void saveWifiConfigCallback(void) { @@ -502,8 +529,7 @@ bool mountSpiffs(void) { bool saveConfig(void) { debug("Saving the config."); bool success = false; - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); + DynamicJsonDocument json(kJsonConfigMaxSize); #if MQTT_ENABLE json[kMqttServerKey] = MqttServer; json[kMqttPortKey] = MqttPort; @@ -528,7 +554,7 @@ bool saveConfig(void) { debug("Failed to open config file for writing."); } else { debug("Writing out the config file."); - json.printTo(configFile); + serializeJson(json, configFile); configFile.close(); debug("Finished writing config file."); success = true; @@ -553,9 +579,8 @@ bool loadConfigFile(void) { std::unique_ptr buf(new char[size]); configFile.readBytes(buf.get(), size); - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.parseObject(buf.get()); - if (json.success()) { + DynamicJsonDocument json(kJsonConfigMaxSize); + if (!deserializeJson(json, buf.get(), kJsonConfigMaxSize)) { debug("Json config file parsed ok."); #if MQTT_ENABLE strncpy(MqttServer, json[kMqttServerKey] | "", kHostnameLength); @@ -621,7 +646,7 @@ String gpioToString(const int16_t gpio) { } int8_t getDefaultTxGpio(void) { - for (int8_t i = 0; i < kNrOfIrTxGpios; i++) + for (int16_t i = 0; i < kNrOfIrTxGpios; i++) if (txGpioTable[i] != kGpioUnused) return txGpioTable[i]; return kGpioUnused; } @@ -630,7 +655,7 @@ int8_t getDefaultTxGpio(void) { String listOfTxGpios(void) { bool found = false; String result = ""; - for (uint8_t i = 0; i < kNrOfIrTxGpios; i++) { + for (uint16_t i = 0; i < kNrOfIrTxGpios; i++) { if (i) result += ", "; result += gpioToString(txGpioTable[i]); if (!found && txGpioTable[i] == getDefaultTxGpio()) { @@ -902,6 +927,17 @@ String htmlSelectModel(const String name, const int16_t def) { return html; } +String htmlSelectUint(const String name, const uint16_t max, + const uint16_t def) { + String html = ""); + return html; +} + String htmlSelectGpio(const String name, const int16_t def, const int8_t list[], const int16_t length) { String html = ": " - "" - "Fan Speed" + - htmlSelectFanspeed(KEY_FANSPEED, climate.fanspeed) + "" - "Swing (V)" + - htmlSelectSwingv(KEY_SWINGV, climate.swingv) + "" - "Swing (H)" + - htmlSelectSwingh(KEY_SWINGH, climate.swingh) + "" - "Quiet" + htmlSelectBool(KEY_QUIET, climate.quiet) + - "" - "Turbo" + htmlSelectBool(KEY_TURBO, climate.turbo) + - "" - "Econo" + htmlSelectBool(KEY_ECONO, climate.econo) + - "" - "Light" + htmlSelectBool(KEY_LIGHT, climate.light) + - "" - "Filter" + htmlSelectBool(KEY_FILTER, climate.filter) + - "" - "Clean" + htmlSelectBool(KEY_CLEAN, climate.clean) + - "" - "Beep" + htmlSelectBool(KEY_BEEP, climate.beep) + - "" - "Force resend" + htmlSelectBool(KEY_RESEND, false) + - "" - "" - "" - ""; + if (kNrOfIrTxGpios > 1) { + html += "
" + "" + "" + "
Climate #" + + htmlSelectUint(KEY_CHANNEL, kNrOfIrTxGpios, chan) + + "" + "
" + "
" + "
"; + } + if (climate[chan] != NULL) { + html += "

Current Settings

" + "
" + "" + + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
Protocol" + + htmlSelectClimateProtocol(KEY_PROTOCOL, + climate[chan]->next.protocol) + + "
Model" + + htmlSelectModel(KEY_MODEL, climate[chan]->next.model) + + "
Power" + + htmlSelectBool(KEY_POWER, climate[chan]->next.power) + + "
Mode" + + htmlSelectMode(KEY_MODE, climate[chan]->next.mode) + + "
Temp" + "" + "
Fan Speed" + + htmlSelectFanspeed(KEY_FANSPEED, climate[chan]->next.fanspeed) + + "
Swing (V)" + + htmlSelectSwingv(KEY_SWINGV, climate[chan]->next.swingv) + + "
Swing (H)" + + htmlSelectSwingh(KEY_SWINGH, climate[chan]->next.swingh) + + "
Quiet" + + htmlSelectBool(KEY_QUIET, climate[chan]->next.quiet) + + "
Turbo" + + htmlSelectBool(KEY_TURBO, climate[chan]->next.turbo) + + "
Econo" + + htmlSelectBool(KEY_ECONO, climate[chan]->next.econo) + + "
Light" + + htmlSelectBool(KEY_LIGHT, climate[chan]->next.light) + + "
Filter" + + htmlSelectBool(KEY_FILTER, climate[chan]->next.filter) + + "
Clean" + + htmlSelectBool(KEY_CLEAN, climate[chan]->next.clean) + + "
Beep" + + htmlSelectBool(KEY_BEEP, climate[chan]->next.beep) + + "
Force resend" + + htmlSelectBool(KEY_RESEND, false) + + "
" + "" + "
"; + } html += htmlEnd(); server.send(200, "text/html", html); } @@ -1043,26 +1113,40 @@ void handleAirConSet(void) { return server.requestAuthentication(); } #endif - stdAc::state_t result = climate; debug("New common a/c received via HTTP"); - bool force_resend = false; - for (uint16_t i = 0; i < server.args(); i++) { - if (server.argName(i).equals(KEY_RESEND)) - force_resend = IRac::strToBool(server.arg(i).c_str()); - else - result = updateClimate(result, server.argName(i), "", server.arg(i)); + uint16_t channel = chan; + if (kNrOfIrTxGpios > 1) { + // Scan for the channel number if needed. + for (uint16_t i = 0; i < server.args(); i++) { + if (server.argName(i).equals(KEY_CHANNEL)) { + channel = server.arg(i).toInt(); + } + } } + // Change the HTML channel for the climate if it is within the correct range. + if (channel < kNrOfIrTxGpios) chan = channel; -#if MQTT_ENABLE - sendClimate(climate, result, MqttClimateStat, true, false, force_resend); -#else // MQTT_ENABLE - sendClimate(climate, result, "", false, false, force_resend); -#endif // MQTT_ENABLE - lastClimateSource = F("HTTP"); - // Update the old climate state with the new one. - climate = result; - // Redirect back to the aircon page. + IRac *ac_ptr = climate[chan]; String html = htmlHeader(F("Aircon updated!")); + if (ac_ptr != NULL) { + bool force_resend = false; + for (uint16_t i = 0; i < server.args(); i++) { + if (server.argName(i).equals(KEY_RESEND)) + force_resend = IRac::strToBool(server.arg(i).c_str()); + else + updateClimate(&(ac_ptr->next), server.argName(i), "", server.arg(i)); + } +#if MQTT_ENABLE + sendClimate(genStatTopic(chan), true, false, force_resend, true, ac_ptr); +#else // MQTT_ENABLE + sendClimate("", false, false, force_resend, true, ac_ptr); +#endif // MQTT_ENABLE + lastClimateSource = F("HTTP"); + } else { // ac_ptr == NULL + debug("No climate setup for the given channel. Aborting!"); + html = htmlHeader(F("Aircon update FAILED!")); + } + // Redirect back to the aircon page. html += addJsReloadUrl(kUrlAircon, kQuickDisplayTime, false); html += htmlEnd(); server.send(200, "text/html", html); @@ -1088,6 +1172,12 @@ void handleAdmin(void) { kUrlSendDiscovery, F("Send MQTT Discovery"), F("Send a Climate MQTT discovery message to Home Assistant.

")); #endif // MQTT_DISCOVERY_ENABLE +#if MQTT_CLEAR_ENABLE + html += htmlButton( + kUrlClearMqtt, F("Clear data saved to MQTT"), + F("Clear all saved climate & discovery messages for this device & " + "reboot.

")); +#endif // MQTT_CLEAR_ENABLE #endif // MQTT_ENABLE html += htmlButton( kUrlReboot, F("Reboot"), @@ -1168,7 +1258,7 @@ void handleInfo(void) { " (" + timeSince(lastIrReceivedTime) + ")
" #endif // IR_RX "Duplicate Wifi networks: " + - String(HIDE_DUPLIATE_NETWORKS ? "Hide" : "Show") + "
" + String(HIDE_DUPLICATE_NETWORKS ? "Hide" : "Show") + "
" "Min Wifi signal required: " #ifdef MIN_SIGNAL_STRENGTH + String(static_cast(MIN_SIGNAL_STRENGTH)) + @@ -1230,14 +1320,18 @@ void handleInfo(void) { "Last state broadcast: " + (hasBroadcastBeenSent ? timeElapsed(lastBroadcast.elapsed()) : String("Never")) + "
" +#if MQTT_DISCOVERY_ENABLE "Last discovery sent: " + (lockMqttBroadcast ? String("Locked") : (hasDiscoveryBeenSent ? timeElapsed(lastDiscovery.elapsed()) : String("Never"))) + "
" - "Command topics: " + MqttClimateCmnd + kClimateTopics + - "State topics: " + MqttClimateStat + kClimateTopics + +#endif // MQTT_DISCOVERY_ENABLE + "Command topics: " + MqttClimate + channel_re + '/' + MQTT_CLIMATE_CMND + + '/' + kClimateTopics + + "State topics: " + MqttClimate + channel_re + '/' + MQTT_CLIMATE_STAT + + '/' + kClimateTopics + #endif // MQTT_ENABLE "

" // Page footer @@ -1261,6 +1355,59 @@ void doRestart(const char* str, const bool serial_only) { delay(5000); // Enough time to ensure we don't return. } +#if MQTT_ENABLE && MQTT_CLEAR_ENABLE +// Clear any MQTT message that we might have set retain on. +bool clearMqttSavedStates(const String topic_base) { + String channelStr = ""; + bool success = true; + // Clear the Last Will & Testament. + success &= mqtt_client.publish(MqttLwt.c_str(), "", true); +#if MQTT_DISCOVERY_ENABLE + // Clear the HA climate discovery message. + success &= mqtt_client.publish(MqttDiscovery.c_str(), "", true); +#endif // MQTT_DISCOVERY_ENABLE + for (size_t channel = 0; + channel <= kNrOfIrTxGpios; + channelStr = '_' + String(channel++)) { + 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]); + success &= mqtt_client.publish(topic.c_str(), "", true); + } + channelStr = '_' + String(channel); + } + String logmesg = "Removing all possible settings saved in MQTT for '" + + topic_base + "' "; + logmesg += success ? F("succeeded") : F("failed"); + mqttLog(logmesg.c_str()); + return success; +} + +// Clear settings from MQTT web page +void handleClearMqtt(void) { +#if HTML_PASSWORD_ENABLE + if (!server.authenticate(HttpUsername, HttpPassword)) { + debug(("Basic HTTP authentication failure for " + + String(kUrlClearMqtt)).c_str()); + return server.requestAuthentication(); + } +#endif + server.send(200, "text/html", + htmlHeader(F("Clearing saved info from MQTT"), + F("Removing all saved settings for this device from " + "MQTT.")) + + "

Device restarting. Try connecting in a few seconds.

" + + addJsReloadUrl(kUrlRoot, 10, true) + + htmlEnd()); + // Do the clearing. + mqttLog("Clearing all saved settings from MQTT."); + clearMqttSavedStates(MqttClimate); + doRestart("Rebooting..."); +} +#endif // MQTT_ENABLE && MQTT_CLEAR_ENABLE + // Reset web page void handleReset(void) { #if HTML_PASSWORD_ENABLE @@ -1278,6 +1425,10 @@ void handleReset(void) { htmlEnd()); // Do the reset. #if MQTT_ENABLE +#if MQTT_CLEAR_ENABLE + mqttLog("Clearing all saved climate settings from MQTT."); + clearMqttSavedStates(MqttClimate); +#endif // MQTT_CLEAR_ENABLE mqttLog("Wiping all saved config settings."); #endif // MQTT_ENABLE if (mountSpiffs()) { @@ -1648,6 +1799,7 @@ void handleIr(void) { decode_type_t ir_type = decode_type_t::NEC; // Default to NEC codes. uint16_t nbits = 0; uint16_t repeat = 0; + int16_t channel = -1; for (uint16_t i = 0; i < server.args(); i++) { if (server.argName(i).equals(KEY_TYPE) || @@ -1660,11 +1812,16 @@ void handleIr(void) { nbits = server.arg(i).toInt(); } else if (server.argName(i).equals(KEY_REPEAT)) { repeat = server.arg(i).toInt(); + } else if (server.argName(i).equals(KEY_CHANNEL)) { + channel = server.arg(i).toInt(); } } debug("New code received via HTTP"); - lastSendSucceeded = sendIRCode(getDefaultIrSendPtr(), ir_type, data, - data_str.c_str(), nbits, repeat); + IRsend *tx_ptr = getDefaultIrSendPtr(); + if (channel >= 0 && channel < kNrOfIrTxGpios && IrSendTable[channel] != NULL) + tx_ptr = IrSendTable[channel]; + lastSendSucceeded = sendIRCode(tx_ptr, ir_type, data, data_str.c_str(), nbits, + repeat); String html = htmlHeader(F("IR command sent!")); html += addJsReloadUrl(kUrlRoot, kQuickDisplayTime, true); html += htmlEnd(); @@ -1831,7 +1988,7 @@ void setup_wifi(void) { #if MIN_SIGNAL_STRENGTH wifiManager.setMinimumSignalQuality(MIN_SIGNAL_STRENGTH); #endif // MIN_SIGNAL_STRENGTH - wifiManager.setRemoveDuplicateAPs(HIDE_DUPLIATE_NETWORKS); + wifiManager.setRemoveDuplicateAPs(HIDE_DUPLICATE_NETWORKS); if (!wifiManager.autoConnect()) // Reboot. A.k.a. "Have you tried turning it Off and On again?" @@ -1873,7 +2030,6 @@ void init_vars(void) { // Sub-topic for the climate command topics. MqttClimateCmnd = MqttClimate + '/' + MQTT_CLIMATE_CMND + '/'; // Sub-topic for the climate stat topics. - MqttClimateStat = MqttClimate + '/' + MQTT_CLIMATE_STAT + '/'; #if MQTT_DISCOVERY_ENABLE MqttDiscovery = "homeassistant/climate/" + String(Hostname) + "/config"; #endif // MQTT_DISCOVERY_ENABLE @@ -1884,28 +2040,6 @@ void init_vars(void) { } void setup(void) { - // Set the default climate settings. - climate.protocol = decode_type_t::UNKNOWN; - climate.model = -1; // Unknown. - climate.power = false; - climate.mode = stdAc::opmode_t::kAuto; - climate.celsius = true; - climate.degrees = 25; // 25C - climate.fanspeed = stdAc::fanspeed_t::kAuto; - climate.swingv = stdAc::swingv_t::kAuto; - climate.swingh = stdAc::swingh_t::kAuto; - climate.quiet = false; - climate.turbo = false; - climate.econo = false; - climate.light = false; - climate.filter = false; - climate.clean = false; - climate.beep = false; - climate.sleep = -1; // Off - climate.clock = -1; // Don't set. - climate_prev = climate; - lastClimateSource = F("None"); - #if DEBUG if (!isSerialGpioUsedByIr()) { #if defined(ESP8266) @@ -1928,17 +2062,29 @@ void setup(void) { if (isSerialGpioUsedByIr()) Serial.end(); #endif // DEBUG + channel_re.reserve(kNrOfIrTxGpios * 3); // Initialise all the IR transmitters. for (uint8_t i = 0; i < kNrOfIrTxGpios; i++) { if (txGpioTable[i] == kGpioUnused) { IrSendTable[i] = NULL; + climate[i] = NULL; } else { IrSendTable[i] = new IRsend(txGpioTable[i], kInvertTxOutput); - if (IrSendTable[i] == NULL) break; - IrSendTable[i]->begin(); - offset = IrSendTable[i]->calibrate(); + if (IrSendTable[i] != NULL) { + IrSendTable[i]->begin(); + offset = IrSendTable[i]->calibrate(); + } + climate[i] = new IRac(txGpioTable[i], kInvertTxOutput); + if (climate[i] != NULL && i > 0) channel_re += '_' + String(i) + '|'; } } + lastClimateSource = F("None"); + if (channel_re.length() == 1) { + channel_re = ""; + } else { + channel_re.remove(channel_re.length() - 1, 1); // Remove the last char. + channel_re += F(")?"); + } #if IR_RX if (rx_gpio != kGpioUnused) irrecv = new IRrecv(rx_gpio, kCaptureBufferSize, kCaptureTimeout, true); @@ -1950,8 +2096,6 @@ void setup(void) { irrecv->enableIRIn(IR_RX_PULLUP); // Start the receiver } #endif // IR_RX - commonAc = new IRac(txGpioTable[0], kInvertTxOutput); - // Wait a bit for things to settle. delay(500); @@ -1992,6 +2136,10 @@ void setup(void) { // Parse and update the new gpios. server.on(kUrlGpioSet, handleGpioSetting); #if MQTT_ENABLE +#if MQTT_CLEAR_ENABLE + // Clear settings saved to MQTT as retained messages. + server.on(kUrlClearMqtt, handleClearMqtt); +#endif // MQTT_CLEAR_ENABLE #if MQTT_DISCOVERY_ENABLE // MQTT Discovery url server.on(kUrlSendDiscovery, handleSendMqttDiscovery); @@ -2070,6 +2218,13 @@ void setup(void) { } #if MQTT_ENABLE +String genStatTopic(const uint16_t channel) { + if (channel) // Never use the '*_0' state channel. + return MqttClimate + "_" + String(channel) + '/' + MQTT_CLIMATE_STAT + '/'; + else + return MqttClimate + '/' + MQTT_CLIMATE_STAT + '/'; +} + // MQTT subscribing to topic void subscribing(const String topic_name) { // subscription to topic for receiving data with QoS. @@ -2125,12 +2280,18 @@ bool reconnect(void) { mqttSentCounter++; // Subscribing to topic(s) - subscribing(MqttSend); - for (uint8_t i = 0; i < kNrOfIrTxGpios; i++) { - subscribing(MqttSend + '_' + String(static_cast(i))); + subscribing(MqttSend); // General base topic. + subscribing(MqttClimateCmnd + '+'); // Base climate command topics + // Per channel topics + for (uint16_t i = 0; i < kNrOfIrTxGpios; i++) { + // General + if (IrSendTable[i] != NULL) + subscribing(MqttSend + '_' + String(i)); + // Climate + if (climate[i] != NULL) + subscribing(MqttClimate + '_' + String(i) + '/' + MQTT_CLIMATE_CMND + + '/' + '+'); } - // Climate command topics. - subscribing(MqttClimateCmnd + '+'); } else { debug(("failed, rc=" + String(mqtt_client.state()) + " Try again in a bit.").c_str()); @@ -2176,18 +2337,20 @@ void handleSendMqttDiscovery(void) { #endif // MQTT_DISCOVERY_ENABLE void doBroadcast(TimerMs *timer, const uint32_t interval, - const stdAc::state_t state, const bool retain, + IRac *climate[], const bool retain, const bool force) { if (force || (!lockMqttBroadcast && timer->elapsed() > interval)) { debug("Sending MQTT stat update broadcast."); - sendClimate(state, state, MqttClimateStat, - retain, true, false); + for (uint16_t i = 0; i < kNrOfIrTxGpios; i++) { + String stat_topic = genStatTopic(i); + sendClimate(stat_topic, retain, true, false, true, climate[i]); #if REPORT_VCC - sendString(MqttClimateStat + KEY_VCC, vccToString(), false); + sendString(stat_topic + KEY_VCC, vccToString(), false); #endif // REPORT_VCC #if MQTT_CLIMATE_JSON - sendJsonState(state, MqttClimateStat + KEY_JSON); + sendJsonState(climate[i]->next, stat_topic + KEY_JSON); #endif // MQTT_CLIMATE_JSON + } timer->reset(); // It's been sent, so reset the timer. hasBroadcastBeenSent = true; } @@ -2209,38 +2372,46 @@ void receivingMQTT(String const topic_name, String const callback_str) { lastMqttCmdTime = millis(); mqttRecvCounter++; + // Check if a specific channel was requested by looking for a "*_[0-9]" suffix + // 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)))) { + channel = i; + break; + } + } + debug(("Channel = " + String(channel)).c_str()); + // Is it a climate topic? if (topic_name.startsWith(MqttClimate)) { - if (topic_name.startsWith(MqttClimateCmnd)) { + String alt_cmnd_topic = MqttClimate + "_" + String(channel) + '/' + + MQTT_CLIMATE_CMND + '/'; + // Also accept climate commands on the '*_0' channel. + String cmnd_topic = topic_name.startsWith(alt_cmnd_topic) ? alt_cmnd_topic + : MqttClimateCmnd; + String stat_topic = genStatTopic(channel); + if (topic_name.startsWith(cmnd_topic)) { debug("It's a climate command topic"); - stdAc::state_t updated = updateClimate( - climate, topic_name, MqttClimateCmnd, callback_str); + updateClimate(&(climate[channel]->next), topic_name, cmnd_topic, + callback_str); // Handle the special command for forcing a resend of the state via IR. bool force_resend = false; - if (topic_name.equals(MqttClimateCmnd + KEY_RESEND) && + if (topic_name.equals(cmnd_topic + KEY_RESEND) && callback_str.equalsIgnoreCase(KEY_RESEND)) { force_resend = true; mqttLog("Climate resend requested."); } - if (sendClimate(climate, updated, MqttClimateStat, - true, false, force_resend) && !force_resend) + if (sendClimate(stat_topic, true, false, force_resend, true, + climate[channel]) && !force_resend) lastClimateSource = F("MQTT"); - climate = updated; - } else if (topic_name.startsWith(MqttClimateStat)) { + } else if (topic_name.startsWith(stat_topic)) { debug("It's a climate state topic. Update internal state and DON'T send"); - climate = updateClimate( - climate, topic_name, MqttClimateStat, callback_str); + updateClimate(&(climate[channel]->next), topic_name, stat_topic, + callback_str); } return; // We are done for now. } - // Check if a specific channel was requested by looking for a "*_[0-9]" suffix - for (uint8_t i = 0; i < kNrOfIrTxGpios; i++) { - debug(("Checking if " + topic_name + " ends with _" + String(i)).c_str()); - if (topic_name.endsWith("_" + String(i))) { - channel = i; - debug("It does!"); - break; - } - } debug(("Using transmit channel " + String(static_cast(channel)) + " / GPIO " + String(static_cast(txGpioTable[channel]))).c_str()); @@ -2356,7 +2527,7 @@ void sendMQTTDiscovery(const char *topic) { "\"swing_mode_stat_t\":\"~/" MQTT_CLIMATE_STAT "/" KEY_SWINGV "\"," "\"swing_modes\":[" "\"off\",\"auto\",\"highest\",\"high\",\"middle\",\"low\",\"lowest\"]" - "}").c_str())) { + "}").c_str(), true)) { mqttLog("MQTT climate discovery successful sent."); hasDiscoveryBeenSent = true; lastDiscovery.reset(); @@ -2402,8 +2573,8 @@ void loop(void) { // Attempt to fetch back any Climate state stored in MQTT retained // messages on the MQTT broker. mqttLog("Started listening for previous state."); - climate_prev = climate; // Make a copy so we can compare afterwards. - subscribing(MqttClimateStat + '+'); + for (uint16_t i = 0; i < kNrOfIrTxGpios; i++) + subscribing(genStatTopic(i) + '+'); statListenTime.reset(); } } @@ -2413,14 +2584,18 @@ void loop(void) { lastConnectedTime = now; mqtt_client.loop(); if (lockMqttBroadcast && statListenTime.elapsed() > kStatListenPeriodMs) { - unsubscribing(MqttClimateStat + '+'); - mqttLog("Finished listening for previous state."); - if (IRac::cmpStates(climate, climate_prev)) { // Something changed. - mqttLog("The state was recovered from MQTT broker. Updating."); - sendClimate(climate_prev, climate, MqttClimateStat, - true, false, false, MQTT_CLIMATE_IR_SEND_ON_RESTART); - lastClimateSource = F("MQTT (via retain)"); + for (uint16_t i = 0; i < kNrOfIrTxGpios; i++) { + String stat_topic = genStatTopic(i); + unsubscribing(stat_topic + '+'); + // Did something change? + if (climate[i] != NULL && climate[i]->hasStateChanged()) { + 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("Finished listening for previous state."); lockMqttBroadcast = false; // Release the lock so we can broadcast again. } // Periodically send all of the climate state via MQTT. @@ -2477,17 +2652,16 @@ uint64_t getUInt64fromHex(char const *str) { uint64_t result = 0; uint16_t offset = 0; // Skip any leading '0x' or '0X' prefix. - if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) - offset = 2; + if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) offset = 2; for (; isxdigit((unsigned char)str[offset]); offset++) { char c = str[offset]; result *= 16; - if (isdigit(c)) /* '0' .. '9' */ - result += c - '0'; - else if (isupper(c)) /* 'A' .. 'F' */ - result += c - 'A' + 10; - else /* 'a' .. 'f'*/ - result += c - 'a' + 10; + if (isdigit(c)) + result += c - '0'; // '0' .. '9' + else if (isupper(c)) + result += c - 'A' + 10; // 'A' .. 'F' + else + result += c - 'a' + 10; // 'a' .. 'f' } return result; } @@ -2641,8 +2815,7 @@ bool sendFloat(const String topic, const float_t temp, const bool retain) { #if MQTT_CLIMATE_JSON void sendJsonState(const stdAc::state_t state, const String topic, const bool retain, const bool ha_mode) { - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); + DynamicJsonDocument json(kJsonAcStateMaxSize); json[KEY_PROTOCOL] = typeToString(state.protocol); json[KEY_MODEL] = state.model; json[KEY_POWER] = IRac::boolToString(state.power); @@ -2668,108 +2841,117 @@ void sendJsonState(const stdAc::state_t state, const String topic, String payload = ""; payload.reserve(200); - json.printTo(payload); + serializeJson(json, payload); sendString(topic, payload, retain); } -stdAc::state_t jsonToState(const stdAc::state_t current, const String str) { - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.parseObject(str); - if (!json.success()) { +bool validJsonStr(DynamicJsonDocument doc, const char* key) { + return doc.containsKey(key) && doc[key].is(); +} + +bool validJsonInt(DynamicJsonDocument doc, const char* key) { + return doc.containsKey(key) && doc[key].is(); +} + +stdAc::state_t jsonToState(const stdAc::state_t current, const char *str) { + DynamicJsonDocument json(kJsonAcStateMaxSize); + if (deserializeJson(json, str, kJsonAcStateMaxSize)) { debug("json MQTT message did not parse. Skipping!"); return current; } stdAc::state_t result = current; - if (json.containsKey(KEY_PROTOCOL)) + if (validJsonStr(json, KEY_PROTOCOL)) result.protocol = strToDecodeType(json[KEY_PROTOCOL]); - if (json.containsKey(KEY_MODEL)) - result.model = IRac::strToModel(json[KEY_MODEL]); - if (json.containsKey(KEY_MODE)) + else if (validJsonInt(json, KEY_PROTOCOL)) + result.protocol = (decode_type_t)json[KEY_PROTOCOL].as(); + if (validJsonStr(json, KEY_MODEL)) + result.model = IRac::strToModel(json[KEY_MODEL].as()); + else if (validJsonInt(json, KEY_MODEL)) + result.model = json[KEY_MODEL]; + if (validJsonStr(json, KEY_MODE)) result.mode = IRac::strToOpmode(json[KEY_MODE]); - if (json.containsKey(KEY_FANSPEED)) + if (validJsonStr(json, KEY_FANSPEED)) result.fanspeed = IRac::strToFanspeed(json[KEY_FANSPEED]); - if (json.containsKey(KEY_SWINGV)) + if (validJsonStr(json, KEY_SWINGV)) result.swingv = IRac::strToSwingV(json[KEY_SWINGV]); - if (json.containsKey(KEY_SWINGH)) + if (validJsonStr(json, KEY_SWINGH)) result.swingh = IRac::strToSwingH(json[KEY_SWINGH]); if (json.containsKey(KEY_TEMP)) result.degrees = json[KEY_TEMP]; - if (json.containsKey(KEY_SLEEP)) + if (validJsonInt(json, KEY_SLEEP)) result.sleep = json[KEY_SLEEP]; - if (json.containsKey(KEY_POWER)) + if (validJsonStr(json, KEY_POWER)) result.power = IRac::strToBool(json[KEY_POWER]); - if (json.containsKey(KEY_QUIET)) + if (validJsonStr(json, KEY_QUIET)) result.quiet = IRac::strToBool(json[KEY_QUIET]); - if (json.containsKey(KEY_TURBO)) + if (validJsonStr(json, KEY_TURBO)) result.turbo = IRac::strToBool(json[KEY_TURBO]); - if (json.containsKey(KEY_ECONO)) + if (validJsonStr(json, KEY_ECONO)) result.econo = IRac::strToBool(json[KEY_ECONO]); - if (json.containsKey(KEY_LIGHT)) + if (validJsonStr(json, KEY_LIGHT)) result.light = IRac::strToBool(json[KEY_LIGHT]); - if (json.containsKey(KEY_CLEAN)) + if (validJsonStr(json, KEY_CLEAN)) result.clean = IRac::strToBool(json[KEY_CLEAN]); - if (json.containsKey(KEY_FILTER)) + if (validJsonStr(json, KEY_FILTER)) result.filter = IRac::strToBool(json[KEY_FILTER]); - if (json.containsKey(KEY_BEEP)) + if (validJsonStr(json, KEY_BEEP)) result.beep = IRac::strToBool(json[KEY_BEEP]); - if (json.containsKey(KEY_CELSIUS)) + if (validJsonStr(json, KEY_CELSIUS)) result.celsius = IRac::strToBool(json[KEY_CELSIUS]); return result; } #endif // MQTT_CLIMATE_JSON -stdAc::state_t updateClimate(stdAc::state_t current, const String str, - const String prefix, const String payload) { - stdAc::state_t result = current; +void updateClimate(stdAc::state_t *state, const String str, + const String prefix, const String payload) { #if MQTT_CLIMATE_JSON if (str.equals(prefix + KEY_JSON)) - result = jsonToState(result, payload.c_str()); + *state = jsonToState(*state, payload.c_str()); else #endif // MQTT_CLIMATE_JSON if (str.equals(prefix + KEY_PROTOCOL)) - result.protocol = strToDecodeType(payload.c_str()); + state->protocol = strToDecodeType(payload.c_str()); else if (str.equals(prefix + KEY_MODEL)) - result.model = IRac::strToModel(payload.c_str()); + state->model = IRac::strToModel(payload.c_str()); else if (str.equals(prefix + KEY_POWER)) - result.power = IRac::strToBool(payload.c_str()); + state->power = IRac::strToBool(payload.c_str()); else if (str.equals(prefix + KEY_MODE)) - result.mode = IRac::strToOpmode(payload.c_str()); + state->mode = IRac::strToOpmode(payload.c_str()); else if (str.equals(prefix + KEY_TEMP)) - result.degrees = payload.toFloat(); + state->degrees = payload.toFloat(); else if (str.equals(prefix + KEY_FANSPEED)) - result.fanspeed = IRac::strToFanspeed(payload.c_str()); + state->fanspeed = IRac::strToFanspeed(payload.c_str()); else if (str.equals(prefix + KEY_SWINGV)) - result.swingv = IRac::strToSwingV(payload.c_str()); + state->swingv = IRac::strToSwingV(payload.c_str()); else if (str.equals(prefix + KEY_SWINGH)) - result.swingh = IRac::strToSwingH(payload.c_str()); + state->swingh = IRac::strToSwingH(payload.c_str()); else if (str.equals(prefix + KEY_QUIET)) - result.quiet = IRac::strToBool(payload.c_str()); + state->quiet = IRac::strToBool(payload.c_str()); else if (str.equals(prefix + KEY_TURBO)) - result.turbo = IRac::strToBool(payload.c_str()); + state->turbo = IRac::strToBool(payload.c_str()); else if (str.equals(prefix + KEY_ECONO)) - result.econo = IRac::strToBool(payload.c_str()); + state->econo = IRac::strToBool(payload.c_str()); else if (str.equals(prefix + KEY_LIGHT)) - result.light = IRac::strToBool(payload.c_str()); + state->light = IRac::strToBool(payload.c_str()); else if (str.equals(prefix + KEY_BEEP)) - result.beep = IRac::strToBool(payload.c_str()); + state->beep = IRac::strToBool(payload.c_str()); else if (str.equals(prefix + KEY_FILTER)) - result.filter = IRac::strToBool(payload.c_str()); + state->filter = IRac::strToBool(payload.c_str()); else if (str.equals(prefix + KEY_CLEAN)) - result.clean = IRac::strToBool(payload.c_str()); + state->clean = IRac::strToBool(payload.c_str()); else if (str.equals(prefix + KEY_CELSIUS)) - result.celsius = IRac::strToBool(payload.c_str()); + state->celsius = IRac::strToBool(payload.c_str()); else if (str.equals(prefix + KEY_SLEEP)) - result.sleep = payload.toInt(); - return result; + state->sleep = payload.toInt(); } -bool sendClimate(const stdAc::state_t prev, const stdAc::state_t next, - const String topic_prefix, const bool retain, +bool sendClimate(const String topic_prefix, const bool retain, const bool forceMQTT, const bool forceIR, - const bool enableIR) { + const bool enableIR, IRac *ac) { bool diff = false; bool success = true; - + const stdAc::state_t next = ac->getState(); + const stdAc::state_t prev = ac->getStatePrev(); if (prev.protocol != next.protocol || forceMQTT) { diff = true; success &= sendString(topic_prefix + KEY_PROTOCOL, @@ -2779,6 +2961,8 @@ bool sendClimate(const stdAc::state_t prev, const stdAc::state_t next, diff = true; success &= sendInt(topic_prefix + KEY_MODEL, next.model, retain); } +#if MQTT_CLIMATE_HA_MODE + // Home Assistant want's these two bound together. if (prev.power != next.power || prev.mode != next.mode || forceMQTT) { diff = true; success &= sendBool(topic_prefix + KEY_POWER, next.power, retain); @@ -2787,6 +2971,18 @@ bool sendClimate(const stdAc::state_t prev, const stdAc::state_t next, : F("off")), retain); } +#else // MQTT_CLIMATE_HA_MODE + // In non-Home Assistant mode, power and mode are not bound together. + if (prev.power != next.power || forceMQTT) { + diff = true; + success &= sendBool(topic_prefix + KEY_POWER, next.power, retain); + } + if (prev.mode != next.mode || forceMQTT) { + diff = true; + success &= sendString(topic_prefix + KEY_MODE, + IRac::opmodeToString(next.mode), retain); + } +#endif // MQTT_CLIMATE_HA_MODE if (prev.degrees != next.degrees || forceMQTT) { diff = true; success &= sendFloat(topic_prefix + KEY_TEMP, next.degrees, retain); @@ -2845,19 +3041,24 @@ bool sendClimate(const stdAc::state_t prev, const stdAc::state_t next, if (diff && !forceMQTT) { debug("Difference in common A/C state detected."); #if MQTT_CLIMATE_JSON - sendJsonState(next, MqttClimateStat + KEY_JSON); + sendJsonState(next, topic_prefix + KEY_JSON); #endif // MQTT_CLIMATE_JSON } else { debug("NO difference in common A/C state detected."); } // Only send an IR message if we need to. if (enableIR && ((diff && !forceMQTT) || forceIR)) { + sendReqCounter++; + if (ac == NULL) { // No climate object is available. + debug("Can't send climate state as common A/C object doesn't exist!"); + return false; + } debug("Sending common A/C state via IR."); #if IR_RX && DISABLE_CAPTURE_WHILE_TRANSMITTING // Turn IR capture off if we need to. if (irrecv != NULL) irrecv->disableIRIn(); // Stop the IR receiver #endif // IR_RX && DISABLE_CAPTURE_WHILE_TRANSMITTING - lastClimateSucceeded = commonAc->sendAc(next, &prev); + lastClimateSucceeded = ac->sendAc(); #if IR_RX && DISABLE_CAPTURE_WHILE_TRANSMITTING // Turn IR capture back on if we need to. if (irrecv != NULL) irrecv->enableIRIn(); // Restart the receiver @@ -2866,7 +3067,6 @@ bool sendClimate(const stdAc::state_t prev, const stdAc::state_t next, success &= lastClimateSucceeded; lastClimateIr.reset(); irClimateCounter++; - sendReqCounter++; } return success; } @@ -2883,35 +3083,39 @@ bool decodeCommonAc(const decode_results *decode) { debug("Inbound IR messages isn't a supported common A/C protocol"); return false; } - stdAc::state_t state = climate; + if (climate[0] == NULL) { + debug("No common A/C object allocated for channel 0. Skipping."); + return false; + } + stdAc::state_t state = climate[0]->next; debug("Converting inbound IR A/C message to common A/C"); - if (!IRAcUtils::decodeToState(decode, &state, &climate)) { + if (!IRAcUtils::decodeToState(decode, &state, &(climate[0]->next))) { debug("Failed to convert to common A/C."); // This shouldn't happen! return false; } #if IGNORE_DECODED_AC_PROTOCOL - if (climate.protocol != decode_type_t::UNKNOWN) { + if (climate[0]->next.protocol != decode_type_t::UNKNOWN) { // Use the previous protcol/model if set. - state.protocol = climate.protocol; - state.model = climate.model; + state.protocol = climate[0]->next.protocol; + state.model = climate[0]->next.model; } #endif // IGNORE_DECODED_AC_PROTOCOL // Continue to use the previously prefered temperature units. // i.e. Keep using Celsius or Fahrenheit. -if (climate.celsius != state.celsius) { +if (climate[0]->next.celsius != state.celsius) { // We've got a mismatch, so we need to convert. - state.degrees = climate.celsius ? fahrenheitToCelsius(state.degrees) - : celsiusToFahrenheit(state.degrees); - state.celsius = climate.celsius; + state.degrees = climate[0]->next.celsius ? fahrenheitToCelsius(state.degrees) + : celsiusToFahrenheit(state.degrees); + state.celsius = climate[0]->next.celsius; } +climate[0]->next = state; // Copy over the new climate state. #if MQTT_ENABLE - sendClimate(climate, state, MqttClimateStat, true, false, - REPLAY_DECODED_AC_MESSAGE, REPLAY_DECODED_AC_MESSAGE); + sendClimate(genStatTopic(0), true, false, REPLAY_DECODED_AC_MESSAGE, + REPLAY_DECODED_AC_MESSAGE, climate[0]); #else // MQTT_ENABLE - sendClimate(climate, state, "", false, false, REPLAY_DECODED_AC_MESSAGE, - REPLAY_DECODED_AC_MESSAGE); + sendClimate("", false, false, REPLAY_DECODED_AC_MESSAGE, + REPLAY_DECODED_AC_MESSAGE, climate[0]); #endif // MQTT_ENABLE - climate = state; // Copy over the new climate state. return true; } #endif // USE_DECODED_AC_SETTINGS && IR_RX diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRMQTTServer/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/IRMQTTServer/platformio.ini old mode 100755 new mode 100644 similarity index 82% rename from lib/IRremoteESP8266-2.6.5/examples/IRMQTTServer/platformio.ini rename to lib/IRremoteESP8266-2.7.0/examples/IRMQTTServer/platformio.ini index 2d82260ad..1a22b09af --- a/lib/IRremoteESP8266-2.6.5/examples/IRMQTTServer/platformio.ini +++ b/lib/IRremoteESP8266-2.7.0/examples/IRMQTTServer/platformio.ini @@ -5,13 +5,15 @@ src_dir = . lib_extra_dirs = ../../ lib_ldf_mode = deep+ lib_ignore = examples -build_flags = -DMQTT_MAX_PACKET_SIZE=768 +build_flags = -DMQTT_MAX_PACKET_SIZE=768 ; -D_IR_LOCALE_=en-AU +framework = arduino +platform = espressif8266 [common] lib_deps_builtin = lib_deps_external = PubSubClient - ArduinoJson@<6.0 + ArduinoJson@>=6.0 [common_esp8266] lib_deps_external = @@ -26,20 +28,14 @@ lib_deps_external = https://github.com/tzapu/WiFiManager.git#development [env:nodemcuv2] -platform = espressif8266 -framework = arduino board = nodemcuv2 lib_deps = ${common_esp8266.lib_deps_external} [env:d1_mini] -platform = espressif8266 -framework = arduino board = d1_mini lib_deps = ${common_esp8266.lib_deps_external} [env:d1_mini_no_mqtt] -platform = espressif8266 -framework = arduino board = d1_mini build_flags = ${env.build_flags} @@ -48,13 +44,10 @@ lib_deps = ${common_esp8266.lib_deps_external} [env:esp32dev] platform = espressif32 -framework = arduino board = esp32dev lib_deps = ${common_esp32.lib_deps_external} [env:esp01_1m] -platform = espressif8266 -framework = arduino board = esp01_1m build_flags = ${env.build_flags} diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRServer/IRServer.ino b/lib/IRremoteESP8266-2.7.0/examples/IRServer/IRServer.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/IRServer/IRServer.ino rename to lib/IRremoteESP8266-2.7.0/examples/IRServer/IRServer.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/IRServer/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/IRServer/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/IRServer/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRrecvDemo/IRrecvDemo.ino b/lib/IRremoteESP8266-2.7.0/examples/IRrecvDemo/IRrecvDemo.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/IRrecvDemo/IRrecvDemo.ino rename to lib/IRremoteESP8266-2.7.0/examples/IRrecvDemo/IRrecvDemo.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/IRrecvDemo/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/IRrecvDemo/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/IRrecvDemo/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRrecvDump/IRrecvDump.ino b/lib/IRremoteESP8266-2.7.0/examples/IRrecvDump/IRrecvDump.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/IRrecvDump/IRrecvDump.ino rename to lib/IRremoteESP8266-2.7.0/examples/IRrecvDump/IRrecvDump.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/IRrecvDump/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/IRrecvDump/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/IRrecvDump/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRrecvDumpV2/IRrecvDumpV2.ino b/lib/IRremoteESP8266-2.7.0/examples/IRrecvDumpV2/IRrecvDumpV2.ino old mode 100755 new mode 100644 similarity index 87% rename from lib/IRremoteESP8266-2.6.5/examples/IRrecvDumpV2/IRrecvDumpV2.ino rename to lib/IRremoteESP8266-2.7.0/examples/IRrecvDumpV2/IRrecvDumpV2.ino index f69c14aed..fc61f9b84 --- a/lib/IRremoteESP8266-2.6.5/examples/IRrecvDumpV2/IRrecvDumpV2.ino +++ b/lib/IRremoteESP8266-2.7.0/examples/IRrecvDumpV2/IRrecvDumpV2.ino @@ -9,6 +9,9 @@ * https://github.com/crankyoldgit/IRremoteESP8266/wiki#ir-receiving * * Changes: + * Version 1.0 October, 2019 + * - Internationalisation (i18n) support. + * - Stop displaying the legacy raw timing info. * Version 0.5 June, 2019 * - Move A/C description to IRac.cpp. * Version 0.4 July, 2018 @@ -25,6 +28,7 @@ #include #include #include +#include #include // ==================== start of TUNEABLE PARAMETERS ==================== @@ -92,6 +96,11 @@ const uint8_t kTimeout = 15; // from your device. (e.g. Other IR remotes work.) // NOTE: Set this value very high to effectively turn off UNKNOWN detection. const uint16_t kMinUnknownSize = 12; + +// Legacy (No longer supported!) +// +// Change to `true` if you miss/need the old "Raw Timing[]" display. +#define LEGACY_TIMING_INFO false // ==================== end of TUNEABLE PARAMETERS ==================== // Use turn on the save buffer feature for more complete capture coverage. @@ -107,12 +116,11 @@ void setup() { #endif // ESP8266 while (!Serial) // Wait for the serial connection to be establised. delay(50); - Serial.printf("\nIRrecvDumpV2 is now running and waiting for IR input on Pin " - "%d\n", kRecvPin); + Serial.printf("\n" D_STR_IRRECVDUMP_STARTUP "\n", kRecvPin); #if DECODE_HASH // Ignore messages with less than minimum on or off pulses. irrecv.setUnknownThreshold(kMinUnknownSize); -#endif // DECODE_HASH +#endif // DECODE_HASH irrecv.enableIRIn(); // Start the receiver } @@ -122,25 +130,23 @@ void loop() { if (irrecv.decode(&results)) { // Display a crude timestamp. uint32_t now = millis(); - Serial.printf("Timestamp : %06u.%03u\n", now / 1000, now % 1000); - // Check if we got an IR message tha was to big for our capture buffer. + Serial.printf(D_STR_TIMESTAMP " : %06u.%03u\n", now / 1000, now % 1000); + // Check if we got an IR message that was to big for our capture buffer. if (results.overflow) - Serial.printf( - "WARNING: IR code is too big for buffer (>= %d). " - "This result shouldn't be trusted until this is resolved. " - "Edit & increase kCaptureBufferSize.\n", - kCaptureBufferSize); + Serial.printf(D_WARN_BUFFERFULL "\n", kCaptureBufferSize); // Display the library version the message was captured with. - Serial.println("Library : v" _IRREMOTEESP8266_VERSION_ "\n"); + Serial.println(D_STR_LIBRARY " : v" _IRREMOTEESP8266_VERSION_ "\n"); // Display the basic output of what we found. Serial.print(resultToHumanReadableBasic(&results)); // Display any extra A/C info if we have it. String description = IRAcUtils::resultAcToString(&results); - if (description.length()) Serial.println("Mesg Desc.: " + description); + if (description.length()) Serial.println(D_STR_MESGDESC ": " + description); yield(); // Feed the WDT as the text output can take a while to print. - // Output RAW timing info of the result. +#if LEGACY_TIMING_INFO + // Output legacy RAW timing info of the result. Serial.println(resultToTimingInfo(&results)); yield(); // Feed the WDT (again) +#endif // LEGACY_TIMING_INFO // Output the results as source code Serial.println(resultToSourceCode(&results)); Serial.println(); // Blank line between entries diff --git a/lib/IRremoteESP8266-2.7.0/examples/IRrecvDumpV2/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/IRrecvDumpV2/platformio.ini new file mode 100644 index 000000000..d3c660df9 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/IRrecvDumpV2/platformio.ini @@ -0,0 +1,46 @@ +[platformio] +src_dir = . + +[env] +; Default platform +platform = espressif8266 +; Default board +board = nodemcuv2 +framework = arduino +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +board = nodemcuv2 +; build_flags = -D_IR_LOCALE_=en-AU + +[env:esp32dev] +platform = espressif32 +board = esp32dev +; build_flags = -D_IR_LOCALE_=en-AU + +[env:de-CH] +build_flags = -D_IR_LOCALE_=de-CH + +[env:de-DE] +build_flags = -D_IR_LOCALE_=de-DE + +[env:en-AU] +build_flags = -D_IR_LOCALE_=en-AU + +[env:en-IE] +build_flags = -D_IR_LOCALE_=en-IE + +[env:en-UK] +build_flags = -D_IR_LOCALE_=en-UK + +[env:en-US] +build_flags = -D_IR_LOCALE_=en-US + +[env:es-ES] +build_flags = -D_IR_LOCALE_=es-ES + +[env:fr-FR] +build_flags = -D_IR_LOCALE_=fr-FR diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRsendDemo/IRsendDemo.ino b/lib/IRremoteESP8266-2.7.0/examples/IRsendDemo/IRsendDemo.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/IRsendDemo/IRsendDemo.ino rename to lib/IRremoteESP8266-2.7.0/examples/IRsendDemo/IRsendDemo.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/IRsendDemo/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/IRsendDemo/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/IRsendDemo/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/IRsendProntoDemo/IRsendProntoDemo.ino b/lib/IRremoteESP8266-2.7.0/examples/IRsendProntoDemo/IRsendProntoDemo.ino old mode 100755 new mode 100644 similarity index 96% rename from lib/IRremoteESP8266-2.6.5/examples/IRsendProntoDemo/IRsendProntoDemo.ino rename to lib/IRremoteESP8266-2.7.0/examples/IRsendProntoDemo/IRsendProntoDemo.ino index 09101c9dc..330ad5051 --- a/lib/IRremoteESP8266-2.6.5/examples/IRsendProntoDemo/IRsendProntoDemo.ino +++ b/lib/IRremoteESP8266-2.7.0/examples/IRsendProntoDemo/IRsendProntoDemo.ino @@ -92,7 +92,11 @@ uint16_t panasonicProntoCode[104] = { void setup() { irsend.begin(); - Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY); + #if defined(ESP8266) + Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY); + #else // ESP8266 + Serial.begin(115200, SERIAL_8N1); + #endif // ESP8266 } void loop() { diff --git a/lib/IRremoteESP8266-2.7.0/examples/IRsendProntoDemo/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/IRsendProntoDemo/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/IRsendProntoDemo/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino b/lib/IRremoteESP8266-2.7.0/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino rename to lib/IRremoteESP8266-2.7.0/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/JVCPanasonicSendDemo/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/JVCPanasonicSendDemo/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/JVCPanasonicSendDemo/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/LGACSend/LGACSend.ino b/lib/IRremoteESP8266-2.7.0/examples/LGACSend/LGACSend.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/LGACSend/LGACSend.ino rename to lib/IRremoteESP8266-2.7.0/examples/LGACSend/LGACSend.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/LGACSend/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/LGACSend/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/LGACSend/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/SmartIRRepeater/SmartIRRepeater.ino b/lib/IRremoteESP8266-2.7.0/examples/SmartIRRepeater/SmartIRRepeater.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/SmartIRRepeater/SmartIRRepeater.ino rename to lib/IRremoteESP8266-2.7.0/examples/SmartIRRepeater/SmartIRRepeater.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/SmartIRRepeater/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/SmartIRRepeater/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/SmartIRRepeater/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnArgoAC/TurnOnArgoAC.ino b/lib/IRremoteESP8266-2.7.0/examples/TurnOnArgoAC/TurnOnArgoAC.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/TurnOnArgoAC/TurnOnArgoAC.ino rename to lib/IRremoteESP8266-2.7.0/examples/TurnOnArgoAC/TurnOnArgoAC.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/TurnOnArgoAC/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/TurnOnArgoAC/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/TurnOnArgoAC/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino b/lib/IRremoteESP8266-2.7.0/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino rename to lib/IRremoteESP8266-2.7.0/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/TurnOnDaikinAC/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/TurnOnDaikinAC/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/TurnOnDaikinAC/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino b/lib/IRremoteESP8266-2.7.0/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino rename to lib/IRremoteESP8266-2.7.0/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/TurnOnFujitsuAC/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/TurnOnFujitsuAC/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/TurnOnFujitsuAC/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino b/lib/IRremoteESP8266-2.7.0/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino rename to lib/IRremoteESP8266-2.7.0/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/TurnOnKelvinatorAC/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/TurnOnKelvinatorAC/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/TurnOnKelvinatorAC/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino b/lib/IRremoteESP8266-2.7.0/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino rename to lib/IRremoteESP8266-2.7.0/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/TurnOnMitsubishiAC/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/TurnOnMitsubishiAC/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/TurnOnMitsubishiAC/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino b/lib/IRremoteESP8266-2.7.0/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino rename to lib/IRremoteESP8266-2.7.0/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/TurnOnMitsubishiHeavyAc/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/TurnOnMitsubishiHeavyAc/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/TurnOnMitsubishiHeavyAc/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino b/lib/IRremoteESP8266-2.7.0/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino rename to lib/IRremoteESP8266-2.7.0/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/TurnOnPanasonicAC/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/TurnOnPanasonicAC/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/TurnOnPanasonicAC/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino b/lib/IRremoteESP8266-2.7.0/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino rename to lib/IRremoteESP8266-2.7.0/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/TurnOnToshibaAC/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/TurnOnToshibaAC/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/TurnOnToshibaAC/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.6.5/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino b/lib/IRremoteESP8266-2.7.0/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino rename to lib/IRremoteESP8266-2.7.0/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino diff --git a/lib/IRremoteESP8266-2.7.0/examples/TurnOnTrotecAC/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/TurnOnTrotecAC/platformio.ini new file mode 100644 index 000000000..e6f6320da --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/TurnOnTrotecAC/platformio.ini @@ -0,0 +1,17 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 + +[env:esp32dev] +platform = espressif32 +board = esp32dev diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/README.md b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/README.md new file mode 100644 index 000000000..fa8a441cb --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/README.md @@ -0,0 +1,43 @@ +# esp8266-AC-control + +This is just a web interface for the IRremoteESP8266 library. + +![Web Gui Preview](https://github.com/mariusmotea/esp8266-AC-control/raw/master/printscreen.png) + + +## Instructions: + + - Connect IR led to one GPIO pin (recommended pin is GPIO4) + + - Edit esp8266-AC-control.ino header marked as "User space". You will need to import the library dedicated for your AC model. Every library has its own commands for AC mode and fan speed that will need to be replace according to commands available in .h file of the library. + + - Flash the firmware in ESP board using 1M or 2M of SPIFFS storage. + + - Connect the board to your wifi network (look for "AC Remote Control" SSID and follow WiFi Manager wizard) + + - Upload web application files in SPIFFS storage using build in web form located at /file-upload path. + + +## REST API: + +Browser console will show the ajax calls to ESP8266 board. Running configuration can be displayed with GET request to /state path, any value can be changed with http PUT request to same path. + +Ex: + +``` +âžś ~ curl 192.168.0.71/state +{"mode":2,"fan":0,"temp":27,"power":true}% +âžś ~ curl -X PUT -d '{"temp":22}' 192.168.0.71/state +{"temp":22}% +âžś ~ curl 192.168.0.71/state +{"mode":2,"fan":0,"temp":22,"power":true}% +``` + +## DEBUG: + +Use mobile phone camera to see if the led is sending any IR signals when buttons are pressed. This will show if the circuit was properly made and the selected GPIO pin is the correct one. + + +## Credits: + +Interface: https://github.com/ael-code/daikin-control diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/Web-AC-control.ino b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/Web-AC-control.ino new file mode 100644 index 000000000..ac02bdc59 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/Web-AC-control.ino @@ -0,0 +1,300 @@ +/* Copyright 2019 Motea Marius + + This example code will create a webserver that will provide basic control to AC units using the web application + build with javascript/css. User config zone need to be updated if a different class than Collix need to be used. + Javasctipt file may also require minor changes as in current version it will not allow to set fan speed if Auto mode + is selected (required for Coolix). + +*/ +#include +#if defined(ESP8266) +#include +#include +#include +#include +#endif // ESP8266 +#if defined(ESP32) +#include +#include +#include +#include +#include +#endif // ESP32 +#include +#include +#include +#include +#include + +//// ###### User configuration space for AC library classes ########## + +#include // replace library based on your AC unit model, check https://github.com/crankyoldgit/IRremoteESP8266 + +#define AUTO_MODE kCoolixAuto +#define COOL_MODE kCoolixCool +#define DRY_MODE kCoolixDry +#define HEAT_MODE kCoolixHeat +#define FAN_MODE kCoolixFan + +#define FAN_AUTO kCoolixFanAuto +#define FAN_MIN kCoolixFanMin +#define FAN_MED kCoolixFanMed +#define FAN_HI kCoolixFanMax + +// ESP8266 GPIO pin to use for IR blaster. +const uint16_t kIrLed = 4; +// Library initialization, change it according to the imported library file. +IRCoolixAC ac(kIrLed); + +/// ##### End user configuration ###### + + +struct state { + uint8_t temperature = 22, fan = 0, operation = 0; + bool powerStatus; +}; + +File fsUploadFile; + +// core + +state acState; + +// settings +char deviceName[] = "AC Remote Control"; + +#if defined(ESP8266) +ESP8266WebServer server(80); +ESP8266HTTPUpdateServer httpUpdateServer; +#endif // ESP8266 +#if defined(ESP32) +WebServer server(80); +#endif // ESP32 + +bool handleFileRead(String path) { + // send the right file to the client (if it exists) + // Serial.println("handleFileRead: " + path); + if (path.endsWith("/")) path += "index.html"; + // If a folder is requested, send the index file + String contentType = getContentType(path); + // Get the MIME type + String pathWithGz = path + ".gz"; + if (SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { + // If the file exists, either as a compressed archive, or normal + if (SPIFFS.exists(pathWithGz)) // If there's a compressed version available + path += ".gz"; // Use the compressed verion + File file = SPIFFS.open(path, "r"); + // Open the file + server.streamFile(file, contentType); + // Send it to the client + file.close(); + // Close the file again + // Serial.println(String("\tSent file: ") + path); + return true; + } + // Serial.println(String("\tFile Not Found: ") + path); + // If the file doesn't exist, return false + return false; +} + +String getContentType(String filename) { + // convert the file extension to the MIME type + if (filename.endsWith(".html")) return "text/html"; + else if (filename.endsWith(".css")) return "text/css"; + else if (filename.endsWith(".js")) return "application/javascript"; + else if (filename.endsWith(".ico")) return "image/x-icon"; + else if (filename.endsWith(".gz")) return "application/x-gzip"; + return "text/plain"; +} + +void handleFileUpload() { // upload a new file to the SPIFFS + HTTPUpload& upload = server.upload(); + if (upload.status == UPLOAD_FILE_START) { + String filename = upload.filename; + if (!filename.startsWith("/")) filename = "/" + filename; + // Serial.print("handleFileUpload Name: "); //Serial.println(filename); + fsUploadFile = SPIFFS.open(filename, "w"); + // Open the file for writing in SPIFFS (create if it doesn't exist) + filename = String(); + } else if (upload.status == UPLOAD_FILE_WRITE) { + if (fsUploadFile) + fsUploadFile.write(upload.buf, upload.currentSize); + // Write the received bytes to the file + } else if (upload.status == UPLOAD_FILE_END) { + if (fsUploadFile) { + // If the file was successfully created + fsUploadFile.close(); + // Close the file again + // Serial.print("handleFileUpload Size: "); + // Serial.println(upload.totalSize); + server.sendHeader("Location", "/success.html"); + // Redirect the client to the success page + server.send(303); + } else { + server.send(500, "text/plain", "500: couldn't create file"); + } + } +} + + +void handleNotFound() { + String message = "File Not Found\n\n"; + message += "URI: "; + message += server.uri(); + message += "\nMethod: "; + message += (server.method() == HTTP_GET) ? "GET" : "POST"; + message += "\nArguments: "; + message += server.args(); + message += "\n"; + for (uint8_t i = 0; i < server.args(); i++) { + message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + } + server.send(404, "text/plain", message); +} + +void setup() { + // Serial.begin(115200); + // Serial.println(); + ac.begin(); + + + delay(1000); + + // Serial.println("mounting FS..."); + + if (!SPIFFS.begin()) { + // Serial.println("Failed to mount file system"); + return; + } + + WiFiManager wifiManager; + + + if (!wifiManager.autoConnect(deviceName)) { + delay(3000); + ESP.restart(); + delay(5000); + } + + +#if defined(ESP8266) + httpUpdateServer.setup(&server); +#endif // ESP8266 + + + + server.on("/state", HTTP_PUT, []() { + DynamicJsonDocument root(1024); + DeserializationError error = deserializeJson(root, server.arg("plain")); + if (error) { + server.send(404, "text/plain", "FAIL. " + server.arg("plain")); + } else { + if (root.containsKey("temp")) { + acState.temperature = (uint8_t) root["temp"]; + } + + if (root.containsKey("fan")) { + acState.fan = (uint8_t) root["fan"]; + } + + if (root.containsKey("power")) { + acState.powerStatus = root["power"]; + } + + if (root.containsKey("mode")) { + acState.operation = root["mode"]; + } + + String output; + serializeJson(root, output); + server.send(200, "text/plain", output); + + delay(200); + + if (acState.powerStatus) { + ac.on(); + ac.setTemp(acState.temperature); + if (acState.operation == 0) { + ac.setMode(AUTO_MODE); + ac.setFan(FAN_AUTO); + acState.fan = 0; + } else if (acState.operation == 1) { + ac.setMode(COOL_MODE); + } else if (acState.operation == 2) { + ac.setMode(DRY_MODE); + } else if (acState.operation == 3) { + ac.setMode(HEAT_MODE); + } else if (acState.operation == 4) { + ac.setMode(FAN_MODE); + } + + if (acState.operation != 0) { + if (acState.fan == 0) { + ac.setFan(FAN_AUTO); + } else if (acState.fan == 1) { + ac.setFan(FAN_MIN); + } else if (acState.fan == 2) { + ac.setFan(FAN_MED); + } else if (acState.fan == 3) { + ac.setFan(FAN_HI); + } + } + } else { + ac.off(); + } + ac.send(); + } + }); + + server.on("/file-upload", HTTP_POST, + // if the client posts to the upload page + []() { + // Send status 200 (OK) to tell the client we are ready to receive + server.send(200); + }, + handleFileUpload); // Receive and save the file + + server.on("/file-upload", HTTP_GET, []() { + // if the client requests the upload page + + String html = "
"; + html += ""; + html += ""; + html += "
"; + server.send(200, "text/html", html); + }); + + server.on("/", []() { + server.sendHeader("Location", String("ui.html"), true); + server.send(302, "text/plain", ""); + }); + + server.on("/state", HTTP_GET, []() { + DynamicJsonDocument root(1024); + root["mode"] = acState.operation; + root["fan"] = acState.fan; + root["temp"] = acState.temperature; + root["power"] = acState.powerStatus; + String output; + serializeJson(root, output); + server.send(200, "text/plain", output); + }); + + + server.on("/reset", []() { + server.send(200, "text/html", "reset"); + delay(100); + ESP.restart(); + }); + + server.serveStatic("/", SPIFFS, "/", "max-age=86400"); + + server.onNotFound(handleNotFound); + + server.begin(); +} + + +void loop() { + server.handleClient(); +} diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/platformio.ini b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/platformio.ini new file mode 100644 index 000000000..731442831 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/platformio.ini @@ -0,0 +1,36 @@ +[platformio] +src_dir = . + +[env] +lib_extra_dirs = ../../ +lib_ldf_mode = deep+ +lib_ignore = examples +framework = arduino +build_flags = ; -D_IR_LOCALE_=en-AU + +[common] +lib_deps_builtin = +lib_deps_external = + ArduinoJson@>=6.0 + +[common_esp8266] +lib_deps_external = + ${common.lib_deps_builtin} + ${common.lib_deps_external} + WifiManager@>=0.14 + +[common_esp32] +lib_deps_external = + ${common.lib_deps_builtin} + ${common.lib_deps_external} + https://github.com/tzapu/WiFiManager.git#development + +[env:nodemcuv2] +platform = espressif8266 +board = nodemcuv2 +lib_deps = ${common_esp8266.lib_deps_external} + +[env:esp32dev] +platform = espressif32 +board = esp32dev +lib_deps = ${common_esp32.lib_deps_external} diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/printscreen.png b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/printscreen.png new file mode 100644 index 000000000..9fc7dbf3c Binary files /dev/null and b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/printscreen.png differ diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/favicon.ico b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/favicon.ico new file mode 100644 index 000000000..f206c7cc7 Binary files /dev/null and b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/favicon.ico differ diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_1_off.svg b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_1_off.svg new file mode 100644 index 000000000..778286d15 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_1_off.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_1_on.svg b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_1_on.svg new file mode 100644 index 000000000..32505f2a4 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_1_on.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_2_off.svg b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_2_off.svg new file mode 100644 index 000000000..20d54679c --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_2_off.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_2_on.svg b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_2_on.svg new file mode 100644 index 000000000..307370607 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_2_on.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_3_off.svg b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_3_off.svg new file mode 100644 index 000000000..2bbf5848e --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_3_off.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_3_on.svg b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_3_on.svg new file mode 100644 index 000000000..ca29839e2 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_3_on.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_4_off.svg b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_4_off.svg new file mode 100644 index 000000000..3ee1beced --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_4_off.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_4_on.svg b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_4_on.svg new file mode 100644 index 000000000..720d70148 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/level_4_on.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/ui.html b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/ui.html new file mode 100644 index 000000000..cfefc20d5 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/ui.html @@ -0,0 +1,109 @@ + + + + + + + Home Temperature + + + + + + + + + + + + + + + + +
+ + + +
+ +

+
+ +
+
+ + +
+ OFF +
+ +
+
+
+
+ + +

Mode

+
+ + + + + +
+ +
+
+ + +

Fan

+
+ + + + +
+ +
+
+
+
+
+
+ + +

Target temperature

+
+ ~ C +
+ +
+ + +
+ + + +
+
+
+ +
+
+ + + + diff --git a/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/ui.js b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/ui.js new file mode 100644 index 000000000..9bdb8c795 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/examples/Web-AC-control/upload/ui.js @@ -0,0 +1,132 @@ +var state = {} + +function updateStatus() { + $.ajax({ + type: 'GET', + url: "state", + dataType: "json", + data: [{ + name: "light", + value: "1" + }, ], + success: function(data) { + if (!data) { + return; + } + state = data; + if (state["power"] === true) { + $("#power").text(" ON"); + $("#power-btn").addClass("btn-info"); + $("#power-btn").removeClass("btn-default"); + } else { + $("#power").text(" OFF"); + $("#power-btn").addClass("btn-default"); + $("#power-btn").removeClass("btn-info"); + } + $("#target_temp").text(state["temp"] + " C"); + setModeColor(state["mode"]); + setFanColor(state["fan"]); + }, + error: function() { + console.log('error getting state'); + }, + timeout: 1000 + }); +} + +updateStatus(); + + + + +function postData(t) { + var e = new XMLHttpRequest; + e.timeout = 2000; + e.open("PUT", "state", !0); + e.setRequestHeader("Content-Type", "application/json"); + console.log(JSON.stringify(t)), e.send(JSON.stringify(t)); +} + +function mode_onclick(mode) { + state["mode"] = mode; + setModeColor(mode); + postData(state); +} + + +function setModeColor(mode) { + $(".mode-btn").addClass("btn-default"); + $(".mode-btn").removeClass("btn-info"); + + if (mode === 0) { + $("#mode_auto").removeClass("btn-default"); + $("#mode_auto").addClass("btn-info"); + setFanColor(0); + state["fan"] = 0; + } else if (mode === 1) { + $("#mode_cooling").removeClass("btn-default"); + $("#mode_cooling").addClass("btn-info"); + } else if (mode === 2) { + $("#mode_dehum").removeClass("btn-default"); + $("#mode_dehum").addClass("btn-info"); + } else if (mode === 3) { + $("#mode_heating").removeClass("btn-default"); + $("#mode_heating").addClass("btn-info"); + } else if (mode === 4) { + $("#mode_fan").removeClass("btn-default"); + $("#mode_fan").addClass("btn-info"); + } +} + +function setFanColor(fan) { + if (fan == 0) { + $("#fan_auto").removeClass("btn-default"); + $("#fan_auto").addClass("btn-info"); + } else { + $("#fan_auto").removeClass("btn-info"); + $("#fan_auto").addClass("btn-default"); + } + for (var i = 1; i <= 3; ++i) { + if (i <= fan) { + $("#fan_lvl_" + i).attr("src", "level_" + i + "_on.svg"); + } else { + $("#fan_lvl_" + i).attr("src", "level_" + i + "_off.svg"); + } + } +} + +function fan_onclick(fan) { + if (state["mode"] !== 0) { + state["fan"] = fan; + setFanColor(fan); + postData(state); + } +} + +function power_onclick(power) { + if (state["power"]) { + state["power"] = false; + $("#power").text(" OFF"); + $("#power-btn").removeClass("btn-info"); + $("#power-btn").addClass("btn-default"); + } else { + state["power"] = true; + $("#power").text(" ON"); + $("#power-btn").addClass("btn-info"); + $("#power-btn").removeClass("btn-default"); + } + postData(state); +} + + +function temp_onclick(temp) { + state["temp"] += temp; + if (state["temp"] < 17) { + state["temp"] = 17; + } + if (state["temp"] > 30) { + state["temp"] = 30; + } + $("#target_temp").text(state["temp"] + " C"); + postData(state); +} diff --git a/lib/IRremoteESP8266-2.6.5/keywords.txt b/lib/IRremoteESP8266-2.7.0/keywords.txt old mode 100755 new mode 100644 similarity index 80% rename from lib/IRremoteESP8266-2.6.5/keywords.txt rename to lib/IRremoteESP8266-2.7.0/keywords.txt index db2d398a1..33a48f5f2 --- a/lib/IRremoteESP8266-2.6.5/keywords.txt +++ b/lib/IRremoteESP8266-2.7.0/keywords.txt @@ -37,8 +37,11 @@ IRGreeAC KEYWORD1 IRHaierAC KEYWORD1 IRHaierACYRW02 KEYWORD1 IRHitachiAc KEYWORD1 +IRHitachiAc424 KEYWORD1 IRKelvinatorAC KEYWORD1 IRMideaAC KEYWORD1 +IRMitsubishi112 KEYWORD1 +IRMitsubishi136 KEYWORD1 IRMitsubishiAC KEYWORD1 IRMitsubishiHeavy152Ac KEYWORD1 IRMitsubishiHeavy88Ac KEYWORD1 @@ -76,16 +79,22 @@ whirlpool_ac_remote_model_t KEYWORD1 ####################################### _delayMicroseconds KEYWORD2 +_getTime KEYWORD2 +_getTimer KEYWORD2 _matchGeneric KEYWORD2 _setMode KEYWORD2 _setTemp KEYWORD2 +_setTime KEYWORD2 +_setTimer KEYWORD2 _validTolerance KEYWORD2 add KEYWORD2 addBoolToString KEYWORD2 +addDayToString KEYWORD2 addFanToString KEYWORD2 addIntToString KEYWORD2 addLabeledString KEYWORD2 addModeToString KEYWORD2 +addModelToString KEYWORD2 addTempToString KEYWORD2 amcor KEYWORD2 argo KEYWORD2 @@ -123,6 +132,7 @@ copyIrParams KEYWORD2 countBits KEYWORD2 daikin KEYWORD2 daikin128 KEYWORD2 +daikin152 KEYWORD2 daikin160 KEYWORD2 daikin176 KEYWORD2 daikin2 KEYWORD2 @@ -151,6 +161,7 @@ decodeHaierAC KEYWORD2 decodeHaierACYRW02 KEYWORD2 decodeHash KEYWORD2 decodeHitachiAC KEYWORD2 +decodeHitachiAc424 KEYWORD2 decodeInax KEYWORD2 decodeJVC KEYWORD2 decodeKelvinator KEYWORD2 @@ -162,6 +173,8 @@ decodeMWM KEYWORD2 decodeMagiQuest KEYWORD2 decodeMidea KEYWORD2 decodeMitsubishi KEYWORD2 +decodeMitsubishi112 KEYWORD2 +decodeMitsubishi136 KEYWORD2 decodeMitsubishi2 KEYWORD2 decodeMitsubishiAC KEYWORD2 decodeMitsubishiHeavy KEYWORD2 @@ -182,7 +195,6 @@ decodeSanyoLC7461 KEYWORD2 decodeSharp KEYWORD2 decodeSharpAc KEYWORD2 decodeSony KEYWORD2 -decodeTcl112Ac KEYWORD2 decodeTeco KEYWORD2 decodeToState KEYWORD2 decodeToshibaAC KEYWORD2 @@ -225,6 +237,7 @@ fujitsu KEYWORD2 get3D KEYWORD2 get8CHeat KEYWORD2 getBeep KEYWORD2 +getBit KEYWORD2 getBufSize KEYWORD2 getButton KEYWORD2 getClean KEYWORD2 @@ -260,7 +273,6 @@ getMax KEYWORD2 getMode KEYWORD2 getMold KEYWORD2 getNight KEYWORD2 -getNormalState KEYWORD2 getOffTime KEYWORD2 getOffTimer KEYWORD2 getOffTimerEnabled KEYWORD2 @@ -316,9 +328,13 @@ goodweather KEYWORD2 gree KEYWORD2 haier KEYWORD2 haierYrwo2 KEYWORD2 +handleSpecialState KEYWORD2 hasACState KEYWORD2 +hasStateChanged KEYWORD2 hitachi KEYWORD2 +hitachi424 KEYWORD2 htmlEscape KEYWORD2 +initState KEYWORD2 invertBits KEYWORD2 isOffTimerActive KEYWORD2 isOffTimerEnabled KEYWORD2 @@ -345,8 +361,11 @@ midea KEYWORD2 minRepeats KEYWORD2 minsToString KEYWORD2 mitsubishi KEYWORD2 +mitsubishi112 KEYWORD2 +mitsubishi136 KEYWORD2 mitsubishiHeavy152 KEYWORD2 mitsubishiHeavy88 KEYWORD2 +modelToStr KEYWORD2 msToString KEYWORD2 neoclima KEYWORD2 off KEYWORD2 @@ -394,6 +413,7 @@ sendHaierACYRW02 KEYWORD2 sendHitachiAC KEYWORD2 sendHitachiAC1 KEYWORD2 sendHitachiAC2 KEYWORD2 +sendHitachiAc424 KEYWORD2 sendInax KEYWORD2 sendJVC KEYWORD2 sendKelvinator KEYWORD2 @@ -406,6 +426,8 @@ sendMWM KEYWORD2 sendMagiQuest KEYWORD2 sendMidea KEYWORD2 sendMitsubishi KEYWORD2 +sendMitsubishi112 KEYWORD2 +sendMitsubishi136 KEYWORD2 sendMitsubishi2 KEYWORD2 sendMitsubishiAC KEYWORD2 sendMitsubishiHeavy152 KEYWORD2 @@ -445,6 +467,8 @@ set3D KEYWORD2 set8CHeat KEYWORD2 setAuto KEYWORD2 setBeep KEYWORD2 +setBit KEYWORD2 +setBits KEYWORD2 setButton KEYWORD2 setClean KEYWORD2 setClock KEYWORD2 @@ -469,6 +493,7 @@ setHealth KEYWORD2 setHold KEYWORD2 setHumid KEYWORD2 setIFeel KEYWORD2 +setInvertedStates KEYWORD2 setIon KEYWORD2 setIonFilter KEYWORD2 setLed KEYWORD2 @@ -594,6 +619,7 @@ ARGO_MIN_TEMP LITERAL1 ARJW2 LITERAL1 ARRAH2E LITERAL1 ARREB1E LITERAL1 +ARRY4 LITERAL1 CARRIER_AC LITERAL1 CARRIER_AC_BITS LITERAL1 COOLIX LITERAL1 @@ -644,6 +670,7 @@ DECODE_HASH LITERAL1 DECODE_HITACHI_AC LITERAL1 DECODE_HITACHI_AC1 LITERAL1 DECODE_HITACHI_AC2 LITERAL1 +DECODE_HITACHI_AC424 LITERAL1 DECODE_INAX LITERAL1 DECODE_JVC LITERAL1 DECODE_KELVINATOR LITERAL1 @@ -654,6 +681,8 @@ DECODE_LUTRON LITERAL1 DECODE_MAGIQUEST LITERAL1 DECODE_MIDEA LITERAL1 DECODE_MITSUBISHI LITERAL1 +DECODE_MITSUBISHI112 LITERAL1 +DECODE_MITSUBISHI136 LITERAL1 DECODE_MITSUBISHI2 LITERAL1 DECODE_MITSUBISHIHEAVY LITERAL1 DECODE_MITSUBISHI_AC LITERAL1 @@ -809,6 +838,7 @@ HITACHI_AC1_STATE_LENGTH LITERAL1 HITACHI_AC2 LITERAL1 HITACHI_AC2_BITS LITERAL1 HITACHI_AC2_STATE_LENGTH LITERAL1 +HITACHI_AC424 LITERAL1 HITACHI_AC_BITS LITERAL1 HITACHI_AC_STATE_LENGTH LITERAL1 ICACHE_RAM_ATTR LITERAL1 @@ -857,6 +887,8 @@ MIDEA_AC_POWER LITERAL1 MIDEA_AC_SLEEP LITERAL1 MIDEA_BITS LITERAL1 MITSUBISHI LITERAL1 +MITSUBISHI112 LITERAL1 +MITSUBISHI136 LITERAL1 MITSUBISHI2 LITERAL1 MITSUBISHI_AC LITERAL1 MITSUBISHI_AC_AUTO LITERAL1 @@ -933,6 +965,7 @@ SEND_HAIER_AC_YRW02 LITERAL1 SEND_HITACHI_AC LITERAL1 SEND_HITACHI_AC1 LITERAL1 SEND_HITACHI_AC2 LITERAL1 +SEND_HITACHI_AC424 LITERAL1 SEND_INAX LITERAL1 SEND_JVC LITERAL1 SEND_KELVINATOR LITERAL1 @@ -943,6 +976,8 @@ SEND_LUTRON LITERAL1 SEND_MAGIQUEST LITERAL1 SEND_MIDEA LITERAL1 SEND_MITSUBISHI LITERAL1 +SEND_MITSUBISHI112 LITERAL1 +SEND_MITSUBISHI136 LITERAL1 SEND_MITSUBISHI2 LITERAL1 SEND_MITSUBISHIHEAVY LITERAL1 SEND_MITSUBISHI_AC LITERAL1 @@ -1031,32 +1066,40 @@ kAmcorDefaultRepeat LITERAL1 kAmcorDry LITERAL1 kAmcorFan LITERAL1 kAmcorFanAuto LITERAL1 -kAmcorFanMask LITERAL1 kAmcorFanMax LITERAL1 kAmcorFanMed LITERAL1 kAmcorFanMin LITERAL1 +kAmcorFanOffset LITERAL1 +kAmcorFanSize LITERAL1 kAmcorFooterMark LITERAL1 kAmcorGap LITERAL1 kAmcorHdrMark LITERAL1 kAmcorHdrSpace LITERAL1 kAmcorHeat LITERAL1 -kAmcorMaxMask LITERAL1 +kAmcorMax LITERAL1 +kAmcorMaxOffset LITERAL1 +kAmcorMaxSize LITERAL1 kAmcorMaxTemp LITERAL1 kAmcorMinTemp LITERAL1 kAmcorModeFanByte LITERAL1 -kAmcorModeMask LITERAL1 +kAmcorModeOffset LITERAL1 +kAmcorModeSize LITERAL1 kAmcorOneMark LITERAL1 kAmcorOneSpace LITERAL1 kAmcorPowerByte LITERAL1 -kAmcorPowerMask LITERAL1 kAmcorPowerOff LITERAL1 +kAmcorPowerOffset LITERAL1 kAmcorPowerOn LITERAL1 +kAmcorPowerSize LITERAL1 kAmcorSpecialByte LITERAL1 kAmcorStateLength LITERAL1 kAmcorTempByte LITERAL1 -kAmcorTempMask LITERAL1 +kAmcorTempOffset LITERAL1 +kAmcorTempSize LITERAL1 kAmcorTolerance LITERAL1 -kAmcorVentMask LITERAL1 +kAmcorVentOffset LITERAL1 +kAmcorVentOn LITERAL1 +kAmcorVentSize LITERAL1 kAmcorZeroMark LITERAL1 kAmcorZeroSpace LITERAL1 kArgoAuto LITERAL1 @@ -1069,7 +1112,8 @@ kArgoFan1 LITERAL1 kArgoFan2 LITERAL1 kArgoFan3 LITERAL1 kArgoFanAuto LITERAL1 -kArgoFanMask LITERAL1 +kArgoFanOffset LITERAL1 +kArgoFanSize LITERAL1 kArgoFlap1 LITERAL1 kArgoFlap2 LITERAL1 kArgoFlap3 LITERAL1 @@ -1085,22 +1129,27 @@ kArgoHeat LITERAL1 kArgoHeatAuto LITERAL1 kArgoHeatBit LITERAL1 kArgoHeatBlink LITERAL1 -kArgoIFeelBit LITERAL1 -kArgoMaxBit LITERAL1 +kArgoIFeelBitOffset LITERAL1 +kArgoMaxBitOffset LITERAL1 kArgoMaxRoomTemp LITERAL1 kArgoMaxTemp LITERAL1 kArgoMinTemp LITERAL1 -kArgoModeMask LITERAL1 -kArgoNightBit LITERAL1 +kArgoModeOffset LITERAL1 +kArgoModeSize LITERAL1 +kArgoNightBitOffset LITERAL1 kArgoOff LITERAL1 kArgoOneSpace LITERAL1 -kArgoPowerBit LITERAL1 -kArgoRoomTempHighMask LITERAL1 -kArgoRoomTempLowMask LITERAL1 +kArgoPowerBitOffset LITERAL1 +kArgoRoomTempHighOffset LITERAL1 +kArgoRoomTempHighSize LITERAL1 +kArgoRoomTempLowOffset LITERAL1 +kArgoRoomTempLowSize LITERAL1 kArgoStateLength LITERAL1 -kArgoTempHighMask LITERAL1 -kArgoTempLowMask LITERAL1 -kArgoTempOffset LITERAL1 +kArgoTempDelta LITERAL1 +kArgoTempHighOffset LITERAL1 +kArgoTempHighSize LITERAL1 +kArgoTempLowOffset LITERAL1 +kArgoTempLowSize LITERAL1 kArgoZeroSpace LITERAL1 kAuto LITERAL1 kCarrierAcBitMark LITERAL1 @@ -1117,6 +1166,7 @@ kCoolixBitMark LITERAL1 kCoolixBitMarkTicks LITERAL1 kCoolixBits LITERAL1 kCoolixClean LITERAL1 +kCoolixCmdFan LITERAL1 kCoolixCool LITERAL1 kCoolixDefaultRepeat LITERAL1 kCoolixDefaultState LITERAL1 @@ -1125,10 +1175,11 @@ kCoolixFan LITERAL1 kCoolixFanAuto LITERAL1 kCoolixFanAuto0 LITERAL1 kCoolixFanFixed LITERAL1 -kCoolixFanMask LITERAL1 kCoolixFanMax LITERAL1 kCoolixFanMed LITERAL1 kCoolixFanMin LITERAL1 +kCoolixFanOffset LITERAL1 +kCoolixFanSize LITERAL1 kCoolixFanTempCode LITERAL1 kCoolixFanZoneFollow LITERAL1 kCoolixHdrMark LITERAL1 @@ -1139,37 +1190,47 @@ kCoolixHeat LITERAL1 kCoolixLed LITERAL1 kCoolixMinGap LITERAL1 kCoolixMinGapTicks LITERAL1 -kCoolixModeMask LITERAL1 +kCoolixModeOffset LITERAL1 +kCoolixModeSize LITERAL1 kCoolixOff LITERAL1 kCoolixOneSpace LITERAL1 kCoolixOneSpaceTicks LITERAL1 kCoolixPrefix LITERAL1 kCoolixSensorTempIgnoreCode LITERAL1 -kCoolixSensorTempMask LITERAL1 kCoolixSensorTempMax LITERAL1 kCoolixSensorTempMin LITERAL1 +kCoolixSensorTempOffset LITERAL1 +kCoolixSensorTempSize LITERAL1 kCoolixSleep LITERAL1 kCoolixSwing LITERAL1 +kCoolixSwingH LITERAL1 +kCoolixSwingV LITERAL1 kCoolixTempMap LITERAL1 -kCoolixTempMask LITERAL1 kCoolixTempMax LITERAL1 kCoolixTempMin LITERAL1 +kCoolixTempOffset LITERAL1 kCoolixTempRange LITERAL1 +kCoolixTempSize LITERAL1 kCoolixTick LITERAL1 kCoolixTurbo LITERAL1 kCoolixUnknown LITERAL1 kCoolixZeroSpace LITERAL1 kCoolixZeroSpaceTicks LITERAL1 -kCoolixZoneFollowMask LITERAL1 +kCoolixZoneFollowMaskOffset LITERAL1 kDaikin128Auto LITERAL1 kDaikin128BitCeiling LITERAL1 kDaikin128BitEcono LITERAL1 +kDaikin128BitEconoOffset LITERAL1 kDaikin128BitHalfHour LITERAL1 kDaikin128BitMark LITERAL1 kDaikin128BitPowerToggle LITERAL1 +kDaikin128BitPowerToggleOffset LITERAL1 kDaikin128BitSleep LITERAL1 +kDaikin128BitSleepOffset LITERAL1 kDaikin128BitSwing LITERAL1 +kDaikin128BitSwingOffset LITERAL1 kDaikin128BitTimerEnabled LITERAL1 +kDaikin128BitTimerEnabledOffset LITERAL1 kDaikin128BitWall LITERAL1 kDaikin128Bits LITERAL1 kDaikin128ByteClockHours LITERAL1 @@ -1193,32 +1254,51 @@ kDaikin128FanQuiet LITERAL1 kDaikin128FooterMark LITERAL1 kDaikin128Freq LITERAL1 kDaikin128Gap LITERAL1 +kDaikin128HalfHourOffset LITERAL1 kDaikin128HdrMark LITERAL1 kDaikin128HdrSpace LITERAL1 kDaikin128Heat LITERAL1 +kDaikin128HoursOffset LITERAL1 +kDaikin128HoursSize LITERAL1 kDaikin128LeaderMark LITERAL1 kDaikin128LeaderSpace LITERAL1 kDaikin128MaskFan LITERAL1 -kDaikin128MaskHours LITERAL1 kDaikin128MaskLight LITERAL1 -kDaikin128MaskMode LITERAL1 kDaikin128MaxTemp LITERAL1 kDaikin128MinTemp LITERAL1 +kDaikin128ModeSize LITERAL1 kDaikin128OneSpace LITERAL1 kDaikin128SectionLength LITERAL1 kDaikin128Sections LITERAL1 kDaikin128StateLength LITERAL1 +kDaikin128TimerOffset LITERAL1 +kDaikin128TimerSize LITERAL1 kDaikin128ZeroSpace LITERAL1 kDaikin152BitMark LITERAL1 kDaikin152Bits LITERAL1 +kDaikin152ComfortByte LITERAL1 +kDaikin152ComfortOffset LITERAL1 kDaikin152DefaultRepeat LITERAL1 +kDaikin152DryTemp LITERAL1 +kDaikin152EconoByte LITERAL1 +kDaikin152FanByte LITERAL1 +kDaikin152FanTemp LITERAL1 kDaikin152Freq LITERAL1 kDaikin152Gap LITERAL1 kDaikin152HdrMark LITERAL1 kDaikin152HdrSpace LITERAL1 kDaikin152LeaderBits LITERAL1 +kDaikin152ModeByte LITERAL1 kDaikin152OneSpace LITERAL1 +kDaikin152PowerByte LITERAL1 +kDaikin152PowerfulByte LITERAL1 +kDaikin152QuietByte LITERAL1 +kDaikin152SensorByte LITERAL1 +kDaikin152SensorOffset LITERAL1 kDaikin152StateLength LITERAL1 +kDaikin152SwingVByte LITERAL1 +kDaikin152TempByte LITERAL1 +kDaikin152TempSize LITERAL1 kDaikin152ZeroSpace LITERAL1 kDaikin160BitMark LITERAL1 kDaikin160Bits LITERAL1 @@ -1233,9 +1313,7 @@ kDaikin160Gap LITERAL1 kDaikin160HdrMark LITERAL1 kDaikin160HdrSpace LITERAL1 kDaikin160MaskFan LITERAL1 -kDaikin160MaskMode LITERAL1 kDaikin160MaskSwingV LITERAL1 -kDaikin160MaskTemp LITERAL1 kDaikin160OneSpace LITERAL1 kDaikin160Section1Length LITERAL1 kDaikin160Section2Length LITERAL1 @@ -1247,6 +1325,8 @@ kDaikin160SwingVHighest LITERAL1 kDaikin160SwingVLow LITERAL1 kDaikin160SwingVLowest LITERAL1 kDaikin160SwingVMiddle LITERAL1 +kDaikin160TempOffset LITERAL1 +kDaikin160TempSize LITERAL1 kDaikin160ZeroSpace LITERAL1 kDaikin176BitMark LITERAL1 kDaikin176Bits LITERAL1 @@ -1266,8 +1346,6 @@ kDaikin176HdrMark LITERAL1 kDaikin176HdrSpace LITERAL1 kDaikin176MaskFan LITERAL1 kDaikin176MaskMode LITERAL1 -kDaikin176MaskSwingH LITERAL1 -kDaikin176MaskTemp LITERAL1 kDaikin176ModeButton LITERAL1 kDaikin176OneSpace LITERAL1 kDaikin176Section1Length LITERAL1 @@ -1276,6 +1354,8 @@ kDaikin176Sections LITERAL1 kDaikin176StateLength LITERAL1 kDaikin176SwingHAuto LITERAL1 kDaikin176SwingHOff LITERAL1 +kDaikin176TempOffset LITERAL1 +kDaikin176TempSize LITERAL1 kDaikin176ZeroSpace LITERAL1 kDaikin216BitMark LITERAL1 kDaikin216Bits LITERAL1 @@ -1292,36 +1372,49 @@ kDaikin216Gap LITERAL1 kDaikin216HdrMark LITERAL1 kDaikin216HdrSpace LITERAL1 kDaikin216MaskFan LITERAL1 -kDaikin216MaskMode LITERAL1 -kDaikin216MaskSwingH LITERAL1 -kDaikin216MaskSwingV LITERAL1 -kDaikin216MaskTemp LITERAL1 kDaikin216OneSpace LITERAL1 kDaikin216Section1Length LITERAL1 kDaikin216Section2Length LITERAL1 kDaikin216Sections LITERAL1 kDaikin216StateLength LITERAL1 +kDaikin216SwingOff LITERAL1 +kDaikin216SwingOn LITERAL1 +kDaikin216SwingSize LITERAL1 +kDaikin216TempOffset LITERAL1 +kDaikin216TempSize LITERAL1 kDaikin216ZeroSpace LITERAL1 -kDaikin2BeepMask LITERAL1 +kDaikin2BeepOffset LITERAL1 +kDaikin2BeepSize LITERAL1 kDaikin2BitClean LITERAL1 +kDaikin2BitCleanOffset LITERAL1 kDaikin2BitEye LITERAL1 kDaikin2BitEyeAuto LITERAL1 +kDaikin2BitEyeAutoOffset LITERAL1 +kDaikin2BitEyeOffset LITERAL1 kDaikin2BitFreshAir LITERAL1 kDaikin2BitFreshAirHigh LITERAL1 +kDaikin2BitFreshAirHighOffset LITERAL1 +kDaikin2BitFreshAirOffset LITERAL1 kDaikin2BitMark LITERAL1 kDaikin2BitMold LITERAL1 +kDaikin2BitMoldOffset LITERAL1 kDaikin2BitPower LITERAL1 +kDaikin2BitPowerOffset LITERAL1 kDaikin2BitPurify LITERAL1 +kDaikin2BitPurifyOffset LITERAL1 kDaikin2BitSleepTimer LITERAL1 +kDaikin2BitSleepTimerOffset LITERAL1 kDaikin2Bits LITERAL1 kDaikin2DefaultRepeat LITERAL1 +kDaikin2FanByte LITERAL1 kDaikin2Freq LITERAL1 kDaikin2Gap LITERAL1 kDaikin2HdrMark LITERAL1 kDaikin2HdrSpace LITERAL1 kDaikin2LeaderMark LITERAL1 kDaikin2LeaderSpace LITERAL1 -kDaikin2LightMask LITERAL1 +kDaikin2LightOffset LITERAL1 +kDaikin2LightSize LITERAL1 kDaikin2MinCoolTemp LITERAL1 kDaikin2OneSpace LITERAL1 kDaikin2Section1Length LITERAL1 @@ -1329,12 +1422,19 @@ kDaikin2Section2Length LITERAL1 kDaikin2Sections LITERAL1 kDaikin2StateLength LITERAL1 kDaikin2SwingHAuto LITERAL1 +kDaikin2SwingHLeft LITERAL1 +kDaikin2SwingHLeftMax LITERAL1 +kDaikin2SwingHMiddle LITERAL1 +kDaikin2SwingHRight LITERAL1 +kDaikin2SwingHRightMax LITERAL1 kDaikin2SwingHSwing LITERAL1 +kDaikin2SwingHWide LITERAL1 kDaikin2SwingVAuto LITERAL1 kDaikin2SwingVBreeze LITERAL1 kDaikin2SwingVCirculate LITERAL1 kDaikin2SwingVHigh LITERAL1 kDaikin2SwingVLow LITERAL1 +kDaikin2SwingVSwing LITERAL1 kDaikin2Tolerance LITERAL1 kDaikin2ZeroSpace LITERAL1 kDaikinAuto LITERAL1 @@ -1342,17 +1442,27 @@ kDaikinBeepLoud LITERAL1 kDaikinBeepOff LITERAL1 kDaikinBeepQuiet LITERAL1 kDaikinBitComfort LITERAL1 +kDaikinBitComfortOffset LITERAL1 kDaikinBitEcono LITERAL1 +kDaikinBitEconoOffset LITERAL1 kDaikinBitEye LITERAL1 kDaikinBitMark LITERAL1 kDaikinBitMold LITERAL1 +kDaikinBitMoldOffset LITERAL1 kDaikinBitOffTimer LITERAL1 +kDaikinBitOffTimerOffset LITERAL1 kDaikinBitOnTimer LITERAL1 +kDaikinBitOnTimerOffset LITERAL1 kDaikinBitPower LITERAL1 +kDaikinBitPowerOffset LITERAL1 kDaikinBitPowerful LITERAL1 +kDaikinBitPowerfulOffset LITERAL1 kDaikinBitSensor LITERAL1 +kDaikinBitSensorOffset LITERAL1 kDaikinBitSilent LITERAL1 +kDaikinBitSilentOffset LITERAL1 kDaikinBitWeeklyTimer LITERAL1 +kDaikinBitWeeklyTimerOffset LITERAL1 kDaikinBits LITERAL1 kDaikinBitsShort LITERAL1 kDaikinByteChecksum1 LITERAL1 @@ -1378,17 +1488,23 @@ kDaikinByteSilent LITERAL1 kDaikinByteSwingH LITERAL1 kDaikinByteTemp LITERAL1 kDaikinByteWeeklyTimer LITERAL1 +kDaikinClockMinsHighOffset LITERAL1 +kDaikinClockMinsHighSize LITERAL1 kDaikinCool LITERAL1 kDaikinCurBit LITERAL1 kDaikinCurIndex LITERAL1 kDaikinDefaultRepeat LITERAL1 +kDaikinDoWOffset LITERAL1 +kDaikinDoWSize LITERAL1 kDaikinDry LITERAL1 kDaikinFan LITERAL1 kDaikinFanAuto LITERAL1 kDaikinFanMax LITERAL1 kDaikinFanMed LITERAL1 kDaikinFanMin LITERAL1 +kDaikinFanOffset LITERAL1 kDaikinFanQuiet LITERAL1 +kDaikinFanSize LITERAL1 kDaikinFirstHeader64 LITERAL1 kDaikinGap LITERAL1 kDaikinHdrMark LITERAL1 @@ -1401,6 +1517,10 @@ kDaikinLightOff LITERAL1 kDaikinMarkExcess LITERAL1 kDaikinMaxTemp LITERAL1 kDaikinMinTemp LITERAL1 +kDaikinModeOffset LITERAL1 +kDaikinModeSize LITERAL1 +kDaikinOnTimerMinsHighOffset LITERAL1 +kDaikinOnTimerMinsHighSize LITERAL1 kDaikinOneSpace LITERAL1 kDaikinSection1Length LITERAL1 kDaikinSection2Length LITERAL1 @@ -1408,6 +1528,12 @@ kDaikinSection3Length LITERAL1 kDaikinSections LITERAL1 kDaikinStateLength LITERAL1 kDaikinStateLengthShort LITERAL1 +kDaikinSwingOff LITERAL1 +kDaikinSwingOffset LITERAL1 +kDaikinSwingOn LITERAL1 +kDaikinSwingSize LITERAL1 +kDaikinTempOffset LITERAL1 +kDaikinTempSize LITERAL1 kDaikinTolerance LITERAL1 kDaikinUnusedTime LITERAL1 kDaikinZeroSpace LITERAL1 @@ -1458,8 +1584,9 @@ kElectraAcFan LITERAL1 kElectraAcFanAuto LITERAL1 kElectraAcFanHigh LITERAL1 kElectraAcFanLow LITERAL1 -kElectraAcFanMask LITERAL1 kElectraAcFanMed LITERAL1 +kElectraAcFanOffset LITERAL1 +kElectraAcFanSize LITERAL1 kElectraAcHdrMark LITERAL1 kElectraAcHdrSpace LITERAL1 kElectraAcHeat LITERAL1 @@ -1467,14 +1594,18 @@ kElectraAcMaxTemp LITERAL1 kElectraAcMessageGap LITERAL1 kElectraAcMinRepeat LITERAL1 kElectraAcMinTemp LITERAL1 -kElectraAcModeMask LITERAL1 -kElectraAcOffsetTemp LITERAL1 +kElectraAcModeOffset LITERAL1 kElectraAcOneSpace LITERAL1 -kElectraAcPowerMask LITERAL1 +kElectraAcPowerOffset LITERAL1 kElectraAcStateLength LITERAL1 -kElectraAcSwingHMask LITERAL1 -kElectraAcSwingVMask LITERAL1 -kElectraAcTempMask LITERAL1 +kElectraAcSwingHOffset LITERAL1 +kElectraAcSwingOff LITERAL1 +kElectraAcSwingOn LITERAL1 +kElectraAcSwingSize LITERAL1 +kElectraAcSwingVOffset LITERAL1 +kElectraAcTempDelta LITERAL1 +kElectraAcTempOffset LITERAL1 +kElectraAcTempSize LITERAL1 kElectraAcZeroSpace LITERAL1 kFan LITERAL1 kFnvBasis32 LITERAL1 @@ -1482,6 +1613,7 @@ kFnvPrime32 LITERAL1 kFooter LITERAL1 kFujitsuAcBitMark LITERAL1 kFujitsuAcBits LITERAL1 +kFujitsuAcCleanOffset LITERAL1 kFujitsuAcCmdEcono LITERAL1 kFujitsuAcCmdPowerful LITERAL1 kFujitsuAcCmdStayOn LITERAL1 @@ -1496,6 +1628,8 @@ kFujitsuAcFanHigh LITERAL1 kFujitsuAcFanLow LITERAL1 kFujitsuAcFanMed LITERAL1 kFujitsuAcFanQuiet LITERAL1 +kFujitsuAcFanSize LITERAL1 +kFujitsuAcFilterOffset LITERAL1 kFujitsuAcHdrMark LITERAL1 kFujitsuAcHdrSpace LITERAL1 kFujitsuAcMaxTemp LITERAL1 @@ -1509,11 +1643,13 @@ kFujitsuAcModeDry LITERAL1 kFujitsuAcModeFan LITERAL1 kFujitsuAcModeHeat LITERAL1 kFujitsuAcOneSpace LITERAL1 +kFujitsuAcOutsideQuietOffset LITERAL1 kFujitsuAcStateLength LITERAL1 kFujitsuAcStateLengthShort LITERAL1 kFujitsuAcSwingBoth LITERAL1 kFujitsuAcSwingHoriz LITERAL1 kFujitsuAcSwingOff LITERAL1 +kFujitsuAcSwingSize LITERAL1 kFujitsuAcSwingVert LITERAL1 kFujitsuAcZeroSpace LITERAL1 kGicableBitMark LITERAL1 @@ -1533,7 +1669,9 @@ kGlobalCacheRptIndex LITERAL1 kGlobalCacheRptStartIndex LITERAL1 kGlobalCacheStartIndex LITERAL1 kGoodweatherAuto LITERAL1 +kGoodweatherBitAirFlow LITERAL1 kGoodweatherBitCommand LITERAL1 +kGoodweatherBitEOF LITERAL1 kGoodweatherBitFan LITERAL1 kGoodweatherBitLight LITERAL1 kGoodweatherBitMark LITERAL1 @@ -1556,32 +1694,30 @@ kGoodweatherCmdSwing LITERAL1 kGoodweatherCmdTimer LITERAL1 kGoodweatherCmdTurbo LITERAL1 kGoodweatherCmdUpTemp LITERAL1 -kGoodweatherCommandMask LITERAL1 +kGoodweatherCommandSize LITERAL1 kGoodweatherCool LITERAL1 kGoodweatherDry LITERAL1 +kGoodweatherEOFMask LITERAL1 +kGoodweatherExtraTolerance LITERAL1 kGoodweatherFan LITERAL1 kGoodweatherFanAuto LITERAL1 kGoodweatherFanHigh LITERAL1 kGoodweatherFanLow LITERAL1 -kGoodweatherFanMask LITERAL1 kGoodweatherFanMed LITERAL1 +kGoodweatherFanSize LITERAL1 kGoodweatherHdrMark LITERAL1 kGoodweatherHdrSpace LITERAL1 kGoodweatherHeat LITERAL1 -kGoodweatherLightMask LITERAL1 kGoodweatherMinRepeat LITERAL1 -kGoodweatherModeMask LITERAL1 kGoodweatherOneSpace LITERAL1 -kGoodweatherPowerMask LITERAL1 -kGoodweatherSleepMask LITERAL1 +kGoodweatherStateInit LITERAL1 kGoodweatherSwingFast LITERAL1 -kGoodweatherSwingMask LITERAL1 kGoodweatherSwingOff LITERAL1 +kGoodweatherSwingSize LITERAL1 kGoodweatherSwingSlow LITERAL1 -kGoodweatherTempMask LITERAL1 kGoodweatherTempMax LITERAL1 kGoodweatherTempMin LITERAL1 -kGoodweatherTurboMask LITERAL1 +kGoodweatherTempSize LITERAL1 kGoodweatherZeroSpace LITERAL1 kGpioUnused LITERAL1 kGreeAuto LITERAL1 @@ -1594,26 +1730,26 @@ kGreeDefaultRepeat LITERAL1 kGreeDry LITERAL1 kGreeFan LITERAL1 kGreeFanAuto LITERAL1 -kGreeFanMask LITERAL1 kGreeFanMax LITERAL1 kGreeFanMed LITERAL1 kGreeFanMin LITERAL1 +kGreeFanOffset LITERAL1 +kGreeFanSize LITERAL1 kGreeHdrMark LITERAL1 kGreeHdrSpace LITERAL1 kGreeHeat LITERAL1 -kGreeIFeelMask LITERAL1 -kGreeLightMask LITERAL1 +kGreeIFeelOffset LITERAL1 +kGreeLightOffset LITERAL1 kGreeMaxTemp LITERAL1 kGreeMinTemp LITERAL1 -kGreeModeMask LITERAL1 kGreeMsgSpace LITERAL1 kGreeOneSpace LITERAL1 -kGreePower1Mask LITERAL1 -kGreePower2Mask LITERAL1 -kGreeSleepMask LITERAL1 +kGreePower1Offset LITERAL1 +kGreePower2Offset LITERAL1 +kGreeSleepOffset LITERAL1 kGreeStateLength LITERAL1 kGreeSwingAuto LITERAL1 -kGreeSwingAutoMask LITERAL1 +kGreeSwingAutoOffset LITERAL1 kGreeSwingDown LITERAL1 kGreeSwingDownAuto LITERAL1 kGreeSwingLastPos LITERAL1 @@ -1621,19 +1757,20 @@ kGreeSwingMiddle LITERAL1 kGreeSwingMiddleAuto LITERAL1 kGreeSwingMiddleDown LITERAL1 kGreeSwingMiddleUp LITERAL1 -kGreeSwingPosMask LITERAL1 +kGreeSwingSize LITERAL1 kGreeSwingUp LITERAL1 kGreeSwingUpAuto LITERAL1 -kGreeTempMask LITERAL1 -kGreeTimer1Mask LITERAL1 -kGreeTimerEnabledBit LITERAL1 -kGreeTimerHalfHrBit LITERAL1 -kGreeTimerHoursMask LITERAL1 +kGreeTempSize LITERAL1 +kGreeTimerEnabledOffset LITERAL1 +kGreeTimerHalfHrOffset LITERAL1 +kGreeTimerHoursOffset LITERAL1 +kGreeTimerHoursSize LITERAL1 kGreeTimerMax LITERAL1 -kGreeTimerTensHrMask LITERAL1 -kGreeTurboMask LITERAL1 -kGreeWiFiMask LITERAL1 -kGreeXfanMask LITERAL1 +kGreeTimerTensHrOffset LITERAL1 +kGreeTimerTensHrSize LITERAL1 +kGreeTurboOffset LITERAL1 +kGreeWiFiOffset LITERAL1 +kGreeXfanOffset LITERAL1 kGreeZeroSpace LITERAL1 kHaierACBits LITERAL1 kHaierACStateLength LITERAL1 @@ -1663,19 +1800,28 @@ kHaierAcFanLow LITERAL1 kHaierAcFanMed LITERAL1 kHaierAcHdr LITERAL1 kHaierAcHdrGap LITERAL1 +kHaierAcHealthBitOffset LITERAL1 kHaierAcHeat LITERAL1 +kHaierAcHoursSize LITERAL1 kHaierAcMaxTemp LITERAL1 kHaierAcMaxTime LITERAL1 kHaierAcMinGap LITERAL1 kHaierAcMinTemp LITERAL1 -kHaierAcModeMask LITERAL1 +kHaierAcMinsSize LITERAL1 +kHaierAcModeOffset LITERAL1 +kHaierAcOffTimerOffset LITERAL1 +kHaierAcOnTimerOffset LITERAL1 kHaierAcOneSpace LITERAL1 kHaierAcPrefix LITERAL1 kHaierAcSleepBit LITERAL1 +kHaierAcSleepBitOffset LITERAL1 kHaierAcSwingChg LITERAL1 kHaierAcSwingDown LITERAL1 kHaierAcSwingOff LITERAL1 +kHaierAcSwingOffset LITERAL1 +kHaierAcSwingSize LITERAL1 kHaierAcSwingUp LITERAL1 +kHaierAcTimeOffset LITERAL1 kHaierAcYrw02Auto LITERAL1 kHaierAcYrw02ButtonFan LITERAL1 kHaierAcYrw02ButtonHealth LITERAL1 @@ -1694,10 +1840,16 @@ kHaierAcYrw02FanAuto LITERAL1 kHaierAcYrw02FanHigh LITERAL1 kHaierAcYrw02FanLow LITERAL1 kHaierAcYrw02FanMed LITERAL1 +kHaierAcYrw02FanOffset LITERAL1 +kHaierAcYrw02FanSize LITERAL1 +kHaierAcYrw02HealthOffset LITERAL1 kHaierAcYrw02Heat LITERAL1 +kHaierAcYrw02ModeOffset LITERAL1 kHaierAcYrw02Power LITERAL1 +kHaierAcYrw02PowerOffset LITERAL1 kHaierAcYrw02Prefix LITERAL1 kHaierAcYrw02Sleep LITERAL1 +kHaierAcYrw02SleepOffset LITERAL1 kHaierAcYrw02SwingAuto LITERAL1 kHaierAcYrw02SwingBottom LITERAL1 kHaierAcYrw02SwingDown LITERAL1 @@ -1707,10 +1859,13 @@ kHaierAcYrw02SwingTop LITERAL1 kHaierAcYrw02TurboHigh LITERAL1 kHaierAcYrw02TurboLow LITERAL1 kHaierAcYrw02TurboOff LITERAL1 +kHaierAcYrw02TurboOffset LITERAL1 +kHaierAcYrw02TurboSize LITERAL1 kHaierAcZeroSpace LITERAL1 kHeader LITERAL1 kHeat LITERAL1 kHigh LITERAL1 +kHighNibble LITERAL1 kHighest LITERAL1 kHitachiAc1Bits LITERAL1 kHitachiAc1HdrMark LITERAL1 @@ -1718,6 +1873,36 @@ kHitachiAc1HdrSpace LITERAL1 kHitachiAc1StateLength LITERAL1 kHitachiAc2Bits LITERAL1 kHitachiAc2StateLength LITERAL1 +kHitachiAc424BitMark LITERAL1 +kHitachiAc424Bits LITERAL1 +kHitachiAc424Cool LITERAL1 +kHitachiAc424Dry LITERAL1 +kHitachiAc424Fan LITERAL1 +kHitachiAc424FanAuto LITERAL1 +kHitachiAc424FanByte LITERAL1 +kHitachiAc424FanHigh LITERAL1 +kHitachiAc424FanLow LITERAL1 +kHitachiAc424FanMax LITERAL1 +kHitachiAc424FanMaxDry LITERAL1 +kHitachiAc424FanMedium LITERAL1 +kHitachiAc424FanMin LITERAL1 +kHitachiAc424FanTemp LITERAL1 +kHitachiAc424HdrMark LITERAL1 +kHitachiAc424HdrSpace LITERAL1 +kHitachiAc424Heat LITERAL1 +kHitachiAc424LdrMark LITERAL1 +kHitachiAc424LdrSpace LITERAL1 +kHitachiAc424MaxTemp LITERAL1 +kHitachiAc424MinTemp LITERAL1 +kHitachiAc424ModeByte LITERAL1 +kHitachiAc424OneSpace LITERAL1 +kHitachiAc424PowerByte LITERAL1 +kHitachiAc424PowerOffset LITERAL1 +kHitachiAc424StateLength LITERAL1 +kHitachiAc424TempByte LITERAL1 +kHitachiAc424TempOffset LITERAL1 +kHitachiAc424TempSize LITERAL1 +kHitachiAc424ZeroSpace LITERAL1 kHitachiAcAuto LITERAL1 kHitachiAcAutoTemp LITERAL1 kHitachiAcBitMark LITERAL1 @@ -1730,6 +1915,7 @@ kHitachiAcFanAuto LITERAL1 kHitachiAcFanHigh LITERAL1 kHitachiAcFanLow LITERAL1 kHitachiAcFanMed LITERAL1 +kHitachiAcFreq LITERAL1 kHitachiAcHdrMark LITERAL1 kHitachiAcHdrSpace LITERAL1 kHitachiAcHeat LITERAL1 @@ -1737,7 +1923,9 @@ kHitachiAcMaxTemp LITERAL1 kHitachiAcMinGap LITERAL1 kHitachiAcMinTemp LITERAL1 kHitachiAcOneSpace LITERAL1 +kHitachiAcPowerOffset LITERAL1 kHitachiAcStateLength LITERAL1 +kHitachiAcSwingOffset LITERAL1 kHitachiAcZeroSpace LITERAL1 kIdleState LITERAL1 kInaxBitMark LITERAL1 @@ -1767,8 +1955,8 @@ kJvcZeroSpace LITERAL1 kJvcZeroSpaceTicks LITERAL1 kKelvinatorAuto LITERAL1 kKelvinatorAutoTemp LITERAL1 -kKelvinatorBasicFanMask LITERAL1 kKelvinatorBasicFanMax LITERAL1 +kKelvinatorBasicFanSize LITERAL1 kKelvinatorBitMark LITERAL1 kKelvinatorBitMarkTicks LITERAL1 kKelvinatorBits LITERAL1 @@ -1780,10 +1968,10 @@ kKelvinatorDefaultRepeat LITERAL1 kKelvinatorDry LITERAL1 kKelvinatorFan LITERAL1 kKelvinatorFanAuto LITERAL1 -kKelvinatorFanMask LITERAL1 kKelvinatorFanMax LITERAL1 kKelvinatorFanMin LITERAL1 kKelvinatorFanOffset LITERAL1 +kKelvinatorFanSize LITERAL1 kKelvinatorGapSpace LITERAL1 kKelvinatorGapSpaceTicks LITERAL1 kKelvinatorHdrMark LITERAL1 @@ -1791,28 +1979,21 @@ kKelvinatorHdrMarkTicks LITERAL1 kKelvinatorHdrSpace LITERAL1 kKelvinatorHdrSpaceTicks LITERAL1 kKelvinatorHeat LITERAL1 -kKelvinatorIonFilter LITERAL1 kKelvinatorIonFilterOffset LITERAL1 -kKelvinatorLight LITERAL1 kKelvinatorLightOffset LITERAL1 kKelvinatorMaxTemp LITERAL1 kKelvinatorMinTemp LITERAL1 -kKelvinatorModeMask LITERAL1 +kKelvinatorModeOffset LITERAL1 kKelvinatorOneSpace LITERAL1 kKelvinatorOneSpaceTicks LITERAL1 -kKelvinatorPower LITERAL1 -kKelvinatorQuiet LITERAL1 +kKelvinatorPowerOffset LITERAL1 kKelvinatorQuietOffset LITERAL1 -kKelvinatorSleep1And3 LITERAL1 kKelvinatorStateLength LITERAL1 kKelvinatorTick LITERAL1 -kKelvinatorTurbo LITERAL1 kKelvinatorTurboOffset LITERAL1 -kKelvinatorVentSwing LITERAL1 -kKelvinatorVentSwingH LITERAL1 +kKelvinatorVentSwingHOffset LITERAL1 kKelvinatorVentSwingOffset LITERAL1 -kKelvinatorVentSwingV LITERAL1 -kKelvinatorXfan LITERAL1 +kKelvinatorVentSwingVOffset LITERAL1 kKelvinatorXfanOffset LITERAL1 kKelvinatorZeroSpace LITERAL1 kKelvinatorZeroSpaceTicks LITERAL1 @@ -1870,6 +2051,7 @@ kLgTick LITERAL1 kLgZeroSpace LITERAL1 kLgZeroSpaceTicks LITERAL1 kLow LITERAL1 +kLowNibble LITERAL1 kLowest LITERAL1 kLutronBits LITERAL1 kLutronDelta LITERAL1 @@ -1900,26 +2082,26 @@ kMaxTimeoutMs LITERAL1 kMedium LITERAL1 kMiddle LITERAL1 kMideaACAuto LITERAL1 -kMideaACCelsiusBit LITERAL1 -kMideaACChecksumMask LITERAL1 +kMideaACCelsiusOffset LITERAL1 kMideaACCool LITERAL1 kMideaACDry LITERAL1 kMideaACFan LITERAL1 kMideaACFanAuto LITERAL1 kMideaACFanHigh LITERAL1 kMideaACFanLow LITERAL1 -kMideaACFanMask LITERAL1 kMideaACFanMed LITERAL1 +kMideaACFanOffset LITERAL1 +kMideaACFanSize LITERAL1 kMideaACHeat LITERAL1 kMideaACMaxTempC LITERAL1 kMideaACMaxTempF LITERAL1 kMideaACMinTempC LITERAL1 kMideaACMinTempF LITERAL1 -kMideaACModeMask LITERAL1 -kMideaACPower LITERAL1 -kMideaACSleep LITERAL1 -kMideaACStateMask LITERAL1 -kMideaACTempMask LITERAL1 +kMideaACModeOffset LITERAL1 +kMideaACPowerOffset LITERAL1 +kMideaACSleepOffset LITERAL1 +kMideaACTempOffset LITERAL1 +kMideaACTempSize LITERAL1 kMideaACToggleSwingV LITERAL1 kMideaBitMark LITERAL1 kMideaBitMarkTicks LITERAL1 @@ -1938,6 +2120,91 @@ kMideaTolerance LITERAL1 kMideaZeroSpace LITERAL1 kMideaZeroSpaceTicks LITERAL1 kMin LITERAL1 +kMitsubishi112Auto LITERAL1 +kMitsubishi112BitMark LITERAL1 +kMitsubishi112Bits LITERAL1 +kMitsubishi112Cool LITERAL1 +kMitsubishi112Dry LITERAL1 +kMitsubishi112FanByte LITERAL1 +kMitsubishi112FanLow LITERAL1 +kMitsubishi112FanMax LITERAL1 +kMitsubishi112FanMed LITERAL1 +kMitsubishi112FanMin LITERAL1 +kMitsubishi112FanOffset LITERAL1 +kMitsubishi112FanQuiet LITERAL1 +kMitsubishi112FanSize LITERAL1 +kMitsubishi112Gap LITERAL1 +kMitsubishi112HdrMark LITERAL1 +kMitsubishi112HdrMarkTolerance LITERAL1 +kMitsubishi112HdrSpace LITERAL1 +kMitsubishi112Heat LITERAL1 +kMitsubishi112MaxTemp LITERAL1 +kMitsubishi112MinRepeat LITERAL1 +kMitsubishi112MinTemp LITERAL1 +kMitsubishi112ModeByte LITERAL1 +kMitsubishi112ModeOffset LITERAL1 +kMitsubishi112OneSpace LITERAL1 +kMitsubishi112PowerByte LITERAL1 +kMitsubishi112PowerOffset LITERAL1 +kMitsubishi112StateLength LITERAL1 +kMitsubishi112SwingHAuto LITERAL1 +kMitsubishi112SwingHByte LITERAL1 +kMitsubishi112SwingHLeft LITERAL1 +kMitsubishi112SwingHLeftMax LITERAL1 +kMitsubishi112SwingHMiddle LITERAL1 +kMitsubishi112SwingHOffset LITERAL1 +kMitsubishi112SwingHRight LITERAL1 +kMitsubishi112SwingHRightMax LITERAL1 +kMitsubishi112SwingHSize LITERAL1 +kMitsubishi112SwingHWide LITERAL1 +kMitsubishi112SwingVAuto LITERAL1 +kMitsubishi112SwingVByte LITERAL1 +kMitsubishi112SwingVHigh LITERAL1 +kMitsubishi112SwingVHighest LITERAL1 +kMitsubishi112SwingVLow LITERAL1 +kMitsubishi112SwingVLowest LITERAL1 +kMitsubishi112SwingVMiddle LITERAL1 +kMitsubishi112SwingVOffset LITERAL1 +kMitsubishi112SwingVSize LITERAL1 +kMitsubishi112TempByte LITERAL1 +kMitsubishi112TempSize LITERAL1 +kMitsubishi112ZeroSpace LITERAL1 +kMitsubishi136Auto LITERAL1 +kMitsubishi136BitMark LITERAL1 +kMitsubishi136Bits LITERAL1 +kMitsubishi136Cool LITERAL1 +kMitsubishi136Dry LITERAL1 +kMitsubishi136Fan LITERAL1 +kMitsubishi136FanByte LITERAL1 +kMitsubishi136FanLow LITERAL1 +kMitsubishi136FanMax LITERAL1 +kMitsubishi136FanMed LITERAL1 +kMitsubishi136FanMin LITERAL1 +kMitsubishi136FanOffset LITERAL1 +kMitsubishi136FanQuiet LITERAL1 +kMitsubishi136FanSize LITERAL1 +kMitsubishi136Gap LITERAL1 +kMitsubishi136HdrMark LITERAL1 +kMitsubishi136HdrSpace LITERAL1 +kMitsubishi136Heat LITERAL1 +kMitsubishi136MaxTemp LITERAL1 +kMitsubishi136MinRepeat LITERAL1 +kMitsubishi136MinTemp LITERAL1 +kMitsubishi136ModeByte LITERAL1 +kMitsubishi136ModeOffset LITERAL1 +kMitsubishi136OneSpace LITERAL1 +kMitsubishi136PowerBit LITERAL1 +kMitsubishi136PowerByte LITERAL1 +kMitsubishi136PowerOffset LITERAL1 +kMitsubishi136StateLength LITERAL1 +kMitsubishi136SwingVAuto LITERAL1 +kMitsubishi136SwingVByte LITERAL1 +kMitsubishi136SwingVHigh LITERAL1 +kMitsubishi136SwingVHighest LITERAL1 +kMitsubishi136SwingVLow LITERAL1 +kMitsubishi136SwingVLowest LITERAL1 +kMitsubishi136TempByte LITERAL1 +kMitsubishi136ZeroSpace LITERAL1 kMitsubishi2BitMark LITERAL1 kMitsubishi2HdrMark LITERAL1 kMitsubishi2HdrSpace LITERAL1 @@ -1951,19 +2218,25 @@ kMitsubishiAcAuto LITERAL1 kMitsubishiAcBitMark LITERAL1 kMitsubishiAcCool LITERAL1 kMitsubishiAcDry LITERAL1 +kMitsubishiAcExtraTolerance LITERAL1 kMitsubishiAcFanAuto LITERAL1 +kMitsubishiAcFanAutoOffset LITERAL1 kMitsubishiAcFanMax LITERAL1 +kMitsubishiAcFanOffset LITERAL1 kMitsubishiAcFanQuiet LITERAL1 kMitsubishiAcFanRealMax LITERAL1 kMitsubishiAcFanSilent LITERAL1 +kMitsubishiAcFanSize LITERAL1 kMitsubishiAcHdrMark LITERAL1 kMitsubishiAcHdrSpace LITERAL1 kMitsubishiAcHeat LITERAL1 kMitsubishiAcMaxTemp LITERAL1 kMitsubishiAcMinTemp LITERAL1 +kMitsubishiAcModeOffset LITERAL1 kMitsubishiAcNoTimer LITERAL1 kMitsubishiAcOneSpace LITERAL1 kMitsubishiAcPower LITERAL1 +kMitsubishiAcPowerOffset LITERAL1 kMitsubishiAcRptMark LITERAL1 kMitsubishiAcRptSpace LITERAL1 kMitsubishiAcStartStopTimer LITERAL1 @@ -1971,6 +2244,9 @@ kMitsubishiAcStartTimer LITERAL1 kMitsubishiAcStopTimer LITERAL1 kMitsubishiAcVaneAuto LITERAL1 kMitsubishiAcVaneAutoMove LITERAL1 +kMitsubishiAcVaneBitOffset LITERAL1 +kMitsubishiAcVaneOffset LITERAL1 +kMitsubishiAcVaneSize LITERAL1 kMitsubishiAcWideVaneAuto LITERAL1 kMitsubishiAcZeroSpace LITERAL1 kMitsubishiBitMark LITERAL1 @@ -1990,7 +2266,6 @@ kMitsubishiHeavy152SwingHAuto LITERAL1 kMitsubishiHeavy152SwingHLeft LITERAL1 kMitsubishiHeavy152SwingHLeftMax LITERAL1 kMitsubishiHeavy152SwingHLeftRight LITERAL1 -kMitsubishiHeavy152SwingHMask LITERAL1 kMitsubishiHeavy152SwingHMiddle LITERAL1 kMitsubishiHeavy152SwingHOff LITERAL1 kMitsubishiHeavy152SwingHRight LITERAL1 @@ -2001,18 +2276,20 @@ kMitsubishiHeavy152SwingVHigh LITERAL1 kMitsubishiHeavy152SwingVHighest LITERAL1 kMitsubishiHeavy152SwingVLow LITERAL1 kMitsubishiHeavy152SwingVLowest LITERAL1 -kMitsubishiHeavy152SwingVMask LITERAL1 kMitsubishiHeavy152SwingVMiddle LITERAL1 kMitsubishiHeavy152SwingVOff LITERAL1 +kMitsubishiHeavy152SwingVOffset LITERAL1 +kMitsubishiHeavy152SwingVSize LITERAL1 kMitsubishiHeavy3DMask LITERAL1 kMitsubishiHeavy88Bits LITERAL1 -kMitsubishiHeavy88CleanBit LITERAL1 +kMitsubishiHeavy88CleanOffset LITERAL1 kMitsubishiHeavy88FanAuto LITERAL1 kMitsubishiHeavy88FanEcono LITERAL1 kMitsubishiHeavy88FanHigh LITERAL1 kMitsubishiHeavy88FanLow LITERAL1 -kMitsubishiHeavy88FanMask LITERAL1 kMitsubishiHeavy88FanMed LITERAL1 +kMitsubishiHeavy88FanOffset LITERAL1 +kMitsubishiHeavy88FanSize LITERAL1 kMitsubishiHeavy88FanTurbo LITERAL1 kMitsubishiHeavy88MinRepeat LITERAL1 kMitsubishiHeavy88StateLength LITERAL1 @@ -2021,43 +2298,44 @@ kMitsubishiHeavy88SwingHAuto LITERAL1 kMitsubishiHeavy88SwingHLeft LITERAL1 kMitsubishiHeavy88SwingHLeftMax LITERAL1 kMitsubishiHeavy88SwingHLeftRight LITERAL1 -kMitsubishiHeavy88SwingHMask LITERAL1 kMitsubishiHeavy88SwingHMiddle LITERAL1 kMitsubishiHeavy88SwingHOff LITERAL1 +kMitsubishiHeavy88SwingHOffset1 LITERAL1 +kMitsubishiHeavy88SwingHOffset2 LITERAL1 kMitsubishiHeavy88SwingHRight LITERAL1 kMitsubishiHeavy88SwingHRightLeft LITERAL1 kMitsubishiHeavy88SwingHRightMax LITERAL1 +kMitsubishiHeavy88SwingHSize LITERAL1 kMitsubishiHeavy88SwingVAuto LITERAL1 +kMitsubishiHeavy88SwingVByte5Offset LITERAL1 +kMitsubishiHeavy88SwingVByte5Size LITERAL1 +kMitsubishiHeavy88SwingVByte7Offset LITERAL1 +kMitsubishiHeavy88SwingVByte7Size LITERAL1 kMitsubishiHeavy88SwingVHigh LITERAL1 kMitsubishiHeavy88SwingVHighest LITERAL1 kMitsubishiHeavy88SwingVLow LITERAL1 kMitsubishiHeavy88SwingVLowest LITERAL1 -kMitsubishiHeavy88SwingVMask LITERAL1 -kMitsubishiHeavy88SwingVMaskByte5 LITERAL1 -kMitsubishiHeavy88SwingVMaskByte7 LITERAL1 kMitsubishiHeavy88SwingVMiddle LITERAL1 kMitsubishiHeavy88SwingVOff LITERAL1 kMitsubishiHeavyAuto LITERAL1 kMitsubishiHeavyBitMark LITERAL1 -kMitsubishiHeavyCleanBit LITERAL1 +kMitsubishiHeavyCleanOffset LITERAL1 kMitsubishiHeavyCool LITERAL1 kMitsubishiHeavyDry LITERAL1 kMitsubishiHeavyFan LITERAL1 -kMitsubishiHeavyFanMask LITERAL1 -kMitsubishiHeavyFilterBit LITERAL1 +kMitsubishiHeavyFilterOffset LITERAL1 kMitsubishiHeavyGap LITERAL1 kMitsubishiHeavyHdrMark LITERAL1 kMitsubishiHeavyHdrSpace LITERAL1 kMitsubishiHeavyHeat LITERAL1 kMitsubishiHeavyMaxTemp LITERAL1 kMitsubishiHeavyMinTemp LITERAL1 -kMitsubishiHeavyModeMask LITERAL1 -kMitsubishiHeavyNightBit LITERAL1 +kMitsubishiHeavyModeOffset LITERAL1 +kMitsubishiHeavyNightOffset LITERAL1 kMitsubishiHeavyOneSpace LITERAL1 -kMitsubishiHeavyPowerBit LITERAL1 +kMitsubishiHeavyPowerOffset LITERAL1 kMitsubishiHeavySigLength LITERAL1 -kMitsubishiHeavySilentBit LITERAL1 -kMitsubishiHeavyTempMask LITERAL1 +kMitsubishiHeavySilentOffset LITERAL1 kMitsubishiHeavyZeroSpace LITERAL1 kMitsubishiHeavyZjsSig LITERAL1 kMitsubishiHeavyZmsSig LITERAL1 @@ -2071,6 +2349,7 @@ kMitsubishiOneSpaceTicks LITERAL1 kMitsubishiTick LITERAL1 kMitsubishiZeroSpace LITERAL1 kMitsubishiZeroSpaceTicks LITERAL1 +kModeBitsSize LITERAL1 kNECBits LITERAL1 kNecBitMark LITERAL1 kNecBitMarkTicks LITERAL1 @@ -2090,7 +2369,7 @@ kNecRptSpaceTicks LITERAL1 kNecTick LITERAL1 kNecZeroSpace LITERAL1 kNecZeroSpaceTicks LITERAL1 -kNeoclima8CHeatMask LITERAL1 +kNeoclima8CHeatOffset LITERAL1 kNeoclimaAuto LITERAL1 kNeoclimaBitMark LITERAL1 kNeoclimaBits LITERAL1 @@ -2103,9 +2382,10 @@ kNeoclimaButtonFresh LITERAL1 kNeoclimaButtonHold LITERAL1 kNeoclimaButtonIon LITERAL1 kNeoclimaButtonLight LITERAL1 -kNeoclimaButtonMask LITERAL1 kNeoclimaButtonMode LITERAL1 +kNeoclimaButtonOffset LITERAL1 kNeoclimaButtonPower LITERAL1 +kNeoclimaButtonSize LITERAL1 kNeoclimaButtonSleep LITERAL1 kNeoclimaButtonSwing LITERAL1 kNeoclimaButtonTempDown LITERAL1 @@ -2113,37 +2393,41 @@ kNeoclimaButtonTempUp LITERAL1 kNeoclimaButtonTurbo LITERAL1 kNeoclimaCool LITERAL1 kNeoclimaDry LITERAL1 -kNeoclimaEyeMask LITERAL1 +kNeoclimaEyeOffset LITERAL1 kNeoclimaFan LITERAL1 kNeoclimaFanAuto LITERAL1 kNeoclimaFanHigh LITERAL1 kNeoclimaFanLow LITERAL1 -kNeoclimaFanMask LITERAL1 kNeoclimaFanMed LITERAL1 +kNeoclimaFanOffest LITERAL1 +kNeoclimaFanSize LITERAL1 kNeoclimaFollowMe LITERAL1 -kNeoclimaFreshMask LITERAL1 +kNeoclimaFreshOffset LITERAL1 kNeoclimaHdrMark LITERAL1 kNeoclimaHdrSpace LITERAL1 kNeoclimaHeat LITERAL1 -kNeoclimaHoldMask LITERAL1 -kNeoclimaIonMask LITERAL1 -kNeoclimaLightMask LITERAL1 +kNeoclimaHoldOffset LITERAL1 +kNeoclimaIonOffset LITERAL1 +kNeoclimaLightOffset LITERAL1 kNeoclimaMaxTemp LITERAL1 kNeoclimaMinGap LITERAL1 kNeoclimaMinRepeat LITERAL1 kNeoclimaMinTemp LITERAL1 -kNeoclimaModeMask LITERAL1 +kNeoclimaModeOffset LITERAL1 kNeoclimaOneSpace LITERAL1 -kNeoclimaPowerMask LITERAL1 -kNeoclimaSleepMask LITERAL1 +kNeoclimaPowerOffset LITERAL1 +kNeoclimaSleepOffset LITERAL1 kNeoclimaStateLength LITERAL1 -kNeoclimaSwingHMask LITERAL1 -kNeoclimaSwingVMask LITERAL1 +kNeoclimaSwingHOffset LITERAL1 kNeoclimaSwingVOff LITERAL1 +kNeoclimaSwingVOffset LITERAL1 kNeoclimaSwingVOn LITERAL1 -kNeoclimaTempMask LITERAL1 -kNeoclimaTurboMask LITERAL1 +kNeoclimaSwingVSize LITERAL1 +kNeoclimaTempOffset LITERAL1 +kNeoclimaTempSize LITERAL1 +kNeoclimaTurboOffset LITERAL1 kNeoclimaZeroSpace LITERAL1 +kNibbleSize LITERAL1 kNikaiBitMark LITERAL1 kNikaiBitMarkTicks LITERAL1 kNikaiBits LITERAL1 @@ -2169,22 +2453,22 @@ kPanasonicAcDry LITERAL1 kPanasonicAcExcess LITERAL1 kPanasonicAcFan LITERAL1 kPanasonicAcFanAuto LITERAL1 +kPanasonicAcFanDelta LITERAL1 kPanasonicAcFanMax LITERAL1 kPanasonicAcFanMed LITERAL1 kPanasonicAcFanMin LITERAL1 kPanasonicAcFanModeTemp LITERAL1 -kPanasonicAcFanOffset LITERAL1 kPanasonicAcHeat LITERAL1 kPanasonicAcMaxTemp LITERAL1 kPanasonicAcMessageGap LITERAL1 kPanasonicAcMinTemp LITERAL1 -kPanasonicAcOffTimer LITERAL1 -kPanasonicAcOnTimer LITERAL1 -kPanasonicAcPower LITERAL1 -kPanasonicAcPowerful LITERAL1 -kPanasonicAcPowerfulCkp LITERAL1 -kPanasonicAcQuiet LITERAL1 -kPanasonicAcQuietCkp LITERAL1 +kPanasonicAcOffTimerOffset LITERAL1 +kPanasonicAcOnTimerOffset LITERAL1 +kPanasonicAcPowerOffset LITERAL1 +kPanasonicAcPowerfulCkpOffset LITERAL1 +kPanasonicAcPowerfulOffset LITERAL1 +kPanasonicAcQuietCkpOffset LITERAL1 +kPanasonicAcQuietOffset LITERAL1 kPanasonicAcSection1Length LITERAL1 kPanasonicAcSectionGap LITERAL1 kPanasonicAcShortBits LITERAL1 @@ -2197,9 +2481,16 @@ kPanasonicAcSwingHLeft LITERAL1 kPanasonicAcSwingHMiddle LITERAL1 kPanasonicAcSwingHRight LITERAL1 kPanasonicAcSwingVAuto LITERAL1 -kPanasonicAcSwingVDown LITERAL1 -kPanasonicAcSwingVUp LITERAL1 +kPanasonicAcSwingVHigh LITERAL1 +kPanasonicAcSwingVHighest LITERAL1 +kPanasonicAcSwingVLow LITERAL1 +kPanasonicAcSwingVLowest LITERAL1 +kPanasonicAcSwingVMiddle LITERAL1 +kPanasonicAcTempOffset LITERAL1 +kPanasonicAcTempSize LITERAL1 kPanasonicAcTimeMax LITERAL1 +kPanasonicAcTimeOverflowSize LITERAL1 +kPanasonicAcTimeSize LITERAL1 kPanasonicAcTimeSpecial LITERAL1 kPanasonicAcTolerance LITERAL1 kPanasonicBitMark LITERAL1 @@ -2303,11 +2594,11 @@ kSamsung36Bits LITERAL1 kSamsungACSectionLength LITERAL1 kSamsungAcAuto LITERAL1 kSamsungAcAutoTemp LITERAL1 -kSamsungAcBeepMask LITERAL1 +kSamsungAcBeepOffset LITERAL1 kSamsungAcBitMark LITERAL1 kSamsungAcBits LITERAL1 -kSamsungAcCleanMask10 LITERAL1 -kSamsungAcCleanMask11 LITERAL1 +kSamsungAcClean10Offset LITERAL1 +kSamsungAcClean11Offset LITERAL1 kSamsungAcCool LITERAL1 kSamsungAcDefaultRepeat LITERAL1 kSamsungAcDry LITERAL1 @@ -2318,32 +2609,35 @@ kSamsungAcFanAuto LITERAL1 kSamsungAcFanAuto2 LITERAL1 kSamsungAcFanHigh LITERAL1 kSamsungAcFanLow LITERAL1 -kSamsungAcFanMask LITERAL1 kSamsungAcFanMed LITERAL1 +kSamsungAcFanOffest LITERAL1 +kSamsungAcFanSize LITERAL1 kSamsungAcFanTurbo LITERAL1 kSamsungAcHdrMark LITERAL1 kSamsungAcHdrSpace LITERAL1 kSamsungAcHeat LITERAL1 kSamsungAcMaxTemp LITERAL1 kSamsungAcMinTemp LITERAL1 -kSamsungAcModeMask LITERAL1 +kSamsungAcModeOffset LITERAL1 kSamsungAcOneSpace LITERAL1 -kSamsungAcPowerMask1 LITERAL1 -kSamsungAcPowerMask6 LITERAL1 +kSamsungAcPower1Offset LITERAL1 +kSamsungAcPower6Offset LITERAL1 +kSamsungAcPower6Size LITERAL1 kSamsungAcPowerSection LITERAL1 -kSamsungAcPowerfulMask10 LITERAL1 +kSamsungAcPowerful10Offset LITERAL1 +kSamsungAcPowerful10Size LITERAL1 kSamsungAcPowerfulMask8 LITERAL1 -kSamsungAcQuietMask1 LITERAL1 -kSamsungAcQuietMask5 LITERAL1 +kSamsungAcQuiet1Offset LITERAL1 +kSamsungAcQuiet5Offset LITERAL1 kSamsungAcSectionGap LITERAL1 kSamsungAcSectionMark LITERAL1 kSamsungAcSectionSpace LITERAL1 kSamsungAcSections LITERAL1 kSamsungAcStateLength LITERAL1 -kSamsungAcSwingMask LITERAL1 kSamsungAcSwingMove LITERAL1 +kSamsungAcSwingOffset LITERAL1 +kSamsungAcSwingSize LITERAL1 kSamsungAcSwingStop LITERAL1 -kSamsungAcTempMask LITERAL1 kSamsungAcZeroSpace LITERAL1 kSamsungBitMark LITERAL1 kSamsungBitMarkTicks LITERAL1 @@ -2383,10 +2677,11 @@ kSanyoSa8650bOneMark LITERAL1 kSanyoSa8650bRptLength LITERAL1 kSanyoSa8650bZeroMark LITERAL1 kSharpAcAuto LITERAL1 -kSharpAcBitFanManual LITERAL1 +kSharpAcBitFanManualOffset LITERAL1 kSharpAcBitMark LITERAL1 -kSharpAcBitPower LITERAL1 -kSharpAcBitTempManual LITERAL1 +kSharpAcBitModeNonAutoOffset LITERAL1 +kSharpAcBitPowerOffset LITERAL1 +kSharpAcBitTempManualOffset LITERAL1 kSharpAcBits LITERAL1 kSharpAcByteFan LITERAL1 kSharpAcByteManual LITERAL1 @@ -2401,15 +2696,15 @@ kSharpAcFanHigh LITERAL1 kSharpAcFanMax LITERAL1 kSharpAcFanMed LITERAL1 kSharpAcFanMin LITERAL1 +kSharpAcFanOffset LITERAL1 +kSharpAcFanSize LITERAL1 kSharpAcGap LITERAL1 kSharpAcHdrMark LITERAL1 kSharpAcHdrSpace LITERAL1 kSharpAcHeat LITERAL1 -kSharpAcMaskFan LITERAL1 -kSharpAcMaskMode LITERAL1 -kSharpAcMaskTemp LITERAL1 kSharpAcMaxTemp LITERAL1 kSharpAcMinTemp LITERAL1 +kSharpAcModeSize LITERAL1 kSharpAcOneSpace LITERAL1 kSharpAcStateLength LITERAL1 kSharpAcZeroSpace LITERAL1 @@ -2455,13 +2750,12 @@ kStartOffset LITERAL1 kStateSizeMax LITERAL1 kStopState LITERAL1 kTcl112AcAuto LITERAL1 -kTcl112AcBitEcono LITERAL1 -kTcl112AcBitHealth LITERAL1 -kTcl112AcBitLight LITERAL1 +kTcl112AcBitEconoOffset LITERAL1 +kTcl112AcBitHealthOffset LITERAL1 +kTcl112AcBitLightOffset LITERAL1 kTcl112AcBitMark LITERAL1 -kTcl112AcBitSwingH LITERAL1 -kTcl112AcBitSwingV LITERAL1 -kTcl112AcBitTurbo LITERAL1 +kTcl112AcBitSwingHOffset LITERAL1 +kTcl112AcBitTurboOffset LITERAL1 kTcl112AcBits LITERAL1 kTcl112AcCool LITERAL1 kTcl112AcDefaultRepeat LITERAL1 @@ -2470,16 +2764,22 @@ kTcl112AcFan LITERAL1 kTcl112AcFanAuto LITERAL1 kTcl112AcFanHigh LITERAL1 kTcl112AcFanLow LITERAL1 -kTcl112AcFanMask LITERAL1 kTcl112AcFanMed LITERAL1 +kTcl112AcFanSize LITERAL1 kTcl112AcGap LITERAL1 -kTcl112AcHalfDegree LITERAL1 +kTcl112AcHalfDegreeOffset LITERAL1 kTcl112AcHdrMark LITERAL1 +kTcl112AcHdrMarkTolerance LITERAL1 kTcl112AcHdrSpace LITERAL1 kTcl112AcHeat LITERAL1 +kTcl112AcModeSize LITERAL1 kTcl112AcOneSpace LITERAL1 -kTcl112AcPowerMask LITERAL1 +kTcl112AcPowerOffset LITERAL1 kTcl112AcStateLength LITERAL1 +kTcl112AcSwingVOff LITERAL1 +kTcl112AcSwingVOffset LITERAL1 +kTcl112AcSwingVOn LITERAL1 +kTcl112AcSwingVSize LITERAL1 kTcl112AcTempMax LITERAL1 kTcl112AcTempMin LITERAL1 kTcl112AcTolerance LITERAL1 @@ -2494,28 +2794,32 @@ kTecoFan LITERAL1 kTecoFanAuto LITERAL1 kTecoFanHigh LITERAL1 kTecoFanLow LITERAL1 -kTecoFanMask LITERAL1 kTecoFanMed LITERAL1 +kTecoFanOffset LITERAL1 +kTecoFanSize LITERAL1 kTecoGap LITERAL1 kTecoHdrMark LITERAL1 kTecoHdrSpace LITERAL1 kTecoHeat LITERAL1 -kTecoHumid LITERAL1 -kTecoLight LITERAL1 +kTecoHumidOffset LITERAL1 +kTecoLightOffset LITERAL1 kTecoMaxTemp LITERAL1 kTecoMinTemp LITERAL1 -kTecoModeMask LITERAL1 +kTecoModeOffset LITERAL1 kTecoOneSpace LITERAL1 -kTecoPower LITERAL1 +kTecoPowerOffset LITERAL1 kTecoReset LITERAL1 -kTecoSave LITERAL1 -kTecoSleep LITERAL1 -kTecoSwing LITERAL1 -kTecoTempMask LITERAL1 -kTecoTimerHalfH LITERAL1 -kTecoTimerOn LITERAL1 -kTecoTimerTenHr LITERAL1 -kTecoTimerUniHr LITERAL1 +kTecoSaveOffset LITERAL1 +kTecoSleepOffset LITERAL1 +kTecoSwingOffset LITERAL1 +kTecoTempOffset LITERAL1 +kTecoTempSize LITERAL1 +kTecoTimerHalfHourOffset LITERAL1 +kTecoTimerOnOffset LITERAL1 +kTecoTimerTensHoursOffset LITERAL1 +kTecoTimerTensHoursSize LITERAL1 +kTecoTimerUnitHoursOffset LITERAL1 +kTecoTimerUnitHoursSize LITERAL1 kTecoZeroSpace LITERAL1 kTimeoutMs LITERAL1 kTolerance LITERAL1 @@ -2530,14 +2834,20 @@ kToshibaAcFanAuto LITERAL1 kToshibaAcFanMax LITERAL1 kToshibaAcFanMed LITERAL1 kToshibaAcFanMin LITERAL1 +kToshibaAcFanOffset LITERAL1 +kToshibaAcFanSize LITERAL1 kToshibaAcHdrMark LITERAL1 kToshibaAcHdrSpace LITERAL1 kToshibaAcHeat LITERAL1 kToshibaAcMaxTemp LITERAL1 kToshibaAcMinGap LITERAL1 kToshibaAcMinTemp LITERAL1 +kToshibaAcModeOffset LITERAL1 +kToshibaAcModeSize LITERAL1 kToshibaAcOneSpace LITERAL1 -kToshibaAcPower LITERAL1 +kToshibaAcPowerOffset LITERAL1 +kToshibaAcTempOffset LITERAL1 +kToshibaAcTempSize LITERAL1 kToshibaAcZeroSpace LITERAL1 kTrotecAuto LITERAL1 kTrotecBitMark LITERAL1 @@ -2550,6 +2860,8 @@ kTrotecFan LITERAL1 kTrotecFanHigh LITERAL1 kTrotecFanLow LITERAL1 kTrotecFanMed LITERAL1 +kTrotecFanOffset LITERAL1 +kTrotecFanSize LITERAL1 kTrotecGap LITERAL1 kTrotecGapEnd LITERAL1 kTrotecHdrMark LITERAL1 @@ -2559,19 +2871,23 @@ kTrotecIntro2 LITERAL1 kTrotecMaxTemp LITERAL1 kTrotecMaxTimer LITERAL1 kTrotecMinTemp LITERAL1 +kTrotecModeOffset LITERAL1 +kTrotecModeSize LITERAL1 kTrotecOneSpace LITERAL1 -kTrotecPowerBit LITERAL1 -kTrotecSleepBit LITERAL1 +kTrotecPowerBitOffset LITERAL1 +kTrotecSleepBitOffset LITERAL1 kTrotecStateLength LITERAL1 -kTrotecTimerBit LITERAL1 +kTrotecTempOffset LITERAL1 +kTrotecTempSize LITERAL1 +kTrotecTimerBitOffset LITERAL1 kTrotecZeroSpace LITERAL1 kUnknownThreshold LITERAL1 kUseDefTol LITERAL1 kVestelAcAuto LITERAL1 kVestelAcBitMark LITERAL1 kVestelAcBits LITERAL1 -kVestelAcCRCMask LITERAL1 kVestelAcChecksumOffset LITERAL1 +kVestelAcChecksumSize LITERAL1 kVestelAcCool LITERAL1 kVestelAcDry LITERAL1 kVestelAcFan LITERAL1 @@ -2582,16 +2898,19 @@ kVestelAcFanHigh LITERAL1 kVestelAcFanLow LITERAL1 kVestelAcFanMed LITERAL1 kVestelAcFanOffset LITERAL1 +kVestelAcFanSize LITERAL1 kVestelAcHdrMark LITERAL1 kVestelAcHdrSpace LITERAL1 kVestelAcHeat LITERAL1 kVestelAcHourOffset LITERAL1 +kVestelAcHourSize LITERAL1 kVestelAcIon LITERAL1 kVestelAcIonOffset LITERAL1 kVestelAcMaxTemp LITERAL1 kVestelAcMinTempC LITERAL1 kVestelAcMinTempH LITERAL1 kVestelAcMinuteOffset LITERAL1 +kVestelAcMinuteSize LITERAL1 kVestelAcModeOffset LITERAL1 kVestelAcNormal LITERAL1 kVestelAcOffTimeOffset LITERAL1 @@ -2600,6 +2919,7 @@ kVestelAcOnTimeOffset LITERAL1 kVestelAcOnTimerFlagOffset LITERAL1 kVestelAcOneSpace LITERAL1 kVestelAcPowerOffset LITERAL1 +kVestelAcPowerSize LITERAL1 kVestelAcSleep LITERAL1 kVestelAcStateDefault LITERAL1 kVestelAcSwing LITERAL1 @@ -2607,11 +2927,14 @@ kVestelAcSwingOffset LITERAL1 kVestelAcTempOffset LITERAL1 kVestelAcTimeStateDefault LITERAL1 kVestelAcTimerFlagOffset LITERAL1 +kVestelAcTimerHourSize LITERAL1 +kVestelAcTimerMinsSize LITERAL1 +kVestelAcTimerSize LITERAL1 kVestelAcTolerance LITERAL1 kVestelAcTurbo LITERAL1 kVestelAcTurboSleepOffset LITERAL1 kVestelAcZeroSpace LITERAL1 -kWhirlpoolAcAltTempMask LITERAL1 +kWhirlpoolAcAltTempOffset LITERAL1 kWhirlpoolAcAltTempPos LITERAL1 kWhirlpoolAcAuto LITERAL1 kWhirlpoolAcAutoTemp LITERAL1 @@ -2640,37 +2963,39 @@ kWhirlpoolAcFan LITERAL1 kWhirlpoolAcFanAuto LITERAL1 kWhirlpoolAcFanHigh LITERAL1 kWhirlpoolAcFanLow LITERAL1 -kWhirlpoolAcFanMask LITERAL1 kWhirlpoolAcFanMedium LITERAL1 +kWhirlpoolAcFanOffset LITERAL1 kWhirlpoolAcFanPos LITERAL1 +kWhirlpoolAcFanSize LITERAL1 kWhirlpoolAcGap LITERAL1 kWhirlpoolAcHdrMark LITERAL1 kWhirlpoolAcHdrSpace LITERAL1 kWhirlpoolAcHeat LITERAL1 -kWhirlpoolAcHourMask LITERAL1 -kWhirlpoolAcLightMask LITERAL1 +kWhirlpoolAcHourOffset LITERAL1 +kWhirlpoolAcHourSize LITERAL1 +kWhirlpoolAcLightOffset LITERAL1 kWhirlpoolAcMaxTemp LITERAL1 kWhirlpoolAcMinGap LITERAL1 kWhirlpoolAcMinTemp LITERAL1 -kWhirlpoolAcMinuteMask LITERAL1 -kWhirlpoolAcModeMask LITERAL1 +kWhirlpoolAcMinuteOffset LITERAL1 +kWhirlpoolAcMinuteSize LITERAL1 +kWhirlpoolAcModeOffset LITERAL1 kWhirlpoolAcModePos LITERAL1 kWhirlpoolAcOffTimerPos LITERAL1 kWhirlpoolAcOnTimerPos LITERAL1 kWhirlpoolAcOneSpace LITERAL1 -kWhirlpoolAcPowerToggleMask LITERAL1 +kWhirlpoolAcPowerToggleOffset LITERAL1 kWhirlpoolAcPowerTogglePos LITERAL1 kWhirlpoolAcSections LITERAL1 -kWhirlpoolAcSleepMask LITERAL1 +kWhirlpoolAcSleepOffset LITERAL1 kWhirlpoolAcSleepPos LITERAL1 kWhirlpoolAcStateLength LITERAL1 kWhirlpoolAcSuperMask LITERAL1 kWhirlpoolAcSuperPos LITERAL1 -kWhirlpoolAcSwing1Mask LITERAL1 -kWhirlpoolAcSwing2Mask LITERAL1 -kWhirlpoolAcTempMask LITERAL1 +kWhirlpoolAcSwing1Offset LITERAL1 +kWhirlpoolAcSwing2Offset LITERAL1 kWhirlpoolAcTempPos LITERAL1 -kWhirlpoolAcTimerEnableMask LITERAL1 +kWhirlpoolAcTimerEnableOffset LITERAL1 kWhirlpoolAcZeroSpace LITERAL1 kWhynterBitMark LITERAL1 kWhynterBitMarkTicks LITERAL1 diff --git a/lib/IRremoteESP8266-2.6.5/library.json b/lib/IRremoteESP8266-2.7.0/library.json old mode 100755 new mode 100644 similarity index 97% rename from lib/IRremoteESP8266-2.6.5/library.json rename to lib/IRremoteESP8266-2.7.0/library.json index c5136f18e..361bbb0af --- a/lib/IRremoteESP8266-2.6.5/library.json +++ b/lib/IRremoteESP8266-2.7.0/library.json @@ -1,6 +1,6 @@ { "name": "IRremoteESP8266", - "version": "2.6.5", + "version": "2.7.0", "keywords": "infrared, ir, remote, esp8266, esp32", "description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)", "repository": diff --git a/lib/IRremoteESP8266-2.6.5/library.properties b/lib/IRremoteESP8266-2.7.0/library.properties old mode 100755 new mode 100644 similarity index 97% rename from lib/IRremoteESP8266-2.6.5/library.properties rename to lib/IRremoteESP8266-2.7.0/library.properties index f83a80428..1f2c0770f --- a/lib/IRremoteESP8266-2.6.5/library.properties +++ b/lib/IRremoteESP8266-2.7.0/library.properties @@ -1,5 +1,5 @@ name=IRremoteESP8266 -version=2.6.5 +version=2.7.0 author=David Conran, Sebastien Warin, Mark Szabo, Ken Shirriff maintainer=Mark Szabo, David Conran, Sebastien Warin, Roi Dayan, Massimiliano Pinto sentence=Send and receive infrared signals with multiple protocols (ESP8266/ESP32) diff --git a/lib/IRremoteESP8266-2.6.5/pylintrc b/lib/IRremoteESP8266-2.7.0/pylintrc old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/pylintrc rename to lib/IRremoteESP8266-2.7.0/pylintrc diff --git a/lib/IRremoteESP8266-2.6.5/src/CPPLINT.cfg b/lib/IRremoteESP8266-2.7.0/src/CPPLINT.cfg old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/CPPLINT.cfg rename to lib/IRremoteESP8266-2.7.0/src/CPPLINT.cfg diff --git a/lib/IRremoteESP8266-2.6.5/src/IRac.cpp b/lib/IRremoteESP8266-2.7.0/src/IRac.cpp old mode 100755 new mode 100644 similarity index 75% rename from lib/IRremoteESP8266-2.6.5/src/IRac.cpp rename to lib/IRremoteESP8266-2.7.0/src/IRac.cpp index df668d836..bec5eb554 --- a/lib/IRremoteESP8266-2.6.5/src/IRac.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/IRac.cpp @@ -14,6 +14,7 @@ #endif #include "IRsend.h" #include "IRremoteESP8266.h" +#include "IRtext.h" #include "IRutils.h" #include "ir_Amcor.h" #include "ir_Argo.h" @@ -42,15 +43,59 @@ IRac::IRac(const uint16_t pin, const bool inverted, const bool use_modulation) { _pin = pin; _inverted = inverted; _modulation = use_modulation; + initState(&next); + _prev = next; } +void IRac::initState(stdAc::state_t *state, + const decode_type_t vendor, const int16_t model, + const bool power, const stdAc::opmode_t mode, + const float degrees, const bool celsius, + 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, + const int16_t clock) { + state->protocol = vendor; + state->model = model; + state->power = power; + state->mode = mode; + state->degrees = degrees; + state->celsius = celsius; + state->fanspeed = fan; + state->swingv = swingv; + state->swingh = swingh; + state->quiet = quiet; + state->turbo = turbo; + state->econo = econo; + state->light = light; + state->filter = filter; + state->clean = clean; + state->beep = beep; + state->sleep = sleep; + state->clock = clock; +} + +void IRac::initState(stdAc::state_t *state) { + initState(state, decode_type_t::UNKNOWN, -1, false, stdAc::opmode_t::kOff, + 25, true, // 25 degrees Celsius + stdAc::fanspeed_t::kAuto, stdAc::swingv_t::kOff, + stdAc::swingh_t::kOff, false, false, false, false, false, false, + false, -1, -1); +} + +stdAc::state_t IRac::getState(void) { return next; } + +stdAc::state_t IRac::getStatePrev(void) { return _prev; } + // Is the given protocol supported by the IRac class? bool IRac::isProtocolSupported(const decode_type_t protocol) { switch (protocol) { #if SEND_AMCOR case decode_type_t::AMCOR: #endif -#if SEND_AMCOR +#if SEND_ARGO case decode_type_t::ARGO: #endif #if SEND_COOLIX @@ -62,6 +107,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { #if SEND_DAIKIN128 case decode_type_t::DAIKIN128: #endif +#if SEND_DAIKIN152 + case decode_type_t::DAIKIN152: +#endif #if SEND_DAIKIN160 case decode_type_t::DAIKIN160: #endif @@ -95,6 +143,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { #if SEND_HITACHI_AC case decode_type_t::HITACHI_AC: #endif +#if SEND_HITACHI_AC424 + case decode_type_t::HITACHI_AC424: +#endif #if SEND_KELVINATOR case decode_type_t::KELVINATOR: #endif @@ -104,6 +155,12 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { #if SEND_MITSUBISHI_AC case decode_type_t::MITSUBISHI_AC: #endif +#if SEND_MITSUBISHI112 + case decode_type_t::MITSUBISHI112: +#endif +#if SEND_MITSUBISHI136 + case decode_type_t::MITSUBISHI136: +#endif #if SEND_MITSUBISHIHEAVY case decode_type_t::MITSUBISHI_HEAVY_88: case decode_type_t::MITSUBISHI_HEAVY_152: @@ -148,6 +205,7 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { void IRac::amcor(IRAmcorAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -170,6 +228,7 @@ void IRac::argo(IRArgoAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const int16_t sleep) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -194,6 +253,14 @@ void IRac::coolix(IRCoolixAC *ac, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool light, const bool clean, const int16_t sleep) { + ac->begin(); + ac->setPower(on); + if (!on) { + // after turn off AC no more commands should + // be accepted + ac->send(); + return; + } ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); @@ -227,8 +294,6 @@ void IRac::coolix(IRCoolixAC *ac, ac->setClean(); ac->send(); } - // Power gets done last, as off has a special command. - ac->setPower(on); ac->send(); } #endif // SEND_COOLIX @@ -240,6 +305,7 @@ void IRac::daikin(IRDaikinESP *ac, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool econo, const bool clean) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -266,6 +332,7 @@ void IRac::daikin128(IRDaikin128 *ac, const stdAc::swingv_t swingv, const bool quiet, const bool turbo, const bool light, const bool econo, const int16_t sleep, const int16_t clock) { + ac->begin(); ac->setPowerToggle(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -285,11 +352,38 @@ void IRac::daikin128(IRDaikin128 *ac, } #endif // SEND_DAIKIN128 +#if SEND_DAIKIN152 +void IRac::daikin152(IRDaikin152 *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 econo) { + ac->begin(); + ac->setPower(on); + ac->setMode(ac->convertMode(mode)); + ac->setTemp(degrees); + ac->setFan(ac->convertFan(fan)); + ac->setSwingV((int8_t)swingv >= 0); + // No Horizontal Swing setting avaliable. + ac->setQuiet(quiet); + // No Light setting available. + // No Filter setting available. + ac->setPowerful(turbo); + ac->setEcono(econo); + // No Clean setting available. + // No Beep setting available. + // No Sleep setting available. + // No Clock setting available. + ac->send(); +} +#endif // SEND_DAIKIN152 + #if SEND_DAIKIN160 void IRac::daikin160(IRDaikin160 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -304,6 +398,7 @@ void IRac::daikin176(IRDaikin176 *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingh_t swingh) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -321,19 +416,21 @@ void IRac::daikin2(IRDaikin2 *ac, const bool quiet, const bool turbo, const bool light, const bool econo, const bool filter, const bool clean, const bool beep, const int16_t sleep, const int16_t clock) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); ac->setSwingVertical(ac->convertSwingV(swingv)); - ac->setSwingHorizontal((int8_t)swingh >= 0); + ac->setSwingHorizontal(ac->convertSwingH(swingh)); ac->setQuiet(quiet); - ac->setLight(light); + ac->setLight(light ? 1 : 3); // On/High is 1, Off is 3. ac->setPowerful(turbo); ac->setEcono(econo); ac->setPurify(filter); ac->setMold(clean); - ac->setBeep(beep); + ac->setClean(true); // Hardwire auto clean to be on per request (@sheppy99) + ac->setBeep(beep ? 2 : 3); // On/Loud is 2, Off is 3. if (sleep > 0) ac->enableSleepTimer(sleep); if (clock >= 0) ac->setCurrentTime(clock); ac->send(); @@ -346,6 +443,7 @@ void IRac::daikin216(IRDaikin216 *ac, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -364,6 +462,7 @@ void IRac::electra(IRElectraAc *ac, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -388,7 +487,9 @@ void IRac::fujitsu(IRFujitsuAC *ac, const fujitsu_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, - const bool quiet, const bool turbo, const bool econo) { + const bool quiet, const bool turbo, const bool econo, + const bool filter, const bool clean) { + ac->begin(); ac->setModel(model); if (on) { // Do all special messages (except "Off") first, @@ -420,8 +521,8 @@ void IRac::fujitsu(IRFujitsuAC *ac, const fujitsu_ac_remote_model_t model, ac->setSwing(swing); if (quiet) ac->setFanSpeed(kFujitsuAcFanQuiet); // No Light setting available. - // No Filter setting available. - // No Clean setting available. + ac->setFilter(filter); + ac->setClean(clean); // No Beep setting available. // No Sleep setting available. // No Clock setting available. @@ -442,6 +543,7 @@ void IRac::goodweather(IRGoodweatherAc *ac, const stdAc::swingv_t swingv, const bool turbo, const bool light, const int16_t sleep) { + ac->begin(); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); @@ -468,6 +570,7 @@ void IRac::gree(IRGreeAC *ac, const gree_ac_remote_model_t model, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool light, const bool clean, const int16_t sleep) { + ac->begin(); ac->setModel(model); ac->setPower(on); ac->setMode(ac->convertMode(mode)); @@ -494,6 +597,7 @@ void IRac::haier(IRHaierAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool filter, const int16_t sleep, const int16_t clock) { + ac->begin(); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); @@ -521,6 +625,7 @@ void IRac::haierYrwo2(IRHaierACYRW02 *ac, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool filter, const int16_t sleep) { + ac->begin(); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); @@ -543,6 +648,7 @@ void IRac::hitachi(IRHitachiAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -561,6 +667,29 @@ void IRac::hitachi(IRHitachiAc *ac, } #endif // SEND_HITACHI_AC +#if SEND_HITACHI_AC424 +void IRac::hitachi424(IRHitachiAc424 *ac, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan) { + ac->begin(); + ac->setPower(on); + ac->setMode(ac->convertMode(mode)); + ac->setTemp(degrees); + ac->setFan(ac->convertFan(fan)); + // TODO(jamsinclair): Add Swing(V) support. + // No Swing(H) setting available. + // No Quiet setting available. + // No Turbo setting available. + // No Light setting available. + // No Filter setting available. + // No Clean setting available. + // No Beep setting available. + // No Sleep setting available. + // No Clock setting available. + ac->send(); +} +#endif // SEND_HITACHI_AC424 + #if SEND_KELVINATOR void IRac::kelvinator(IRKelvinatorAC *ac, const bool on, const stdAc::opmode_t mode, @@ -569,6 +698,7 @@ void IRac::kelvinator(IRKelvinatorAC *ac, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const bool light, const bool filter, const bool clean) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -592,6 +722,7 @@ void IRac::midea(IRMideaAC *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const int16_t sleep) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setUseCelsius(celsius); @@ -618,6 +749,7 @@ void IRac::mitsubishi(IRMitsubishiAC *ac, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const int16_t clock) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -636,6 +768,58 @@ void IRac::mitsubishi(IRMitsubishiAC *ac, } #endif // SEND_MITSUBISHI_AC +#if SEND_MITSUBISHI112 +void IRac::mitsubishi112(IRMitsubishi112 *ac, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, + const stdAc::swingh_t swingh, + const bool quiet) { + ac->begin(); + ac->setPower(on); + ac->setMode(ac->convertMode(mode)); + ac->setTemp(degrees); + ac->setFan(ac->convertFan(fan)); + ac->setSwingV(ac->convertSwingV(swingv)); + ac->setSwingH(ac->convertSwingH(swingh)); + ac->setQuiet(quiet); + // FIXME - Econo + // ac->setEcono(econo); + // No Turbo setting available. + // No Light setting available. + // No Filter setting available. + // No Clean setting available. + // No Beep setting available. + // No Sleep setting available. + // No Clock setting available. + ac->send(); +} +#endif // SEND_MITSUBISHI112 + +#if SEND_MITSUBISHI136 +void IRac::mitsubishi136(IRMitsubishi136 *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) { + ac->begin(); + ac->setPower(on); + ac->setMode(ac->convertMode(mode)); + ac->setTemp(degrees); + ac->setFan(ac->convertFan(fan)); + ac->setSwingV(ac->convertSwingV(swingv)); + // No Horizontal Swing setting available. + ac->setQuiet(quiet); + // No Turbo setting available. + // No Light setting available. + // No Filter setting available. + // No Clean setting available. + // No Beep setting available. + // No Sleep setting available. + // No Clock setting available. + ac->send(); +} +#endif // SEND_MITSUBISHI136 + #if SEND_MITSUBISHIHEAVY void IRac::mitsubishiHeavy88(IRMitsubishiHeavy88Ac *ac, const bool on, const stdAc::opmode_t mode, @@ -645,6 +829,7 @@ void IRac::mitsubishiHeavy88(IRMitsubishiHeavy88Ac *ac, const stdAc::swingh_t swingh, const bool turbo, const bool econo, const bool clean) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -672,6 +857,7 @@ void IRac::mitsubishiHeavy152(IRMitsubishiHeavy152Ac *ac, const bool quiet, const bool turbo, const bool econo, const bool filter, const bool clean, const int16_t sleep) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -698,6 +884,7 @@ void IRac::neoclima(IRNeoclimaAc *ac, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool light, const bool filter, const int16_t sleep) { + ac->begin(); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); @@ -723,6 +910,7 @@ void IRac::panasonic(IRPanasonicAc *ac, const panasonic_ac_remote_model_t model, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool quiet, const bool turbo, const int16_t clock) { + ac->begin(); ac->setModel(model); ac->setPower(on); ac->setMode(ac->convertMode(mode)); @@ -749,9 +937,11 @@ void IRac::samsung(IRSamsungAc *ac, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet, const bool turbo, const bool clean, - const bool beep, const bool dopower) { - // dopower is for unit testing only. It should only ever be false in tests. - if (dopower) ac->setPower(on); + const bool beep, const bool prevpower, + const bool forcepower) { + ac->begin(); + ac->stateReset(forcepower, prevpower); + ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); @@ -776,6 +966,7 @@ void IRac::samsung(IRSamsungAc *ac, void IRac::sharp(IRSharpAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -804,6 +995,7 @@ void IRac::tcl112(IRTcl112Ac *ac, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, const bool turbo, const bool light, const bool econo, const bool filter) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -828,6 +1020,7 @@ void IRac::teco(IRTecoAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool light, const int16_t sleep) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -850,6 +1043,7 @@ void IRac::teco(IRTecoAc *ac, void IRac::toshiba(IRToshibaAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -873,6 +1067,7 @@ void IRac::trotec(IRTrotecESP *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const int16_t sleep) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -898,6 +1093,7 @@ void IRac::vestel(IRVestelAc *ac, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool filter, const int16_t sleep, const int16_t clock, const bool sendNormal) { + ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -926,6 +1122,7 @@ void IRac::whirlpool(IRWhirlpoolAc *ac, const whirlpool_ac_remote_model_t model, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool turbo, const bool light, const int16_t sleep, const int16_t clock) { + ac->begin(); ac->setModel(model); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); @@ -1029,303 +1226,11 @@ bool IRac::sendAc(const decode_type_t vendor, const int16_t model, 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, const int16_t clock) { - // Convert the temperature to Celsius. - float degC; - if (celsius) - degC = degrees; - else - degC = fahrenheitToCelsius(degrees); - bool on = power; - // A hack for Home Assistant, it appears to need/want an Off opmode. - if (mode == stdAc::opmode_t::kOff) on = false; - // Per vendor settings & setup. - switch (vendor) { -#if SEND_AMCOR - case AMCOR: - { - IRAmcorAc ac(_pin, _inverted, _modulation); - amcor(&ac, on, mode, degC, fan); - break; - } -#endif // SEND_AMCOR -#if SEND_ARGO - case ARGO: - { - IRArgoAC ac(_pin, _inverted, _modulation); - argo(&ac, on, mode, degC, fan, swingv, turbo, sleep); - break; - } -#endif // SEND_ARGO -#if SEND_COOLIX - case COOLIX: - { - IRCoolixAC ac(_pin, _inverted, _modulation); - coolix(&ac, on, mode, degC, fan, swingv, swingh, - turbo, light, clean, sleep); - break; - } -#endif // SEND_COOLIX -#if SEND_DAIKIN - case DAIKIN: - { - IRDaikinESP ac(_pin, _inverted, _modulation); - daikin(&ac, on, mode, degC, fan, swingv, swingh, - quiet, turbo, econo, clean); - break; - } -#endif // SEND_DAIKIN -#if SEND_DAIKIN128 - case DAIKIN128: - { - IRDaikin128 ac(_pin, _inverted, _modulation); - daikin128(&ac, on, mode, degC, fan, swingv, quiet, turbo, - light, econo, sleep, clock); - break; - } -#endif // SEND_DAIKIN2 -#if SEND_DAIKIN160 - case DAIKIN160: - { - IRDaikin160 ac(_pin, _inverted, _modulation); - daikin160(&ac, on, mode, degC, fan, swingv); - break; - } -#endif // SEND_DAIKIN160 -#if SEND_DAIKIN176 - case DAIKIN176: - { - IRDaikin176 ac(_pin, _inverted, _modulation); - daikin176(&ac, on, mode, degC, fan, swingh); - break; - } -#endif // SEND_DAIKIN176 -#if SEND_DAIKIN2 - case DAIKIN2: - { - IRDaikin2 ac(_pin, _inverted, _modulation); - daikin2(&ac, on, mode, degC, fan, swingv, swingh, quiet, turbo, - light, econo, filter, clean, beep, sleep, clock); - break; - } -#endif // SEND_DAIKIN2 -#if SEND_DAIKIN216 - case DAIKIN216: - { - IRDaikin216 ac(_pin, _inverted, _modulation); - daikin216(&ac, on, mode, degC, fan, swingv, swingh, quiet, turbo); - break; - } -#endif // SEND_DAIKIN216 -#if SEND_ELECTRA_AC - case ELECTRA_AC: - { - IRElectraAc ac(_pin, _inverted, _modulation); - ac.begin(); - electra(&ac, on, mode, degC, fan, swingv, swingh); - break; - } -#endif // SEND_ELECTRA_AC -#if SEND_FUJITSU_AC - case FUJITSU_AC: - { - IRFujitsuAC ac(_pin, (fujitsu_ac_remote_model_t)model, _inverted, - _modulation); - ac.begin(); - fujitsu(&ac, (fujitsu_ac_remote_model_t)model, on, mode, degC, fan, - swingv, swingh, quiet, turbo, econo); - break; - } -#endif // SEND_FUJITSU_AC -#if SEND_GOODWEATHER - case GOODWEATHER: - { - IRGoodweatherAc ac(_pin, _inverted, _modulation); - ac.begin(); - goodweather(&ac, on, mode, degC, fan, swingv, turbo, light, sleep); - break; - } -#endif // SEND_GOODWEATHER -#if SEND_GREE - case GREE: - { - IRGreeAC ac(_pin, (gree_ac_remote_model_t)model, _inverted, _modulation); - ac.begin(); - gree(&ac, (gree_ac_remote_model_t)model, on, mode, degC, fan, swingv, - turbo, light, clean, sleep); - break; - } -#endif // SEND_GREE -#if SEND_HAIER_AC - case HAIER_AC: - { - IRHaierAC ac(_pin, _inverted, _modulation); - ac.begin(); - haier(&ac, on, mode, degC, fan, swingv, filter, sleep, clock); - break; - } -#endif // SEND_HAIER_AC -#if SEND_HAIER_AC_YRW02 - case HAIER_AC_YRW02: - { - IRHaierACYRW02 ac(_pin, _inverted, _modulation); - ac.begin(); - haierYrwo2(&ac, on, mode, degC, fan, swingv, turbo, filter, sleep); - break; - } -#endif // SEND_HAIER_AC_YRW02 -#if SEND_HITACHI_AC - case HITACHI_AC: - { - IRHitachiAc ac(_pin, _inverted, _modulation); - ac.begin(); - hitachi(&ac, on, mode, degC, fan, swingv, swingh); - break; - } -#endif // SEND_HITACHI_AC -#if SEND_KELVINATOR - case KELVINATOR: - { - IRKelvinatorAC ac(_pin, _inverted, _modulation); - ac.begin(); - kelvinator(&ac, on, mode, degC, fan, swingv, swingh, quiet, turbo, - light, filter, clean); - break; - } -#endif // SEND_KELVINATOR -#if SEND_MIDEA - case MIDEA: - { - IRMideaAC ac(_pin, _inverted, _modulation); - ac.begin(); - midea(&ac, on, mode, celsius, degrees, fan, swingv, sleep); - break; - } -#endif // SEND_MIDEA -#if SEND_MITSUBISHI_AC - case MITSUBISHI_AC: - { - IRMitsubishiAC ac(_pin, _inverted, _modulation); - ac.begin(); - mitsubishi(&ac, on, mode, degC, fan, swingv, swingh, quiet, clock); - break; - } -#endif // SEND_MITSUBISHI_AC -#if SEND_MITSUBISHIHEAVY - case MITSUBISHI_HEAVY_88: - { - IRMitsubishiHeavy88Ac ac(_pin, _inverted, _modulation); - ac.begin(); - mitsubishiHeavy88(&ac, on, mode, degC, fan, swingv, swingh, - turbo, econo, clean); - break; - } - case MITSUBISHI_HEAVY_152: - { - IRMitsubishiHeavy152Ac ac(_pin, _inverted, _modulation); - ac.begin(); - mitsubishiHeavy152(&ac, on, mode, degC, fan, swingv, swingh, - quiet, turbo, econo, filter, clean, sleep); - break; - } -#endif // SEND_MITSUBISHIHEAVY -#if SEND_NEOCLIMA - case NEOCLIMA: - { - IRNeoclimaAc ac(_pin, _inverted, _modulation); - ac.begin(); - neoclima(&ac, on, mode, degC, fan, swingv, swingh, turbo, light, filter, - sleep); - break; - } -#endif // SEND_NEOCLIMA -#if SEND_PANASONIC_AC - case PANASONIC_AC: - { - IRPanasonicAc ac(_pin, _inverted, _modulation); - ac.begin(); - panasonic(&ac, (panasonic_ac_remote_model_t)model, on, mode, degC, fan, - swingv, swingh, quiet, turbo, clock); - break; - } -#endif // SEND_PANASONIC_AC -#if SEND_SAMSUNG_AC - case SAMSUNG_AC: - { - IRSamsungAc ac(_pin, _inverted, _modulation); - ac.begin(); - samsung(&ac, on, mode, degC, fan, swingv, quiet, turbo, clean, beep); - break; - } -#endif // SEND_SAMSUNG_AC -#if SEND_SHARP_AC - case SHARP_AC: - { - IRSharpAc ac(_pin, _inverted, _modulation); - ac.begin(); - sharp(&ac, on, mode, degC, fan); - break; - } -#endif // SEND_SHARP_AC -#if SEND_TCL112AC - case TCL112AC: - { - IRTcl112Ac ac(_pin, _inverted, _modulation); - ac.begin(); - tcl112(&ac, on, mode, degC, fan, swingv, swingh, turbo, light, econo, - filter); - break; - } -#endif // SEND_TCL112AC -#if SEND_TECO - case TECO: - { - IRTecoAc ac(_pin, _inverted, _modulation); - ac.begin(); - teco(&ac, on, mode, degC, fan, swingv, light, sleep); - break; - } -#endif // SEND_TECO -#if SEND_TOSHIBA_AC - case TOSHIBA_AC: - { - IRToshibaAC ac(_pin, _inverted, _modulation); - ac.begin(); - toshiba(&ac, on, mode, degC, fan); - break; - } -#endif // SEND_TOSHIBA_AC -#if SEND_TROTEC - case TROTEC: - { - IRTrotecESP ac(_pin, _inverted, _modulation); - ac.begin(); - trotec(&ac, on, mode, degC, fan, sleep); - break; - } -#endif // SEND_TROTEC -#if SEND_VESTEL_AC - case VESTEL_AC: - { - IRVestelAc ac(_pin, _inverted, _modulation); - ac.begin(); - vestel(&ac, on, mode, degC, fan, swingv, turbo, filter, sleep, clock); - break; - } -#endif // SEND_VESTEL_AC -#if SEND_WHIRLPOOL_AC - case WHIRLPOOL_AC: - { - IRWhirlpoolAc ac(_pin, _inverted, _modulation); - ac.begin(); - whirlpool(&ac, (whirlpool_ac_remote_model_t)model, on, mode, degC, fan, - swingv, turbo, light, sleep, clock); - break; - } -#endif // SEND_WHIRLPOOL_AC - default: - return false; // Fail, didn't match anything. - } - return true; // Success. + stdAc::state_t to_send; + initState(&to_send, vendor, model, power, mode, degrees, celsius, fan, swingv, + swingh, quiet, turbo, econo, light, filter, clean, beep, sleep, + clock); + return this->sendAc(to_send, &to_send); } // Send A/C message for a given device using state_t structures. @@ -1336,12 +1241,348 @@ bool IRac::sendAc(const decode_type_t vendor, const int16_t model, // Returns: // boolean: True, if accepted/converted/attempted. False, if unsupported. bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { - stdAc::state_t final = this->handleToggles(desired, prev); - return this->sendAc(final.protocol, final.model, final.power, final.mode, - final.degrees, final.celsius, final.fanspeed, - final.swingv, final.swingh, final.quiet, final.turbo, - final.econo, final.light, final.filter, final.clean, - final.beep, final.sleep, final.clock); + stdAc::state_t send = this->handleToggles(desired, prev); + // Convert the temperature to Celsius. + float degC; + if (desired.celsius) + degC = send.degrees; + else + degC = fahrenheitToCelsius(desired.degrees); + bool on = desired.power; + // A hack for Home Assistant, it appears to need/want an Off opmode. + if (desired.mode == stdAc::opmode_t::kOff) on = false; + // Per vendor settings & setup. + switch (send.protocol) { +#if SEND_AMCOR + case AMCOR: + { + IRAmcorAc ac(_pin, _inverted, _modulation); + amcor(&ac, on, send.mode, degC, send.fanspeed); + break; + } +#endif // SEND_AMCOR +#if SEND_ARGO + case ARGO: + { + IRArgoAC ac(_pin, _inverted, _modulation); + argo(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.turbo, + send.sleep); + break; + } +#endif // SEND_ARGO +#if SEND_COOLIX + case COOLIX: + { + IRCoolixAC ac(_pin, _inverted, _modulation); + coolix(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.swingh, + send.turbo, send.light, send.clean, send.sleep); + break; + } +#endif // SEND_COOLIX +#if SEND_DAIKIN + case DAIKIN: + { + IRDaikinESP ac(_pin, _inverted, _modulation); + daikin(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.swingh, + send.quiet, send.turbo, send.econo, send.clean); + break; + } +#endif // SEND_DAIKIN +#if SEND_DAIKIN128 + case DAIKIN128: + { + IRDaikin128 ac(_pin, _inverted, _modulation); + daikin128(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.quiet, send.turbo, send.light, send.econo, send.sleep, + send.clock); + break; + } +#endif // SEND_DAIKIN2 +#if SEND_DAIKIN152 + case DAIKIN152: + { + IRDaikin152 ac(_pin, _inverted, _modulation); + daikin152(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.quiet, send.turbo, send.econo); + break; + } +#endif // SEND_DAIKIN152 +#if SEND_DAIKIN160 + case DAIKIN160: + { + IRDaikin160 ac(_pin, _inverted, _modulation); + daikin160(&ac, on, send.mode, degC, send.fanspeed, send.swingv); + break; + } +#endif // SEND_DAIKIN160 +#if SEND_DAIKIN176 + case DAIKIN176: + { + IRDaikin176 ac(_pin, _inverted, _modulation); + daikin176(&ac, on, send.mode, degC, send.fanspeed, send.swingh); + break; + } +#endif // SEND_DAIKIN176 +#if SEND_DAIKIN2 + case DAIKIN2: + { + IRDaikin2 ac(_pin, _inverted, _modulation); + daikin2(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.swingh, + send.quiet, send.turbo, send.light, send.econo, send.filter, + send.clean, send.beep, send.sleep, send.clock); + break; + } +#endif // SEND_DAIKIN2 +#if SEND_DAIKIN216 + case DAIKIN216: + { + IRDaikin216 ac(_pin, _inverted, _modulation); + daikin216(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.swingh, send.quiet, send.turbo); + break; + } +#endif // SEND_DAIKIN216 +#if SEND_ELECTRA_AC + case ELECTRA_AC: + { + IRElectraAc ac(_pin, _inverted, _modulation); + electra(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.swingh); + break; + } +#endif // SEND_ELECTRA_AC +#if SEND_FUJITSU_AC + case FUJITSU_AC: + { + IRFujitsuAC ac(_pin, (fujitsu_ac_remote_model_t)send.model, _inverted, + _modulation); + fujitsu(&ac, (fujitsu_ac_remote_model_t)send.model, on, send.mode, degC, + send.fanspeed, send.swingv, send.swingh, send.quiet, send.turbo, + send.econo, send.filter, send.clean); + break; + } +#endif // SEND_FUJITSU_AC +#if SEND_GOODWEATHER + case GOODWEATHER: + { + IRGoodweatherAc ac(_pin, _inverted, _modulation); + goodweather(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.turbo, send.light, send.sleep); + break; + } +#endif // SEND_GOODWEATHER +#if SEND_GREE + case GREE: + { + IRGreeAC ac(_pin, (gree_ac_remote_model_t)send.model, _inverted, + _modulation); + gree(&ac, (gree_ac_remote_model_t)send.model, on, send.mode, degC, + send.fanspeed, send.swingv, send.turbo, send.light, send.clean, + send.sleep); + break; + } +#endif // SEND_GREE +#if SEND_HAIER_AC + case HAIER_AC: + { + IRHaierAC ac(_pin, _inverted, _modulation); + haier(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.filter, + send.sleep, send.clock); + break; + } +#endif // SEND_HAIER_AC +#if SEND_HAIER_AC_YRW02 + case HAIER_AC_YRW02: + { + IRHaierACYRW02 ac(_pin, _inverted, _modulation); + haierYrwo2(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.turbo, send.filter, send.sleep); + break; + } +#endif // SEND_HAIER_AC_YRW02 +#if SEND_HITACHI_AC + case HITACHI_AC: + { + IRHitachiAc ac(_pin, _inverted, _modulation); + hitachi(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.swingh); + break; + } +#endif // SEND_HITACHI_AC +#if SEND_HITACHI_AC424 + case HITACHI_AC424: + { + IRHitachiAc424 ac(_pin, _inverted, _modulation); + hitachi424(&ac, on, send.mode, degC, send.fanspeed); + break; + } +#endif // SEND_HITACHI_AC424 +#if SEND_KELVINATOR + case KELVINATOR: + { + IRKelvinatorAC ac(_pin, _inverted, _modulation); + kelvinator(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.swingh, send.quiet, send.turbo, send.light, send.filter, + send.clean); + break; + } +#endif // SEND_KELVINATOR +#if SEND_MIDEA + case MIDEA: + { + IRMideaAC ac(_pin, _inverted, _modulation); + midea(&ac, on, send.mode, send.celsius, send.degrees, send.fanspeed, + send.swingv, send.sleep); + break; + } +#endif // SEND_MIDEA +#if SEND_MITSUBISHI_AC + case MITSUBISHI_AC: + { + IRMitsubishiAC ac(_pin, _inverted, _modulation); + mitsubishi(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.swingh, send.quiet, send.clock); + break; + } +#endif // SEND_MITSUBISHI_AC +#if SEND_MITSUBISHI112 + case MITSUBISHI112: + { + IRMitsubishi112 ac(_pin, _inverted, _modulation); + mitsubishi112(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.swingh, send.quiet); + break; + } +#endif // SEND_MITSUBISHI112 +#if SEND_MITSUBISHI136 + case MITSUBISHI136: + { + IRMitsubishi136 ac(_pin, _inverted, _modulation); + mitsubishi136(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.quiet); + break; + } +#endif // SEND_MITSUBISHI136 +#if SEND_MITSUBISHIHEAVY + case MITSUBISHI_HEAVY_88: + { + IRMitsubishiHeavy88Ac ac(_pin, _inverted, _modulation); + mitsubishiHeavy88(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.swingh, send.turbo, send.econo, send.clean); + break; + } + case MITSUBISHI_HEAVY_152: + { + IRMitsubishiHeavy152Ac ac(_pin, _inverted, _modulation); + mitsubishiHeavy152(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.swingh, send.quiet, send.turbo, send.econo, + send.filter, send.clean, send.sleep); + break; + } +#endif // SEND_MITSUBISHIHEAVY +#if SEND_NEOCLIMA + case NEOCLIMA: + { + IRNeoclimaAc ac(_pin, _inverted, _modulation); + neoclima(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + send.swingh, send.turbo, send.light, send.filter, send.sleep); + break; + } +#endif // SEND_NEOCLIMA +#if SEND_PANASONIC_AC + case PANASONIC_AC: + { + IRPanasonicAc ac(_pin, _inverted, _modulation); + panasonic(&ac, (panasonic_ac_remote_model_t)send.model, on, send.mode, + degC, send.fanspeed, send.swingv, send.swingh, send.quiet, + send.turbo, send.clock); + break; + } +#endif // SEND_PANASONIC_AC +#if SEND_SAMSUNG_AC + case SAMSUNG_AC: + { + IRSamsungAc ac(_pin, _inverted, _modulation); + samsung(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.quiet, + send.turbo, send.clean, send.beep, prev->power); + break; + } +#endif // SEND_SAMSUNG_AC +#if SEND_SHARP_AC + case SHARP_AC: + { + IRSharpAc ac(_pin, _inverted, _modulation); + sharp(&ac, on, send.mode, degC, send.fanspeed); + break; + } +#endif // SEND_SHARP_AC +#if SEND_TCL112AC + case TCL112AC: + { + IRTcl112Ac ac(_pin, _inverted, _modulation); + tcl112(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.swingh, + send.turbo, send.light, send.econo, send.filter); + break; + } +#endif // SEND_TCL112AC +#if SEND_TECO + case TECO: + { + IRTecoAc ac(_pin, _inverted, _modulation); + teco(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.light, + send.sleep); + break; + } +#endif // SEND_TECO +#if SEND_TOSHIBA_AC + case TOSHIBA_AC: + { + IRToshibaAC ac(_pin, _inverted, _modulation); + toshiba(&ac, on, send.mode, degC, send.fanspeed); + break; + } +#endif // SEND_TOSHIBA_AC +#if SEND_TROTEC + case TROTEC: + { + IRTrotecESP ac(_pin, _inverted, _modulation); + trotec(&ac, on, send.mode, degC, send.fanspeed, send.sleep); + break; + } +#endif // SEND_TROTEC +#if SEND_VESTEL_AC + case VESTEL_AC: + { + IRVestelAc ac(_pin, _inverted, _modulation); + vestel(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.turbo, + send.filter, send.sleep, send.clock); + break; + } +#endif // SEND_VESTEL_AC +#if SEND_WHIRLPOOL_AC + case WHIRLPOOL_AC: + { + IRWhirlpoolAc ac(_pin, _inverted, _modulation); + whirlpool(&ac, (whirlpool_ac_remote_model_t)send.model, on, send.mode, + degC, send.fanspeed, send.swingv, send.turbo, send.light, + send.sleep, send.clock); + break; + } +#endif // SEND_WHIRLPOOL_AC + default: + return false; // Fail, didn't match anything. + } + return true; // Success. +} + +// Send an A/C message based soley on our internal state. +// +// Returns: +// boolean: True, if accepted/converted/attempted. False, if unsupported. +bool IRac::sendAc(void) { + bool success = this->sendAc(next, &_prev); + _prev = next; + return success; } // Compare two AirCon states. @@ -1356,21 +1597,29 @@ bool IRac::cmpStates(const stdAc::state_t a, const stdAc::state_t b) { a.clean != b.clean || a.beep != b.beep || a.sleep != b.sleep; } +bool IRac::hasStateChanged(void) { return cmpStates(next, _prev); } + stdAc::opmode_t IRac::strToOpmode(const char *str, const stdAc::opmode_t def) { - if (!strcasecmp(str, "AUTO") || !strcasecmp(str, "AUTOMATIC")) + if (!strcasecmp(str, kAutoStr.c_str()) || + !strcasecmp(str, kAutomaticStr.c_str())) return stdAc::opmode_t::kAuto; - else if (!strcasecmp(str, "OFF") || !strcasecmp(str, "STOP")) + else if (!strcasecmp(str, kOffStr.c_str()) || + !strcasecmp(str, kStopStr.c_str())) return stdAc::opmode_t::kOff; - else if (!strcasecmp(str, "COOL") || !strcasecmp(str, "COOLING")) + else if (!strcasecmp(str, kCoolStr.c_str()) || + !strcasecmp(str, "COOLING")) return stdAc::opmode_t::kCool; - else if (!strcasecmp(str, "HEAT") || !strcasecmp(str, "HEATING")) + else if (!strcasecmp(str, kHeatStr.c_str()) || + !strcasecmp(str, "HEATING")) return stdAc::opmode_t::kHeat; - else if (!strcasecmp(str, "DRY") || !strcasecmp(str, "DRYING") || + else if (!strcasecmp(str, kDryStr.c_str()) || + !strcasecmp(str, "DRYING") || !strcasecmp(str, "DEHUMIDIFY")) return stdAc::opmode_t::kDry; - else if (!strcasecmp(str, "FAN") || !strcasecmp(str, "FANONLY") || - !strcasecmp(str, "FAN_ONLY")) + else if (!strcasecmp(str, kFanStr.c_str()) || + !strcasecmp(str, "FANONLY") || + !strcasecmp(str, kFanOnlyStr.c_str())) return stdAc::opmode_t::kFan; else return def; @@ -1378,20 +1627,26 @@ stdAc::opmode_t IRac::strToOpmode(const char *str, stdAc::fanspeed_t IRac::strToFanspeed(const char *str, const stdAc::fanspeed_t def) { - if (!strcasecmp(str, "AUTO") || !strcasecmp(str, "AUTOMATIC")) + if (!strcasecmp(str, kAutoStr.c_str()) || + !strcasecmp(str, kAutomaticStr.c_str())) return stdAc::fanspeed_t::kAuto; - else if (!strcasecmp(str, "MIN") || !strcasecmp(str, "MINIMUM") || - !strcasecmp(str, "LOWEST")) + else if (!strcasecmp(str, kMinStr.c_str()) || + !strcasecmp(str, kMinimumStr.c_str()) || + !strcasecmp(str, kLowestStr.c_str())) return stdAc::fanspeed_t::kMin; - else if (!strcasecmp(str, "LOW")) + else if (!strcasecmp(str, kLowStr.c_str()) || + !strcasecmp(str, kLoStr.c_str())) return stdAc::fanspeed_t::kLow; - else if (!strcasecmp(str, "MED") || !strcasecmp(str, "MEDIUM") || - !strcasecmp(str, "MID")) + else if (!strcasecmp(str, kMedStr.c_str()) || + !strcasecmp(str, kMediumStr.c_str()) || + !strcasecmp(str, kMidStr.c_str())) return stdAc::fanspeed_t::kMedium; - else if (!strcasecmp(str, "HIGH") || !strcasecmp(str, "HI")) + else if (!strcasecmp(str, kHighStr.c_str()) || + !strcasecmp(str, kHiStr.c_str())) return stdAc::fanspeed_t::kHigh; - else if (!strcasecmp(str, "MAX") || !strcasecmp(str, "MAXIMUM") || - !strcasecmp(str, "HIGHEST")) + else if (!strcasecmp(str, kMaxStr.c_str()) || + !strcasecmp(str, kMaximumStr.c_str()) || + !strcasecmp(str, kHighestStr.c_str())) return stdAc::fanspeed_t::kMax; else return def; @@ -1399,26 +1654,36 @@ stdAc::fanspeed_t IRac::strToFanspeed(const char *str, stdAc::swingv_t IRac::strToSwingV(const char *str, const stdAc::swingv_t def) { - if (!strcasecmp(str, "AUTO") || !strcasecmp(str, "AUTOMATIC") || - !strcasecmp(str, "ON") || !strcasecmp(str, "SWING")) + if (!strcasecmp(str, kAutoStr.c_str()) || + !strcasecmp(str, kAutomaticStr.c_str()) || + !strcasecmp(str, kOnStr.c_str()) || + !strcasecmp(str, kSwingStr.c_str())) return stdAc::swingv_t::kAuto; - else if (!strcasecmp(str, "OFF") || !strcasecmp(str, "STOP")) + else if (!strcasecmp(str, kOffStr.c_str()) || + !strcasecmp(str, kStopStr.c_str())) return stdAc::swingv_t::kOff; - else if (!strcasecmp(str, "MIN") || !strcasecmp(str, "MINIMUM") || - !strcasecmp(str, "LOWEST") || !strcasecmp(str, "BOTTOM") || - !strcasecmp(str, "DOWN")) + else if (!strcasecmp(str, kMinStr.c_str()) || + !strcasecmp(str, kMinimumStr.c_str()) || + !strcasecmp(str, kLowestStr.c_str()) || + !strcasecmp(str, kBottomStr.c_str()) || + !strcasecmp(str, kDownStr.c_str())) return stdAc::swingv_t::kLowest; - else if (!strcasecmp(str, "LOW")) + else if (!strcasecmp(str, kLowStr.c_str())) return stdAc::swingv_t::kLow; - else if (!strcasecmp(str, "MID") || !strcasecmp(str, "MIDDLE") || - !strcasecmp(str, "MED") || !strcasecmp(str, "MEDIUM") || - !strcasecmp(str, "CENTRE") || !strcasecmp(str, "CENTER")) + else if (!strcasecmp(str, kMidStr.c_str()) || + !strcasecmp(str, kMiddleStr.c_str()) || + !strcasecmp(str, kMedStr.c_str()) || + !strcasecmp(str, kMediumStr.c_str()) || + !strcasecmp(str, kCentreStr.c_str())) return stdAc::swingv_t::kMiddle; - else if (!strcasecmp(str, "HIGH") || !strcasecmp(str, "HI")) + else if (!strcasecmp(str, kHighStr.c_str()) || + !strcasecmp(str, kHiStr.c_str())) return stdAc::swingv_t::kHigh; - else if (!strcasecmp(str, "HIGHEST") || !strcasecmp(str, "MAX") || - !strcasecmp(str, "MAXIMUM") || !strcasecmp(str, "TOP") || - !strcasecmp(str, "UP")) + else if (!strcasecmp(str, kHighestStr.c_str()) || + !strcasecmp(str, kMaxStr.c_str()) || + !strcasecmp(str, kMaximumStr.c_str()) || + !strcasecmp(str, kTopStr.c_str()) || + !strcasecmp(str, kUpStr.c_str())) return stdAc::swingv_t::kHighest; else return def; @@ -1426,34 +1691,40 @@ stdAc::swingv_t IRac::strToSwingV(const char *str, stdAc::swingh_t IRac::strToSwingH(const char *str, const stdAc::swingh_t def) { - if (!strcasecmp(str, "AUTO") || !strcasecmp(str, "AUTOMATIC") || - !strcasecmp(str, "ON") || !strcasecmp(str, "SWING")) + if (!strcasecmp(str, kAutoStr.c_str()) || + !strcasecmp(str, kAutomaticStr.c_str()) || + !strcasecmp(str, kOnStr.c_str()) || !strcasecmp(str, kSwingStr.c_str())) return stdAc::swingh_t::kAuto; - else if (!strcasecmp(str, "OFF") || !strcasecmp(str, "STOP")) + else if (!strcasecmp(str, kOffStr.c_str()) || + !strcasecmp(str, kStopStr.c_str())) return stdAc::swingh_t::kOff; - else if (!strcasecmp(str, "LEFTMAX") || !strcasecmp(str, "LEFT MAX") || - !strcasecmp(str, "MAXLEFT") || !strcasecmp(str, "MAX LEFT") || - !strcasecmp(str, "FARLEFT") || !strcasecmp(str, "FAR LEFT")) + else if (!strcasecmp(str, kLeftMaxStr.c_str()) || + !strcasecmp(str, D_STR_LEFT " " D_STR_MAX) || + !strcasecmp(str, D_STR_MAX D_STR_LEFT) || + !strcasecmp(str, kMaxLeftStr.c_str())) return stdAc::swingh_t::kLeftMax; - else if (!strcasecmp(str, "LEFT")) + else if (!strcasecmp(str, kLeftStr.c_str())) return stdAc::swingh_t::kLeft; - else if (!strcasecmp(str, "MID") || !strcasecmp(str, "MIDDLE") || - !strcasecmp(str, "MED") || !strcasecmp(str, "MEDIUM") || - !strcasecmp(str, "CENTRE") || !strcasecmp(str, "CENTER")) + else if (!strcasecmp(str, kMidStr.c_str()) || + !strcasecmp(str, kMiddleStr.c_str()) || + !strcasecmp(str, kMedStr.c_str()) || + !strcasecmp(str, kMediumStr.c_str()) || + !strcasecmp(str, kCentreStr.c_str())) return stdAc::swingh_t::kMiddle; - else if (!strcasecmp(str, "RIGHT")) + else if (!strcasecmp(str, kRightStr.c_str())) return stdAc::swingh_t::kRight; - else if (!strcasecmp(str, "RIGHTMAX") || !strcasecmp(str, "RIGHT MAX") || - !strcasecmp(str, "MAXRIGHT") || !strcasecmp(str, "MAX RIGHT") || - !strcasecmp(str, "FARRIGHT") || !strcasecmp(str, "FAR RIGHT")) + else if (!strcasecmp(str, kRightMaxStr.c_str()) || + !strcasecmp(str, D_STR_MAX " " D_STR_RIGHT) || + !strcasecmp(str, D_STR_MAX D_STR_RIGHT) || + !strcasecmp(str, kMaxRightStr.c_str())) return stdAc::swingh_t::kRightMax; - else if (!strcasecmp(str, "WIDE")) + else if (!strcasecmp(str, kWideStr.c_str())) return stdAc::swingh_t::kWide; else return def; } -// Assumes str is the model or an integer >= 1. +// Assumes str is the model code or an integer >= 1. int16_t IRac::strToModel(const char *str, const int16_t def) { // Gree if (!strcasecmp(str, "YAW1F")) { @@ -1469,6 +1740,8 @@ int16_t IRac::strToModel(const char *str, const int16_t def) { return fujitsu_ac_remote_model_t::ARREB1E; } else if (!strcasecmp(str, "ARJW2")) { return fujitsu_ac_remote_model_t::ARJW2; + } else if (!strcasecmp(str, "ARRY4")) { + return fujitsu_ac_remote_model_t::ARRY4; // Panasonic A/C families } else if (!strcasecmp(str, "LKE") || !strcasecmp(str, "PANASONICLKE")) { return panasonic_ac_remote_model_t::kPanasonicLke; @@ -1498,99 +1771,103 @@ int16_t IRac::strToModel(const char *str, const int16_t def) { } bool IRac::strToBool(const char *str, const bool def) { - if (!strcasecmp(str, "ON") || !strcasecmp(str, "1") || - !strcasecmp(str, "YES") || !strcasecmp(str, "TRUE")) + if (!strcasecmp(str, kOnStr.c_str()) || + !strcasecmp(str, "1") || + !strcasecmp(str, kYesStr.c_str()) || + !strcasecmp(str, kTrueStr.c_str())) return true; - else if (!strcasecmp(str, "OFF") || !strcasecmp(str, "0") || - !strcasecmp(str, "NO") || !strcasecmp(str, "FALSE")) + else if (!strcasecmp(str, kOffStr.c_str()) || + !strcasecmp(str, "0") || + !strcasecmp(str, kNoStr.c_str()) || + !strcasecmp(str, kFalseStr.c_str())) return false; else return def; } String IRac::boolToString(const bool value) { - return value ? F("on") : F("off"); + return value ? kOnStr : kOffStr; } String IRac::opmodeToString(const stdAc::opmode_t mode) { switch (mode) { case stdAc::opmode_t::kOff: - return F("off"); + return kOffStr; case stdAc::opmode_t::kAuto: - return F("auto"); + return kAutoStr; case stdAc::opmode_t::kCool: - return F("cool"); + return kCoolStr; case stdAc::opmode_t::kHeat: - return F("heat"); + return kHeatStr; case stdAc::opmode_t::kDry: - return F("dry"); + return kDryStr; case stdAc::opmode_t::kFan: - return F("fan_only"); + return kFanOnlyStr; default: - return F("unknown"); + return kUnknownStr; } } String IRac::fanspeedToString(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kAuto: - return F("auto"); + return kAutoStr; case stdAc::fanspeed_t::kMax: - return F("max"); + return kMaxStr; case stdAc::fanspeed_t::kHigh: - return F("high"); + return kHighStr; case stdAc::fanspeed_t::kMedium: - return F("medium"); + return kMediumStr; case stdAc::fanspeed_t::kLow: - return F("low"); + return kLowStr; case stdAc::fanspeed_t::kMin: - return F("min"); + return kMinStr; default: - return F("unknown"); + return kUnknownStr; } } String IRac::swingvToString(const stdAc::swingv_t swingv) { switch (swingv) { case stdAc::swingv_t::kOff: - return F("off"); + return kOffStr; case stdAc::swingv_t::kAuto: - return F("auto"); + return kAutoStr; case stdAc::swingv_t::kHighest: - return F("highest"); + return kHighestStr; case stdAc::swingv_t::kHigh: - return F("high"); + return kHighStr; case stdAc::swingv_t::kMiddle: - return F("middle"); + return kMiddleStr; case stdAc::swingv_t::kLow: - return F("low"); + return kLowStr; case stdAc::swingv_t::kLowest: - return F("lowest"); + return kLowestStr; default: - return F("unknown"); + return kUnknownStr; } } String IRac::swinghToString(const stdAc::swingh_t swingh) { switch (swingh) { case stdAc::swingh_t::kOff: - return F("off"); + return kOffStr; case stdAc::swingh_t::kAuto: - return F("auto"); + return kAutoStr; case stdAc::swingh_t::kLeftMax: - return F("leftmax"); + return kLeftMaxStr; case stdAc::swingh_t::kLeft: - return F("left"); + return kLeftStr; case stdAc::swingh_t::kMiddle: - return F("middle"); + return kMiddleStr; case stdAc::swingh_t::kRight: - return F("right"); + return kRightStr; case stdAc::swingh_t::kRightMax: - return F("rightmax"); + return kRightMaxStr; case stdAc::swingh_t::kWide: - return F("wide"); + return kWideStr; default: - return F("unknown"); + return kUnknownStr; } } @@ -1630,6 +1907,13 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_DAIKIN128 +#if DECODE_DAIKIN152 + case decode_type_t::DAIKIN152: { + IRDaikin152 ac(0); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_DAIKIN152 #if DECODE_DAIKIN160 case decode_type_t::DAIKIN160: { IRDaikin160 ac(0); @@ -1686,6 +1970,20 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_MITSUBISHI_AC +#if DECODE_MITSUBISHI112 + case decode_type_t::MITSUBISHI112: { + IRMitsubishi112 ac(0); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_MITSUBISHI112 +#if DECODE_MITSUBISHI136 + case decode_type_t::MITSUBISHI136: { + IRMitsubishi136 ac(0); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_MITSUBISHI136 #if DECODE_MITSUBISHIHEAVY case decode_type_t::MITSUBISHI_HEAVY_88: { IRMitsubishiHeavy88Ac ac(0); @@ -1771,6 +2069,7 @@ namespace IRAcUtils { #if DECODE_COOLIX case decode_type_t::COOLIX: { IRCoolixAC ac(0); + ac.on(); ac.setRaw(result->value); // Coolix uses value instead of state. return ac.toString(); } @@ -1792,6 +2091,13 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_HITACHI_AC +#if DECODE_HITACHI_AC424 + case decode_type_t::HITACHI_AC424: { + IRHitachiAc424 ac(0); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_HITACHI_AC424 #if DECODE_WHIRLPOOL_AC case decode_type_t::WHIRLPOOL_AC: { IRWhirlpoolAc ac(0); @@ -1870,6 +2176,22 @@ namespace IRAcUtils { break; } #endif // DECODE_DAIKIN +#if DECODE_DAIKIN128 + case decode_type_t::DAIKIN128: { + IRDaikin128 ac(0); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } +#endif // DECODE_DAIKIN128 +#if DECODE_DAIKIN152 + case decode_type_t::DAIKIN152: { + IRDaikin152 ac(0); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } +#endif // DECODE_DAIKIN152 #if DECODE_DAIKIN160 case decode_type_t::DAIKIN160: { IRDaikin160 ac(kGpioUnused); @@ -1958,6 +2280,14 @@ namespace IRAcUtils { break; } #endif // (DECODE_HITACHI_AC || DECODE_HITACHI_AC2) +#if DECODE_HITACHI_AC424 + case decode_type_t::HITACHI_AC424: { + IRHitachiAc424 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } +#endif // DECODE_HITACHI_AC424 #if DECODE_KELVINATOR case decode_type_t::KELVINATOR: { IRKelvinatorAC ac(kGpioUnused); @@ -1982,6 +2312,22 @@ namespace IRAcUtils { break; } #endif // DECODE_MITSUBISHI_AC +#if DECODE_MITSUBISHI112 + case decode_type_t::MITSUBISHI112: { + IRMitsubishi112 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } +#endif // DECODE_MITSUBISHI112 +#if DECODE_MITSUBISHI136 + case decode_type_t::MITSUBISHI136: { + IRMitsubishi136 ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } +#endif // DECODE_MITSUBISHI136 #if DECODE_MITSUBISHIHEAVY case decode_type_t::MITSUBISHI_HEAVY_88: { IRMitsubishiHeavy88Ac ac(kGpioUnused); diff --git a/lib/IRremoteESP8266-2.6.5/src/IRac.h b/lib/IRremoteESP8266-2.7.0/src/IRac.h old mode 100755 new mode 100644 similarity index 84% rename from lib/IRremoteESP8266-2.6.5/src/IRac.h rename to lib/IRremoteESP8266-2.7.0/src/IRac.h index 73ee4b2a3..2fae0084a --- a/lib/IRremoteESP8266-2.6.5/src/IRac.h +++ b/lib/IRremoteESP8266-2.7.0/src/IRac.h @@ -41,6 +41,20 @@ class IRac { explicit IRac(const uint16_t pin, const bool inverted = false, const bool use_modulation = true); static bool isProtocolSupported(const decode_type_t protocol); + static void initState(stdAc::state_t *state, + const decode_type_t vendor, const int16_t model, + const bool power, const stdAc::opmode_t mode, + const float degrees, const bool celsius, + 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, + const int16_t clock); + static void initState(stdAc::state_t *state); + bool sendAc(void); + bool sendAc(const stdAc::state_t desired, const stdAc::state_t *prev = NULL); bool sendAc(const decode_type_t vendor, const int16_t model, const bool power, const stdAc::opmode_t mode, const float degrees, const bool celsius, const stdAc::fanspeed_t fan, @@ -49,7 +63,6 @@ class IRac { const bool light, const bool filter, const bool clean, const bool beep, const int16_t sleep = -1, const int16_t clock = -1); - bool sendAc(const stdAc::state_t desired, const stdAc::state_t *prev = NULL); static bool cmpStates(const stdAc::state_t a, const stdAc::state_t b); static bool strToBool(const char *str, const bool def = false); static int16_t strToModel(const char *str, const int16_t def = -1); @@ -67,6 +80,10 @@ class IRac { static String fanspeedToString(const stdAc::fanspeed_t speed); static String swingvToString(const stdAc::swingv_t swingv); static String swinghToString(const stdAc::swingh_t swingh); + stdAc::state_t getState(void); + stdAc::state_t getStatePrev(void); + bool hasStateChanged(void); + stdAc::state_t next; // The state we want the device to be in after we send. #ifndef UNIT_TEST private: @@ -74,6 +91,7 @@ class IRac { uint16_t _pin; bool _inverted; bool _modulation; + stdAc::state_t _prev; // The state we expect the device to currently be in. #if SEND_AMCOR void amcor(IRAmcorAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, @@ -110,6 +128,13 @@ class IRac { const bool econo, const int16_t sleep = -1, const int16_t clock = -1); #endif // SEND_DAIKIN128 +#if SEND_DAIKIN152 + void daikin152(IRDaikin152 *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 econo); +#endif // SEND_DAIKIN152 #if SEND_DAIKIN160 void daikin160(IRDaikin160 *ac, const bool on, const stdAc::opmode_t mode, @@ -151,7 +176,8 @@ void electra(IRElectraAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, - const bool quiet, const bool turbo, const bool econo); + const bool quiet, const bool turbo, const bool econo, + const bool filter, const bool clean); #endif // SEND_FUJITSU_AC #if SEND_GOODWEATHER void goodweather(IRGoodweatherAc *ac, @@ -190,6 +216,11 @@ void electra(IRElectraAc *ac, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh); #endif // SEND_HITACHI_AC +#if SEND_HITACHI_AC424 + void hitachi424(IRHitachiAc424 *ac, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan); +#endif // SEND_HITACHI_AC424 #if SEND_KELVINATOR void kelvinator(IRKelvinatorAC *ac, const bool on, const stdAc::opmode_t mode, @@ -212,6 +243,20 @@ void electra(IRElectraAc *ac, const stdAc::swingh_t swingh, const bool quiet, const int16_t clock = -1); #endif // SEND_MITSUBISHI_AC +#if SEND_MITSUBISHI112 + void mitsubishi112(IRMitsubishi112 *ac, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, + const stdAc::swingh_t swingh, + const bool quiet); +#endif // SEND_MITSUBISHI112 +#if SEND_MITSUBISHI136 + void mitsubishi136(IRMitsubishi136 *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); +#endif // SEND_MITSUBISHI136 #if SEND_MITSUBISHIHEAVY void mitsubishiHeavy88(IRMitsubishiHeavy88Ac *ac, const bool on, const stdAc::opmode_t mode, @@ -247,7 +292,8 @@ void electra(IRElectraAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const bool quiet, const bool turbo, const bool clean, - const bool beep, const bool dopower = true); + const bool beep, const bool prevpower = true, + const bool forcepower = true); #endif // SEND_SAMSUNG_AC #if SEND_SHARP_AC void sharp(IRSharpAc *ac, diff --git a/lib/IRremoteESP8266-2.6.5/src/IRrecv.cpp b/lib/IRremoteESP8266-2.7.0/src/IRrecv.cpp old mode 100755 new mode 100644 similarity index 98% rename from lib/IRremoteESP8266-2.6.5/src/IRrecv.cpp rename to lib/IRremoteESP8266-2.7.0/src/IRrecv.cpp index 739ced38f..c2c1b5394 --- a/lib/IRremoteESP8266-2.6.5/src/IRrecv.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/IRrecv.cpp @@ -560,11 +560,16 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) { DPRINTLN("Attempting Haier AC YR-W02 decode"); if (decodeHaierACYRW02(results)) return true; #endif +#if DECODE_HITACHI_AC424 + // HitachiAc424 should be checked before HitachiAC & HitachiAC2 + DPRINTLN("Attempting Hitachi AC 424 decode"); + if (decodeHitachiAc424(results, kHitachiAc424Bits)) return true; +#endif // DECODE_HITACHI_AC2 #if DECODE_HITACHI_AC2 // HitachiAC2 should be checked before HitachiAC DPRINTLN("Attempting Hitachi AC2 decode"); if (decodeHitachiAC(results, kHitachiAc2Bits)) return true; -#endif +#endif // DECODE_HITACHI_AC2 #if DECODE_HITACHI_AC DPRINTLN("Attempting Hitachi AC decode"); if (decodeHitachiAC(results, kHitachiAcBits)) return true; @@ -607,10 +612,11 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) { DPRINTLN("Attempting Vestel AC decode"); if (decodeVestelAc(results)) return true; #endif -#if DECODE_TCL112AC - DPRINTLN("Attempting TCL112AC decode"); - if (decodeTcl112Ac(results)) return true; -#endif +#if DECODE_MITSUBISHI112 || DECODE_TCL112AC + // Mitsubish112 and Tcl112 share the same decoder. + DPRINTLN("Attempting Mitsubishi112/TCL112AC decode"); + if (decodeMitsubishi112(results)) return true; +#endif // DECODE_MITSUBISHI112 || DECODE_TCL112AC #if DECODE_TECO DPRINTLN("Attempting Teco decode"); if (decodeTeco(results)) return true; @@ -669,6 +675,11 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) { DPRINTLN("Attempting Daikin152 decode"); if (decodeDaikin152(results)) return true; #endif // DECODE_DAIKIN152 +#if DECODE_MITSUBISHI136 + DPRINTLN("Attempting Mitsubishi136 decode"); + if (decodeMitsubishi136(results)) return true; +#endif // DECODE_MITSUBISHI136 + // Typically new protocols are added above this line. #if DECODE_HASH // decodeHash returns a hash on any input. // Thus, it needs to be last in the list. diff --git a/lib/IRremoteESP8266-2.6.5/src/IRrecv.h b/lib/IRremoteESP8266-2.7.0/src/IRrecv.h old mode 100755 new mode 100644 similarity index 96% rename from lib/IRremoteESP8266-2.6.5/src/IRrecv.h rename to lib/IRremoteESP8266-2.7.0/src/IRrecv.h index 72c168269..2424f0463 --- a/lib/IRremoteESP8266-2.6.5/src/IRrecv.h +++ b/lib/IRremoteESP8266-2.7.0/src/IRrecv.h @@ -254,6 +254,16 @@ class IRrecv { uint16_t nbits = kMitsubishiACBits, bool strict = false); #endif +#if DECODE_MITSUBISHI136 + bool decodeMitsubishi136(decode_results *results, + const uint16_t nbits = kMitsubishi136Bits, + const bool strict = true); +#endif +#if DECODE_MITSUBISHI112 + bool decodeMitsubishi112(decode_results *results, + const uint16_t nbits = kMitsubishi112Bits, + const bool strict = true); +#endif #if DECODE_MITSUBISHIHEAVY bool decodeMitsubishiHeavy(decode_results *results, const uint16_t nbits, const bool strict = true); @@ -436,6 +446,11 @@ class IRrecv { const uint16_t nbits = kHitachiAc1Bits, const bool strict = true); #endif +#if DECODE_HITACHI_AC424 + bool decodeHitachiAc424(decode_results *results, + const uint16_t nbits = kHitachiAc424Bits, + const bool strict = true); +#endif // DECODE_HITACHI_AC424 #if DECODE_GICABLE bool decodeGICable(decode_results *results, uint16_t nbits = kGicableBits, bool strict = true); @@ -472,11 +487,6 @@ class IRrecv { const uint16_t nbits = kVestelAcBits, const bool strict = true); #endif -#if DECODE_TCL112AC - bool decodeTcl112Ac(decode_results *results, - const uint16_t nbits = kTcl112AcBits, - const bool strict = true); -#endif #if DECODE_TECO bool decodeTeco(decode_results *results, const uint16_t nbits = kTecoBits, const bool strict = false); diff --git a/lib/IRremoteESP8266-2.6.5/src/IRremoteESP8266.h b/lib/IRremoteESP8266-2.7.0/src/IRremoteESP8266.h old mode 100755 new mode 100644 similarity index 95% rename from lib/IRremoteESP8266-2.6.5/src/IRremoteESP8266.h rename to lib/IRremoteESP8266-2.7.0/src/IRremoteESP8266.h index 0e1f00fa3..19e44d2fd --- a/lib/IRremoteESP8266-2.6.5/src/IRremoteESP8266.h +++ b/lib/IRremoteESP8266-2.7.0/src/IRremoteESP8266.h @@ -36,6 +36,7 @@ * Carrier & Haier AC code by crankyoldgit * Vestel AC code by Erdem U. Altınyurt * Teco AC code by Fabien Valthier (hcoohb) + * Mitsubishi 112 AC Code by kuchel77 * * GPL license, all text above must be included in any redistribution ****************************************************/ @@ -51,7 +52,13 @@ #endif // UNIT_TEST // Library Version -#define _IRREMOTEESP8266_VERSION_ "2.6.5" +#define _IRREMOTEESP8266_VERSION_ "2.7.0" + +// Set the language & locale for the library. See the `locale` dir for options. +#ifndef _IR_LOCALE_ +#define _IR_LOCALE_ en-AU +#endif // _IR_LOCALE_ + // Supported IR protocols // Each protocol you include costs memory and, during decode, costs time // Disable (set to false) all the protocols you do not need/want! @@ -132,6 +139,12 @@ #define DECODE_MITSUBISHI_AC true // Beta. #define SEND_MITSUBISHI_AC true +#define DECODE_MITSUBISHI136 true +#define SEND_MITSUBISHI136 true + +#define DECODE_MITSUBISHI112 true +#define SEND_MITSUBISHI112 true + #define DECODE_FUJITSU_AC true #define SEND_FUJITSU_AC true @@ -255,6 +268,9 @@ #define DECODE_DAIKIN152 true #define SEND_DAIKIN152 true +#define DECODE_HITACHI_AC424 true +#define SEND_HITACHI_AC424 true + #else // defined(FIRMWARE_IR) || defined(FIRMWARE_IR_CUSTOM) // full IR protocols // Tasmota supported protocols (less protocols is less code size) @@ -448,6 +464,15 @@ #define DECODE_DAIKIN128 false #define SEND_DAIKIN128 true +#define DECODE_AMCOR false +#define SEND_AMCOR true + +#define DECODE_DAIKIN152 false +#define SEND_DAIKIN152 true + +#define DECODE_HITACHI_AC424 false +#define SEND_HITACHI_AC424 true + #endif // defined(FIRMWARE_IR) || defined(FIRMWARE_IR_CUSTOM) // full IR protocols #if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \ @@ -459,7 +484,8 @@ DECODE_VESTEL_AC || DECODE_TCL112AC || DECODE_MITSUBISHIHEAVY || \ DECODE_DAIKIN216 || DECODE_SHARP_AC || DECODE_DAIKIN160 || \ DECODE_NEOCLIMA || DECODE_DAIKIN176 || DECODE_DAIKIN128 || \ - DECODE_AMCOR || DECODE_DAIKIN152) + DECODE_AMCOR || DECODE_DAIKIN152 || DECODE_MITSUBISHI136 || \ + DECODE_MITSUBISHI112 || DECODE_HITACHI_AC424) #define DECODE_AC true // We need some common infrastructure for decoding A/Cs. #else #define DECODE_AC false // We don't need that infrastructure. @@ -549,8 +575,11 @@ enum decode_type_t { DAIKIN128, AMCOR, DAIKIN152, // 70 + MITSUBISHI136, + MITSUBISHI112, + HITACHI_AC424, // Add new entries before this one, and update it to point to the last entry. - kLastDecodeType = DAIKIN152, + kLastDecodeType = HITACHI_AC424, }; // Message lengths & required repeat values @@ -625,6 +654,8 @@ const uint16_t kHitachiAc1StateLength = 13; const uint16_t kHitachiAc1Bits = kHitachiAc1StateLength * 8; const uint16_t kHitachiAc2StateLength = 53; const uint16_t kHitachiAc2Bits = kHitachiAc2StateLength * 8; +const uint16_t kHitachiAc424StateLength = 53; +const uint16_t kHitachiAc424Bits = kHitachiAc424StateLength * 8; const uint16_t kInaxBits = 24; const uint16_t kInaxMinRepeat = kSingleRepeat; const uint16_t kJvcBits = 16; @@ -648,6 +679,12 @@ const uint16_t kMitsubishiMinRepeat = kSingleRepeat; const uint16_t kMitsubishiACStateLength = 18; const uint16_t kMitsubishiACBits = kMitsubishiACStateLength * 8; const uint16_t kMitsubishiACMinRepeat = kSingleRepeat; +const uint16_t kMitsubishi136StateLength = 17; +const uint16_t kMitsubishi136Bits = kMitsubishi136StateLength * 8; +const uint16_t kMitsubishi136MinRepeat = kNoRepeat; +const uint16_t kMitsubishi112StateLength = 14; +const uint16_t kMitsubishi112Bits = kMitsubishi112StateLength * 8; +const uint16_t kMitsubishi112MinRepeat = kNoRepeat; const uint16_t kMitsubishiHeavy88StateLength = 11; const uint16_t kMitsubishiHeavy88Bits = kMitsubishiHeavy88StateLength * 8; const uint16_t kMitsubishiHeavy88MinRepeat = kNoRepeat; diff --git a/lib/IRremoteESP8266-2.6.5/src/IRsend.cpp b/lib/IRremoteESP8266-2.7.0/src/IRsend.cpp old mode 100755 new mode 100644 similarity index 98% rename from lib/IRremoteESP8266-2.6.5/src/IRsend.cpp rename to lib/IRremoteESP8266-2.7.0/src/IRsend.cpp index b094fdff5..18e2eb559 --- a/lib/IRremoteESP8266-2.6.5/src/IRsend.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/IRsend.cpp @@ -608,10 +608,16 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return kHitachiAc1Bits; case HITACHI_AC2: return kHitachiAc2Bits; + case HITACHI_AC424: + return kHitachiAc424Bits; case KELVINATOR: return kKelvinatorBits; case MITSUBISHI_AC: return kMitsubishiACBits; + case MITSUBISHI136: + return kMitsubishi136Bits; + case MITSUBISHI112: + return kMitsubishi112Bits; case MITSUBISHI_HEAVY_152: return kMitsubishiHeavy152Bits; case MITSUBISHI_HEAVY_88: @@ -930,6 +936,11 @@ bool IRsend::send(const decode_type_t type, const unsigned char *state, sendHitachiAC2(state, nbytes); break; #endif // SEND_HITACHI_AC2 +#if SEND_HITACHI_AC424 + case HITACHI_AC424: + sendHitachiAc424(state, nbytes); + break; +#endif // SEND_HITACHI_AC424 #if SEND_KELVINATOR case KELVINATOR: sendKelvinator(state, nbytes); @@ -940,6 +951,16 @@ bool IRsend::send(const decode_type_t type, const unsigned char *state, sendMitsubishiAC(state, nbytes); break; #endif // SEND_MITSUBISHI_AC +#if SEND_MITSUBISHI136 + case MITSUBISHI136: + sendMitsubishi136(state, nbytes); + break; +#endif // SEND_MITSUBISHI136 +#if SEND_MITSUBISHI112 + case MITSUBISHI112: + sendMitsubishi112(state, nbytes); + break; +#endif // SEND_MITSUBISHI112 #if SEND_MITSUBISHIHEAVY case MITSUBISHI_HEAVY_88: sendMitsubishiHeavy88(state, nbytes); diff --git a/lib/IRremoteESP8266-2.6.5/src/IRsend.h b/lib/IRremoteESP8266-2.7.0/src/IRsend.h old mode 100755 new mode 100644 similarity index 92% rename from lib/IRremoteESP8266-2.6.5/src/IRsend.h rename to lib/IRremoteESP8266-2.7.0/src/IRsend.h index cbccee479..b0956e77c --- a/lib/IRremoteESP8266-2.6.5/src/IRsend.h +++ b/lib/IRremoteESP8266-2.7.0/src/IRsend.h @@ -112,6 +112,36 @@ namespace stdAc { } state_t; }; // namespace stdAc + +enum fujitsu_ac_remote_model_t { + ARRAH2E = 1, // (1) AR-RAH2E, AR-RAC1E, AR-RAE1E (Default) + ARDB1, // (2) AR-DB1, AR-DL10 (AR-DL10 swing doesn't work) + ARREB1E, // (3) AR-REB1E + ARJW2, // (4) AR-JW2 (Same as ARDB1 but with horiz control) + ARRY4, // (5) AR-RY4 (Same as AR-RAH2E but with clean & filter) +}; + +enum gree_ac_remote_model_t { + YAW1F = 1, // (1) Ultimate, EKOKAI, RusClimate (Default) + YBOFB, // (2) Green, YBOFB2, YAPOF3 +}; + +enum panasonic_ac_remote_model_t { + kPanasonicUnknown = 0, + kPanasonicLke = 1, + kPanasonicNke = 2, + kPanasonicDke = 3, + kPanasonicJke = 4, + kPanasonicCkp = 5, + kPanasonicRkr = 6, +}; + +enum whirlpool_ac_remote_model_t { + DG11J13A = 1, // DG11J1-04 too + DG11J191, +}; + + // Classes class IRsend { public: @@ -275,6 +305,16 @@ class IRsend { void sendMitsubishi(uint64_t data, uint16_t nbits = kMitsubishiBits, uint16_t repeat = kMitsubishiMinRepeat); #endif +#if SEND_MITSUBISHI136 + void sendMitsubishi136(const unsigned char data[], + const uint16_t nbytes = kMitsubishi136StateLength, + const uint16_t repeat = kMitsubishi136MinRepeat); +#endif +#if SEND_MITSUBISHI112 + void sendMitsubishi112(const unsigned char data[], + const uint16_t nbytes = kMitsubishi112StateLength, + const uint16_t repeat = kMitsubishi112MinRepeat); +#endif #if SEND_MITSUBISHI2 void sendMitsubishi2(uint64_t data, uint16_t nbits = kMitsubishiBits, uint16_t repeat = kMitsubishiMinRepeat); @@ -417,13 +457,18 @@ class IRsend { #if SEND_HITACHI_AC1 void sendHitachiAC1(const unsigned char data[], const uint16_t nbytes = kHitachiAc1StateLength, - const uint16_t repeat = kNoRepeat); + const uint16_t repeat = kHitachiAcDefaultRepeat); #endif #if SEND_HITACHI_AC2 void sendHitachiAC2(const unsigned char data[], const uint16_t nbytes = kHitachiAc2StateLength, - const uint16_t repeat = kNoRepeat); + const uint16_t repeat = kHitachiAcDefaultRepeat); #endif +#if SEND_HITACHI_AC424 + void sendHitachiAc424(const unsigned char data[], + const uint16_t nbytes = kHitachiAc424StateLength, + const uint16_t repeat = kHitachiAcDefaultRepeat); +#endif // SEND_HITACHI_AC424 #if SEND_GICABLE void sendGICable(uint64_t data, uint16_t nbits = kGicableBits, uint16_t repeat = kGicableMinRepeat); diff --git a/lib/IRremoteESP8266-2.7.0/src/IRtext.cpp b/lib/IRremoteESP8266-2.7.0/src/IRtext.cpp new file mode 100644 index 000000000..f7702db9b --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/IRtext.cpp @@ -0,0 +1,149 @@ +// Copyright 2019 - David Conran (@crankyoldgit) + +#ifndef UNIT_TEST +#include +#endif // UNIT_TEST +#include "IRremoteESP8266.h" +#include "i18n.h" + +// Common + +String kUnknownStr = D_STR_UNKNOWN; +String kProtocolStr = D_STR_PROTOCOL; +String kPowerStr = D_STR_POWER; +String kOnStr = D_STR_ON; +String kOffStr = D_STR_OFF; +String kModeStr = D_STR_MODE; +String kToggleStr = D_STR_TOGGLE; +String kTurboStr = D_STR_TURBO; +String kSuperStr = D_STR_SUPER; +String kSleepStr = D_STR_SLEEP; +String kLightStr = D_STR_LIGHT; +String kPowerfulStr = D_STR_POWERFUL; +String kQuietStr = D_STR_QUIET; +String kEconoStr = D_STR_ECONO; +String kSwingStr = D_STR_SWING; +String kSwingHStr = D_STR_SWINGH; +String kSwingVStr = D_STR_SWINGV; +String kBeepStr = D_STR_BEEP; +String kZoneFollowStr = D_STR_ZONEFOLLOW; +String kFixedStr = D_STR_FIXED; +String kMouldStr = D_STR_MOULD; +String kCleanStr = D_STR_CLEAN; +String kPurifyStr = D_STR_PURIFY; +String kTimerStr = D_STR_TIMER; +String kOnTimerStr = D_STR_ONTIMER; +String kOffTimerStr = D_STR_OFFTIMER; +String kClockStr = D_STR_CLOCK; +String kCommandStr = D_STR_COMMAND; +String kXFanStr = D_STR_XFAN; +String kHealthStr = D_STR_HEALTH; +String kModelStr = D_STR_MODEL; +String kTempStr = D_STR_TEMP; +String kIFeelStr = D_STR_IFEEL; +String kHumidStr = D_STR_HUMID; +String kSaveStr = D_STR_SAVE; +String kEyeStr = D_STR_EYE; +String kFollowStr = D_STR_FOLLOW; +String kIonStr = D_STR_ION; +String kFreshStr = D_STR_FRESH; +String kHoldStr = D_STR_HOLD; +String kButtonStr = D_STR_BUTTON; +String k8CHeatStr = D_STR_8C_HEAT; +String kNightStr = D_STR_NIGHT; +String kSilentStr = D_STR_SILENT; +String kFilterStr = D_STR_FILTER; +String k3DStr = D_STR_3D; +String kCelsiusStr = D_STR_CELSIUS; +String kTempUpStr = D_STR_TEMPUP; +String kTempDownStr = D_STR_TEMPDOWN; +String kStartStr = D_STR_START; +String kStopStr = D_STR_STOP; +String kMoveStr = D_STR_MOVE; +String kSetStr = D_STR_SET; +String kCancelStr = D_STR_CANCEL; +String kUpStr = D_STR_UP; +String kDownStr = D_STR_DOWN; +String kChangeStr = D_STR_CHANGE; +String kComfortStr = D_STR_COMFORT; +String kSensorStr = D_STR_SENSOR; +String kWeeklyTimerStr = D_STR_WEEKLYTIMER; +String kWifiStr = D_STR_WIFI; +String kLastStr = D_STR_LAST; +String kFastStr = D_STR_FAST; +String kSlowStr = D_STR_SLOW; +String kAirFlowStr = D_STR_AIRFLOW; +String kStepStr = D_STR_STEP; +String kNAStr = D_STR_NA; +String kOutsideStr = D_STR_OUTSIDE; +String kLoudStr = D_STR_LOUD; +String kLowerStr = D_STR_LOWER; +String kUpperStr = D_STR_UPPER; +String kBreezeStr = D_STR_BREEZE; +String kCirculateStr = D_STR_CIRCULATE; +String kCeilingStr = D_STR_CEILING; +String kWallStr = D_STR_WALL; +String kRoomStr = D_STR_ROOM; +String k6thSenseStr = D_STR_6THSENSE; + +String kAutoStr = D_STR_AUTO; +String kAutomaticStr = D_STR_AUTOMATIC; +String kManualStr = D_STR_MANUAL; +String kCoolStr = D_STR_COOL; +String kHeatStr = D_STR_HEAT; +String kFanStr = D_STR_FAN; +String kDryStr = D_STR_DRY; +String kFanOnlyStr = D_STR_FANONLY; + +String kMaxStr = D_STR_MAX; +String kMaximumStr = D_STR_MAXIMUM; +String kMinStr = D_STR_MIN; +String kMinimumStr = D_STR_MINIMUM; +String kMedStr = D_STR_MED; +String kMediumStr = D_STR_MEDIUM; + +String kHighestStr = D_STR_HIGHEST; +String kHighStr = D_STR_HIGH; +String kHiStr = D_STR_HI; +String kMidStr = D_STR_MID; +String kMiddleStr = D_STR_MIDDLE; +String kLowStr = D_STR_LOW; +String kLoStr = D_STR_LO; +String kLowestStr = D_STR_LOWEST; +String kMaxRightStr = D_STR_MAXRIGHT; +String kRightMaxStr = D_STR_RIGHTMAX_NOSPACE; +String kRightStr = D_STR_RIGHT; +String kLeftStr = D_STR_LEFT; +String kMaxLeftStr = D_STR_MAXLEFT; +String kLeftMaxStr = D_STR_LEFTMAX_NOSPACE; +String kWideStr = D_STR_WIDE; +String kCentreStr = D_STR_CENTRE; +String kTopStr = D_STR_TOP; +String kBottomStr = D_STR_BOTTOM; + +String kSpaceLBraceStr = D_STR_SPACELBRACE; +String kCommaSpaceStr = D_STR_COMMASPACE; +String kColonSpaceStr = D_STR_COLONSPACE; + +// IRutils +// - Time +char kTimeSep = D_CHR_TIME_SEP; +String kDayStr = D_STR_DAY; +String kDaysStr = D_STR_DAYS; +String kHourStr = D_STR_HOUR; +String kHoursStr = D_STR_HOURS; +String kMinuteStr = D_STR_MINUTE; +String kMinutesStr = D_STR_MINUTES; +String kSecondStr = D_STR_SECOND; +String kSecondsStr = D_STR_SECONDS; +String kNowStr = D_STR_NOW; +String kThreeLetterDayOfWeekStr = D_STR_THREELETTERDAYS; + +String kYesStr = D_STR_YES; +String kNoStr = D_STR_NO; +String kTrueStr = D_STR_TRUE; +String kFalseStr = D_STR_FALSE; + +String kRepeatStr = D_STR_REPEAT; +String kCodeStr = D_STR_CODE; +String kBitsStr = D_STR_BITS; diff --git a/lib/IRremoteESP8266-2.7.0/src/IRtext.h b/lib/IRremoteESP8266-2.7.0/src/IRtext.h new file mode 100644 index 000000000..526290c1c --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/IRtext.h @@ -0,0 +1,146 @@ +// Copyright 2019 - David Conran (@crankyoldgit) +// This header file is to be included in files **other than** 'IRtext.cpp'. +// +// WARNING: Do not edit this file! This file is automatically generated by +// 'tools/generate_irtext_h.sh'. + +#ifndef IRTEXT_H_ +#define IRTEXT_H_ + +#include "i18n.h" + +// Constant text to be shared across all object files. +// This means there is only one copy of the character/string/text etc. + +extern const char kTimeSep; +extern const String k3DStr; +extern const String k6thSenseStr; +extern const String k8CHeatStr; +extern const String kAirFlowStr; +extern const String kAutomaticStr; +extern const String kAutoStr; +extern const String kBeepStr; +extern const String kBitsStr; +extern const String kBottomStr; +extern const String kBreezeStr; +extern const String kButtonStr; +extern const String kCancelStr; +extern const String kCeilingStr; +extern const String kCelsiusStr; +extern const String kCentreStr; +extern const String kChangeStr; +extern const String kCirculateStr; +extern const String kCleanStr; +extern const String kClockStr; +extern const String kCodeStr; +extern const String kColonSpaceStr; +extern const String kComfortStr; +extern const String kCommandStr; +extern const String kCommaSpaceStr; +extern const String kCoolStr; +extern const String kDaysStr; +extern const String kDayStr; +extern const String kDownStr; +extern const String kDryStr; +extern const String kEconoStr; +extern const String kEyeStr; +extern const String kFalseStr; +extern const String kFanOnlyStr; +extern const String kFanStr; +extern const String kFastStr; +extern const String kFilterStr; +extern const String kFixedStr; +extern const String kFollowStr; +extern const String kFreshStr; +extern const String kHealthStr; +extern const String kHeatStr; +extern const String kHighestStr; +extern const String kHighStr; +extern const String kHiStr; +extern const String kHoldStr; +extern const String kHoursStr; +extern const String kHourStr; +extern const String kHumidStr; +extern const String kIFeelStr; +extern const String kIonStr; +extern const String kLastStr; +extern const String kLeftMaxStr; +extern const String kLeftStr; +extern const String kLightStr; +extern const String kLoStr; +extern const String kLoudStr; +extern const String kLowerStr; +extern const String kLowestStr; +extern const String kLowStr; +extern const String kManualStr; +extern const String kMaximumStr; +extern const String kMaxLeftStr; +extern const String kMaxRightStr; +extern const String kMaxStr; +extern const String kMediumStr; +extern const String kMedStr; +extern const String kMiddleStr; +extern const String kMidStr; +extern const String kMinimumStr; +extern const String kMinStr; +extern const String kMinutesStr; +extern const String kMinuteStr; +extern const String kModelStr; +extern const String kModeStr; +extern const String kMouldStr; +extern const String kMoveStr; +extern const String kNAStr; +extern const String kNightStr; +extern const String kNoStr; +extern const String kNowStr; +extern const String kOffStr; +extern const String kOffTimerStr; +extern const String kOnStr; +extern const String kOnTimerStr; +extern const String kOutsideStr; +extern const String kPowerfulStr; +extern const String kPowerStr; +extern const String kProtocolStr; +extern const String kPurifyStr; +extern const String kQuietStr; +extern const String kRepeatStr; +extern const String kRightMaxStr; +extern const String kRightStr; +extern const String kRoomStr; +extern const String kSaveStr; +extern const String kSecondsStr; +extern const String kSecondStr; +extern const String kSensorStr; +extern const String kSetStr; +extern const String kSilentStr; +extern const String kSleepStr; +extern const String kSlowStr; +extern const String kSpaceLBraceStr; +extern const String kStartStr; +extern const String kStepStr; +extern const String kStopStr; +extern const String kSuperStr; +extern const String kSwingHStr; +extern const String kSwingStr; +extern const String kSwingVStr; +extern const String kTempDownStr; +extern const String kTempStr; +extern const String kTempUpStr; +extern const String kThreeLetterDayOfWeekStr; +extern const String kTimerStr; +extern const String kToggleStr; +extern const String kTopStr; +extern const String kTrueStr; +extern const String kTurboStr; +extern const String kUnknownStr; +extern const String kUpperStr; +extern const String kUpStr; +extern const String kWallStr; +extern const String kWeeklyTimerStr; +extern const String kWideStr; +extern const String kWifiStr; +extern const String kXFanStr; +extern const String kYesStr; +extern const String kZoneFollowStr; + +#endif // IRTEXT_H_ diff --git a/lib/IRremoteESP8266-2.6.5/src/IRtimer.cpp b/lib/IRremoteESP8266-2.7.0/src/IRtimer.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/IRtimer.cpp rename to lib/IRremoteESP8266-2.7.0/src/IRtimer.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/IRtimer.h b/lib/IRremoteESP8266-2.7.0/src/IRtimer.h old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/IRtimer.h rename to lib/IRremoteESP8266-2.7.0/src/IRtimer.h diff --git a/lib/IRremoteESP8266-2.6.5/src/IRutils.cpp b/lib/IRremoteESP8266-2.7.0/src/IRutils.cpp old mode 100755 new mode 100644 similarity index 70% rename from lib/IRremoteESP8266-2.6.5/src/IRutils.cpp rename to lib/IRremoteESP8266-2.7.0/src/IRutils.cpp index 6f589aa3d..76a3db307 --- a/lib/IRremoteESP8266-2.6.5/src/IRutils.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/IRutils.cpp @@ -14,6 +14,8 @@ #endif #include "IRrecv.h" #include "IRremoteESP8266.h" +#include "IRsend.h" +#include "IRtext.h" // Reverse the order of the requested least significant nr. of bits. // Args: @@ -89,7 +91,7 @@ void serialPrintUint64(uint64_t input, uint8_t base) { // Returns: // A decode_type_t enum. decode_type_t strToDecodeType(const char * const str) { - if (!strcasecmp(str, "UNKNOWN")) + if (!strcasecmp(str, kUnknownStr.c_str())) return decode_type_t::UNKNOWN; else if (!strcasecmp(str, "UNUSED")) return decode_type_t::UNUSED; @@ -143,6 +145,8 @@ decode_type_t strToDecodeType(const char * const str) { return decode_type_t::HITACHI_AC1; else if (!strcasecmp(str, "HITACHI_AC2")) return decode_type_t::HITACHI_AC2; + else if (!strcasecmp(str, "HITACHI_AC424")) + return decode_type_t::HITACHI_AC424; else if (!strcasecmp(str, "INAX")) return decode_type_t::INAX; else if (!strcasecmp(str, "JVC")) @@ -169,6 +173,10 @@ decode_type_t strToDecodeType(const char * const str) { return decode_type_t::MITSUBISHI2; else if (!strcasecmp(str, "MITSUBISHI_AC")) return decode_type_t::MITSUBISHI_AC; + else if (!strcasecmp(str, "MITSUBISHI136")) + return decode_type_t::MITSUBISHI136; + else if (!strcasecmp(str, "MITSUBISHI112")) + return decode_type_t::MITSUBISHI112; else if (!strcasecmp(str, "MITSUBISHI_HEAVY_88")) return decode_type_t::MITSUBISHI_HEAVY_88; else if (!strcasecmp(str, "MITSUBISHI_HEAVY_152")) @@ -330,6 +338,9 @@ String typeToString(const decode_type_t protocol, const bool isRepeat) { case HITACHI_AC2: result = F("HITACHI_AC2"); break; + case HITACHI_AC424: + result = F("HITACHI_AC424"); + break; case INAX: result = F("INAX"); break; @@ -369,6 +380,12 @@ String typeToString(const decode_type_t protocol, const bool isRepeat) { case MITSUBISHI_AC: result = F("MITSUBISHI_AC"); break; + case MITSUBISHI136: + result = F("MITSUBISHI136"); + break; + case MITSUBISHI112: + result = F("MITSUBISHI112"); + break; case MITSUBISHI_HEAVY_88: result = F("MITSUBISHI_HEAVY_88"); break; @@ -467,10 +484,10 @@ String typeToString(const decode_type_t protocol, const bool isRepeat) { break; case UNKNOWN: default: - result = F("UNKNOWN"); + result = kUnknownStr; break; } - if (isRepeat) result += F(" (Repeat)"); + if (isRepeat) result += kSpaceLBraceStr + kRepeatStr + ')'; return result; } @@ -494,7 +511,10 @@ bool hasACState(const decode_type_t protocol) { case HITACHI_AC: case HITACHI_AC1: case HITACHI_AC2: + case HITACHI_AC424: case KELVINATOR: + case MITSUBISHI136: + case MITSUBISHI112: case MITSUBISHI_AC: case MITSUBISHI_HEAVY_88: case MITSUBISHI_HEAVY_152: @@ -555,7 +575,7 @@ String resultToSourceCode(const decode_results * const results) { } output += uint64ToString(usecs, 10); if (i < results->rawlen - 1) - output += F(", "); // ',' not needed on the last one + output += kCommaSpaceStr; // ',' not needed on the last one if (i % 2 == 0) output += ' '; // Extra if it was even. } @@ -582,7 +602,7 @@ String resultToSourceCode(const decode_results * const results) { output += F("0x"); if (results->state[i] < 0x10) output += '0'; output += uint64ToString(results->state[i], 16); - if (i < nbytes - 1) output += F(", "); + if (i < nbytes - 1) output += kCommaSpaceStr; } output += F("};\n"); #endif // DECODE_AC @@ -630,7 +650,7 @@ String resultToTimingInfo(const decode_results * const results) { while (value.length() < 6) value = ' ' + value; output += value; if (i < results->rawlen - 1) - output += F(", "); // ',' not needed for last one + output += kCommaSpaceStr; // ',' not needed for last one if (!(i % 8)) output += '\n'; // Newline every 8 entries. } output += '\n'; @@ -640,9 +660,9 @@ String resultToTimingInfo(const decode_results * const results) { // Convert the decode_results structure's value/state to simple hexadecimal. // String resultToHexidecimal(const decode_results * const result) { - String output = ""; + String output = F("0x"); // Reserve some space for the string to reduce heap fragmentation. - output.reserve(2 * kStateSizeMax); // Should cover worst cases. + output.reserve(2 * kStateSizeMax + 2); // Should cover worst cases. if (hasACState(result->decode_type)) { #if DECODE_AC for (uint16_t i = 0; result->bits > i * 8; i++) { @@ -663,16 +683,16 @@ String resultToHumanReadableBasic(const decode_results * const results) { // Reserve some space for the string to reduce heap fragmentation. output.reserve(2 * kStateSizeMax + 50); // Should cover most cases. // Show Encoding standard - output += F("Encoding : "); + output += kProtocolStr + F(" : "); output += typeToString(results->decode_type, results->repeat); output += '\n'; // Show Code & length - output += F("Code : "); + output += kCodeStr + F(" : "); output += resultToHexidecimal(results); - output += F(" ("); + output += kSpaceLBraceStr; output += uint64ToString(results->bits); - output += F(" bits)\n"); + output += ' ' + kBitsStr + F(")\n"); return output; } @@ -778,15 +798,15 @@ namespace irutils { String addLabeledString(const String value, const String label, const bool precomma) { String result = ""; - if (precomma) result += F(", "); + if (precomma) result += kCommaSpaceStr; result += label; - result += F(": "); + result += kColonSpaceStr; return result + value; } String addBoolToString(const bool value, const String label, const bool precomma) { - return addLabeledString((value ? F("On") : F("Off")), label, precomma); + return addLabeledString((value ? kOnStr : kOffStr), label, precomma); } String addIntToString(const uint16_t value, const String label, @@ -794,9 +814,58 @@ namespace irutils { return addLabeledString(uint64ToString(value), label, precomma); } + String modelToStr(const decode_type_t protocol, const int16_t model) { + switch (protocol) { + 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"); + default: return kUnknownStr; + } + break; + 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"); + 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"); + 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"); + default: return kUnknownStr; + } + break; + default: return kUnknownStr; + } + } + + String addModelToString(const decode_type_t protocol, const int16_t model, + const bool precomma) { + String result = addIntToString(model, kModelStr, precomma); + result += kSpaceLBraceStr; + result += modelToStr(protocol, model); + return result + ')'; + } + String addTempToString(const uint16_t degrees, const bool celsius, const bool precomma) { - String result = addIntToString(degrees, F("Temp"), precomma); + String result = addIntToString(degrees, kTempStr, precomma); result += celsius ? 'C' : 'F'; return result; } @@ -804,30 +873,47 @@ namespace irutils { String addModeToString(const uint8_t mode, const uint8_t automatic, const uint8_t cool, const uint8_t heat, const uint8_t dry, const uint8_t fan) { - String result = addIntToString(mode, F("Mode")); - result += F(" ("); - if (mode == automatic) result += F("AUTO"); - else if (mode == cool) result += F("COOL"); - else if (mode == heat) result += F("HEAT"); - else if (mode == dry) result += F("DRY"); - else if (mode == fan) result += F("FAN"); + String result = addIntToString(mode, kModeStr); + result += kSpaceLBraceStr; + if (mode == automatic) result += kAutoStr; + else if (mode == cool) result += kCoolStr; + else if (mode == heat) result += kHeatStr; + else if (mode == dry) result += kDryStr; + else if (mode == fan) result += kFanStr; else - result += F("UNKNOWN"); + result += kUnknownStr; + return result + ')'; + } + + String addDayToString(const uint8_t day_of_week, const int8_t offset, + const bool precomma) { + String result = addIntToString(day_of_week, kDayStr, precomma); + result += kSpaceLBraceStr; + if ((uint8_t)(day_of_week + offset) < 7) +#if UNIT_TEST + result += kThreeLetterDayOfWeekStr.substr( + (day_of_week + offset) * 3, 3); +#else // UNIT_TEST + result += kThreeLetterDayOfWeekStr.substring( + (day_of_week + offset) * 3, (day_of_week + offset) * 3 + 3); +#endif // UNIT_TEST + else + result += kUnknownStr; return result + ')'; } String addFanToString(const uint8_t speed, const uint8_t high, const uint8_t low, const uint8_t automatic, const uint8_t quiet, const uint8_t medium) { - String result = addIntToString(speed, F("Fan")); - result += F(" ("); - if (speed == high) result += F("High"); - else if (speed == low) result += F("Low"); - else if (speed == automatic) result += F("Auto"); - else if (speed == quiet) result += F("Quiet"); - else if (speed == medium) result += F("Medium"); + String result = addIntToString(speed, kFanStr); + result += kSpaceLBraceStr; + if (speed == high) result += kHighStr; + else if (speed == low) result += kLowStr; + else if (speed == automatic) result += kAutoStr; + else if (speed == quiet) result += kQuietStr; + else if (speed == medium) result += kMediumStr; else - result += F("UNKNOWN"); + result += kUnknownStr; return result + ')'; } @@ -895,7 +981,7 @@ namespace irutils { String msToString(uint32_t const msecs) { uint32_t totalseconds = msecs / 1000; - if (totalseconds == 0) return F("Now"); + if (totalseconds == 0) return kNowStr; // Note: uint32_t can only hold up to 45 days, so uint8_t is safe. uint8_t days = totalseconds / (60 * 60 * 24); @@ -904,24 +990,22 @@ namespace irutils { uint8_t seconds = totalseconds % 60; String result = ""; - if (days) { - result += uint64ToString(days) + F(" day"); - if (days > 1) result += 's'; - } + if (days) + result += uint64ToString(days) + ' ' + ((days > 1) ? kDaysStr : kDayStr); if (hours) { if (result.length()) result += ' '; - result += uint64ToString(hours) + F(" hour"); - if (hours > 1) result += 's'; + result += uint64ToString(hours) + ' ' + ((hours > 1) ? kHoursStr + : kHourStr); } if (minutes) { if (result.length()) result += ' '; - result += uint64ToString(minutes) + F(" minute"); - if (minutes > 1) result += 's'; + result += uint64ToString(minutes) + ' ' + ((minutes > 1) ? kMinutesStr + : kMinuteStr); } if (seconds) { if (result.length()) result += ' '; - result += uint64ToString(seconds) + F(" second"); - if (seconds > 1) result += 's'; + result += uint64ToString(seconds) + ' ' + ((seconds > 1) ? kSecondsStr + : kSecondStr); } return result; } @@ -930,7 +1014,7 @@ namespace irutils { String result = ""; result.reserve(5); // 23:59 is the typical worst case. if (mins / 60 < 10) result += '0'; // Zero pad the hours - result += uint64ToString(mins / 60) + ':'; + result += uint64ToString(mins / 60) + kTimeSep; if (mins % 60 < 10) result += '0'; // Zero pad the minutes. result += uint64ToString(mins % 60); return result; @@ -961,4 +1045,152 @@ namespace irutils { if (integer > 99) return 255; // Too big. return ((integer / 10) << 4) + (integer % 10); } + + // Return the value of `position`th bit of `data`. + // Args: + // data: Value to be examined. + // position: Nr. of the nth bit to be examined. `0` is the LSB. + // size: Nr. of bits in data. + bool getBit(const uint64_t data, const uint8_t position, const uint8_t size) { + if (position >= size) return false; // Outside of range. + return data & (1ULL << position); + } + + // Return the value of `position`th bit of `data`. + // Args: + // data: Value to be examined. + // position: Nr. of the nth bit to be examined. `0` is the LSB. + bool getBit(const uint8_t data, const uint8_t position) { + if (position >= 8) return false; // Outside of range. + return data & (1 << position); + } + + // Return the value of `data` with the `position`th bit changed to `on` + // Args: + // data: Value to be changed. + // position: Nr. of the bit to be changed. `0` is the LSB. + // on: Value to set the position'th bit to. + // size: Nr. of bits in data. + uint64_t setBit(const uint64_t data, const uint8_t position, const bool on, + const uint8_t size) { + if (position >= size) return data; // Outside of range. + uint64_t mask = 1ULL << position; + if (on) + return data | mask; + else + return data & ~mask; + } + + // Return the value of `data` with the `position`th bit changed to `on` + // Args: + // data: Value to be changed. + // position: Nr. of the bit to be changed. `0` is the LSB. + // on: Value to set the position'th bit to. + uint8_t setBit(const uint8_t data, const uint8_t position, const bool on) { + if (position >= 8) return data; // Outside of range. + uint8_t mask = 1 << position; + if (on) + return data | mask; + else + return data & ~mask; + } + + // Change the value at the location `data_ptr` with the `position`th bit + // changed to `on` + // Args: + // data: Ptr to the data to be changed. + // position: Nr. of the bit to be changed. `0` is the LSB. + // on: Value to set the position'th bit to. + void setBit(uint8_t * const data, const uint8_t position, const bool on) { + uint8_t mask = 1 << position; + if (on) + *data |= mask; + else + *data &= ~mask; + } + + // Change the value at the location `data_ptr` with the `position`th bit + // changed to `on` + // Args: + // data: Ptr to the data to be changed. + // position: Nr. of the bit to be changed. `0` is the LSB. + // on: Value to set the position'th bit to. + void setBit(uint32_t * const data, const uint8_t position, const bool on) { + uint32_t mask = (uint32_t)1 << position; + if (on) + *data |= mask; + else + *data &= ~mask; + } + + // Change the value at the location `data_ptr` with the `position`th bit + // changed to `on` + // Args: + // data: Ptr to the data to be changed. + // position: Nr. of the bit to be changed. `0` is the LSB. + // on: Value to set the position'th bit to. + void setBit(uint64_t * const data, const uint8_t position, const bool on) { + uint64_t mask = (uint64_t)1 << position; + if (on) + *data |= mask; + else + *data &= ~mask; + } + + // Change the uint8_t pointed to by `dst` starting at the `offset`th bit + // and for `nbits` bits, with the contents of `data`. + // Args: + // dst: Ptr to the uint8_t to be changed. + // offset: Nr. of bits from the Least Significant Bit to be ignored. + // nbits: Nr of bits of `data` to be placed into the destination uint8_t. + // data: Value to be placed into dst. + void setBits(uint8_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint8_t data) { + if (offset >= 8 || !nbits) return; // Short circuit as it won't change. + // Calculate the mask for the supplied value. + uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits)); + // Calculate the mask & clear the space for the data. + // Clear the destination bits. + *dst &= ~(uint8_t)(mask << offset); + // Merge in the data. + *dst |= ((data & mask) << offset); + } + + // Change the uint32_t pointed to by `dst` starting at the `offset`th bit + // and for `nbits` bits, with the contents of `data`. + // Args: + // dst: Ptr to the uint32_t to be changed. + // offset: Nr. of bits from the Least Significant Bit to be ignored. + // nbits: Nr of bits of `data` to be placed into the destination uint32_t. + // data: Value to be placed into dst. + void setBits(uint32_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint32_t data) { + if (offset >= 32 || !nbits) return; // Short circuit as it won't change. + // Calculate the mask for the supplied value. + uint32_t mask = UINT32_MAX >> (32 - ((nbits > 32) ? 32 : nbits)); + // Calculate the mask & clear the space for the data. + // Clear the destination bits. + *dst &= ~(mask << offset); + // Merge in the data. + *dst |= ((data & mask) << offset); + } + + // Change the uint64_t pointed to by `dst` starting at the `offset`th bit + // and for `nbits` bits, with the contents of `data`. + // Args: + // dst: Ptr to the uint64_t to be changed. + // offset: Nr. of bits from the Least Significant Bit to be ignored. + // nbits: Nr of bits of `data` to be placed into the destination uint64_t. + // data: Value to be placed into dst. + void setBits(uint64_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint64_t data) { + if (offset >= 64 || !nbits) return; // Short circuit as it won't change. + // Calculate the mask for the supplied value. + uint64_t mask = UINT64_MAX >> (64 - ((nbits > 64) ? 64 : nbits)); + // Calculate the mask & clear the space for the data. + // Clear the destination bits. + *dst &= ~(mask << offset); + // Merge in the data. + *dst |= ((data & mask) << offset); + } } // namespace irutils diff --git a/lib/IRremoteESP8266-2.6.5/src/IRutils.h b/lib/IRremoteESP8266-2.7.0/src/IRutils.h old mode 100755 new mode 100644 similarity index 57% rename from lib/IRremoteESP8266-2.6.5/src/IRutils.h rename to lib/IRremoteESP8266-2.7.0/src/IRutils.h index 8d4226577..34319134a --- a/lib/IRremoteESP8266-2.6.5/src/IRutils.h +++ b/lib/IRremoteESP8266-2.7.0/src/IRutils.h @@ -14,6 +14,10 @@ #include "IRremoteESP8266.h" #include "IRrecv.h" +const uint8_t kNibbleSize = 4; +const uint8_t kLowNibble = 0; +const uint8_t kHighNibble = 4; +const uint8_t kModeBitsSize = 3; uint64_t reverseBits(uint64_t input, uint16_t nbits); String uint64ToString(uint64_t input, uint8_t base = 10); String typeToString(const decode_type_t protocol, @@ -43,6 +47,9 @@ namespace irutils { const bool precomma = true); String addIntToString(const uint16_t value, const String label, const bool precomma = true); + String modelToStr(const decode_type_t protocol, const int16_t model); + String addModelToString(const decode_type_t protocol, const int16_t model, + const bool precomma = true); String addLabeledString(const String value, const String label, const bool precomma = true); String addTempToString(const uint16_t degrees, const bool celsius = true, @@ -53,6 +60,8 @@ namespace irutils { String addFanToString(const uint8_t speed, const uint8_t high, const uint8_t low, const uint8_t automatic, const uint8_t quiet, const uint8_t medium); + String addDayToString(const uint8_t day_of_week, const int8_t offset = 0, + const bool precomma = true); String htmlEscape(const String unescaped); String msToString(uint32_t const msecs); String minsToString(const uint16_t mins); @@ -60,5 +69,39 @@ namespace irutils { const uint8_t init = 0); uint8_t bcdToUint8(const uint8_t bcd); uint8_t uint8ToBcd(const uint8_t integer); + 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 GETBITS8(data, offset, size) \ + (((data) & (((uint8_t)UINT8_MAX >> (8 - (size))) << (offset))) >> (offset)) +#define GETBITS16(data, offset, size) \ + (((data) & (((uint16_t)UINT16_MAX >> (16 - (size))) << (offset))) >> \ + (offset)) +#define GETBITS32(data, offset, size) \ + (((data) & (((uint32_t)UINT32_MAX >> (32 - (size))) << (offset))) >> \ + (offset)) +#define GETBITS64(data, offset, size) \ + (((data) & (((uint64_t)UINT64_MAX >> (64 - (size))) << (offset))) >> \ + (offset)) + uint64_t setBit(const uint64_t data, const uint8_t position, + const bool on = true, const uint8_t size = 64); + uint8_t setBit(const uint8_t data, const uint8_t position, + const bool on = true); + void setBit(uint8_t * const data, const uint8_t position, + const bool on = true); + void setBit(uint32_t * const data, const uint8_t position, + const bool on = true); + void setBit(uint64_t * const data, const uint8_t position, + const bool on = true); + void setBits(uint8_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint8_t data); + void setBits(uint32_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint32_t data); + void setBits(uint64_t * const dst, const uint8_t offset, const uint8_t nbits, + const uint64_t data); } // namespace irutils #endif // IRUTILS_H_ diff --git a/lib/IRremoteESP8266-2.7.0/src/i18n.h b/lib/IRremoteESP8266-2.7.0/src/i18n.h new file mode 100644 index 000000000..27ac4d714 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/i18n.h @@ -0,0 +1,25 @@ +// Copyright 2019 - David Conran (@crankyoldgit) + +#ifndef I18N_H_ +#define I18N_H_ + +#include "IRremoteESP8266.h" + +// Load the appropriate locale header file. +#ifndef _IR_LOCALE_ +#define _IR_LOCALE_ en-AU +#endif // _IR_LOCALE_ + +#define ENQUOTE_(x) #x +#define ENQUOTE(x) ENQUOTE_(x) + +// Load the desired/requested locale. +#ifdef _IR_LOCALE_ +#include ENQUOTE(locale/_IR_LOCALE_.h) +#endif // _IR_LOCALE_ + +// Now that any specific locale has been loaded, we can safely load the defaults +// as the defaults should not override anything that has now set. +#include "locale/defaults.h" + +#endif // I18N_H_ diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Aiwa.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Aiwa.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Aiwa.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Aiwa.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Amcor.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Amcor.cpp old mode 100755 new mode 100644 similarity index 82% rename from lib/IRremoteESP8266-2.6.5/src/ir_Amcor.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Amcor.cpp index 8c0b73c8c..b36c6d15a --- a/lib/IRremoteESP8266-2.6.5/src/ir_Amcor.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Amcor.cpp @@ -7,8 +7,10 @@ #include "ir_Amcor.h" #include +#include #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // Constants @@ -28,6 +30,7 @@ using irutils::addBoolToString; using irutils::addModeToString; using irutils::addFanToString; using irutils::addTempToString; +using irutils::setBits; #if SEND_AMCOR // Send a Amcor HVAC formatted message. @@ -104,8 +107,7 @@ void IRAmcorAc::begin(void) { _irsend.begin(); } #if SEND_AMCOR void IRAmcorAc::send(const uint16_t repeat) { - this->checksum(); // Create valid checksum before sending - _irsend.sendAmcor(remote_state, kAmcorStateLength, repeat); + _irsend.sendAmcor(getRaw(), kAmcorStateLength, repeat); } #endif // SEND_AMCOR @@ -136,7 +138,7 @@ uint8_t* IRAmcorAc::getRaw(void) { } void IRAmcorAc::setRaw(const uint8_t state[]) { - for (uint8_t i = 0; i < kAmcorStateLength; i++) remote_state[i] = state[i]; + memcpy(remote_state, state, kAmcorStateLength); } void IRAmcorAc::on(void) { setPower(true); } @@ -144,49 +146,45 @@ void IRAmcorAc::on(void) { setPower(true); } void IRAmcorAc::off(void) { setPower(false); } void IRAmcorAc::setPower(const bool on) { - remote_state[kAmcorPowerByte] &= ~kAmcorPowerMask; - remote_state[kAmcorPowerByte] |= (on ? kAmcorPowerOn : kAmcorPowerOff); + setBits(&remote_state[kAmcorPowerByte], kAmcorPowerOffset, kAmcorPowerSize, + on ? kAmcorPowerOn : kAmcorPowerOff); } bool IRAmcorAc::getPower(void) { - return ((remote_state[kAmcorPowerByte] & kAmcorPowerMask) == kAmcorPowerOn); + return GETBITS8(remote_state[kAmcorPowerByte], kAmcorPowerOffset, + kAmcorPowerSize) == kAmcorPowerOn; } // Set the temp in deg C void IRAmcorAc::setTemp(const uint8_t degrees) { uint8_t temp = std::max(kAmcorMinTemp, degrees); temp = std::min(kAmcorMaxTemp, temp); - - temp <<= 1; - remote_state[kAmcorTempByte] &= ~kAmcorTempMask; - remote_state[kAmcorTempByte] |= temp; + setBits(&remote_state[kAmcorTempByte], kAmcorTempOffset, kAmcorTempSize, + temp); } uint8_t IRAmcorAc::getTemp(void) { - return (remote_state[kAmcorTempByte] & kAmcorTempMask) >> 1; + return GETBITS8(remote_state[kAmcorTempByte], kAmcorTempOffset, + kAmcorTempSize); } // Maximum Cooling or Hearing void IRAmcorAc::setMax(const bool on) { if (on) { switch (getMode()) { - case kAmcorCool: - setTemp(kAmcorMinTemp); - break; - case kAmcorHeat: - setTemp(kAmcorMaxTemp); - break; - default: // Not allowed in all other operating modes. - return; + case kAmcorCool: setTemp(kAmcorMinTemp); break; + case kAmcorHeat: setTemp(kAmcorMaxTemp); break; + // Not allowed in all other operating modes. + default: return; } - remote_state[kAmcorSpecialByte] |= kAmcorMaxMask; - } else { - remote_state[kAmcorSpecialByte] &= ~kAmcorMaxMask; } + setBits(&remote_state[kAmcorSpecialByte], kAmcorMaxOffset, kAmcorMaxSize, + on ? kAmcorMax : 0); } bool IRAmcorAc::getMax(void) { - return ((remote_state[kAmcorSpecialByte] & kAmcorMaxMask) == kAmcorMaxMask); + return GETBITS8(remote_state[kAmcorSpecialByte], kAmcorMaxOffset, + kAmcorMaxSize) == kAmcorMax; } // Set the speed of the fan @@ -196,8 +194,8 @@ void IRAmcorAc::setFan(const uint8_t speed) { case kAmcorFanMin: case kAmcorFanMed: case kAmcorFanMax: - remote_state[kAmcorModeFanByte] &= ~kAmcorFanMask; - remote_state[kAmcorModeFanByte] |= speed << 4; + setBits(&remote_state[kAmcorModeFanByte], kAmcorFanOffset, kAmcorFanSize, + speed); break; default: setFan(kAmcorFanAuto); @@ -205,27 +203,26 @@ void IRAmcorAc::setFan(const uint8_t speed) { } uint8_t IRAmcorAc::getFan(void) { - return (remote_state[kAmcorModeFanByte] & kAmcorFanMask) >> 4; + return GETBITS8(remote_state[kAmcorModeFanByte], kAmcorFanOffset, + kAmcorFanSize); } uint8_t IRAmcorAc::getMode(void) { - return remote_state[kAmcorModeFanByte] & kAmcorModeMask; + return GETBITS8(remote_state[kAmcorModeFanByte], kAmcorModeOffset, + kAmcorModeSize); } void IRAmcorAc::setMode(const uint8_t mode) { - remote_state[kAmcorSpecialByte] &= ~kAmcorVentMask; // Clear the vent setting switch (mode) { case kAmcorFan: - remote_state[kAmcorSpecialByte] |= kAmcorVentMask; // Set the vent option - // FALL-THRU case kAmcorCool: case kAmcorHeat: case kAmcorDry: case kAmcorAuto: - // Mask out bits - remote_state[kAmcorModeFanByte] &= ~kAmcorModeMask; - // Set the mode at bit positions - remote_state[kAmcorModeFanByte] |= mode; + setBits(&remote_state[kAmcorSpecialByte], kAmcorVentOffset, + kAmcorVentSize, (mode == kAmcorFan) ? kAmcorVentOn : 0); + setBits(&remote_state[kAmcorModeFanByte], kAmcorModeOffset, + kAmcorModeSize, mode); return; default: this->setMode(kAmcorAuto); @@ -311,16 +308,16 @@ stdAc::state_t IRAmcorAc::toCommon(void) { } // Convert the internal state into a human readable string. -String IRAmcorAc::toString() { +String IRAmcorAc::toString(void) { String result = ""; result.reserve(70); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kAmcorAuto, kAmcorCool, kAmcorHeat, kAmcorDry, kAmcorFan); result += addFanToString(getFan(), kAmcorFanMax, kAmcorFanMin, kAmcorFanAuto, kAmcorFanAuto, kAmcorFanMed); result += addTempToString(getTemp()); - result += addBoolToString(getMax(), F("Max")); + result += addBoolToString(getMax(), kMaxStr); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Amcor.h b/lib/IRremoteESP8266-2.7.0/src/ir_Amcor.h old mode 100755 new mode 100644 similarity index 83% rename from lib/IRremoteESP8266-2.6.5/src/ir_Amcor.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Amcor.h index 73beb27a7..fa8aa1edd --- a/lib/IRremoteESP8266-2.6.5/src/ir_Amcor.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Amcor.h @@ -35,36 +35,44 @@ const uint8_t kAmcorFanMin = 0b001; const uint8_t kAmcorFanMed = 0b010; const uint8_t kAmcorFanMax = 0b011; const uint8_t kAmcorFanAuto = 0b100; -const uint8_t kAmcorFanMask = 0b01110000; +const uint8_t kAmcorFanOffset = 4; +const uint8_t kAmcorFanSize = 3; // Modes const uint8_t kAmcorCool = 0b001; const uint8_t kAmcorHeat = 0b010; const uint8_t kAmcorFan = 0b011; // Aka "Vent" const uint8_t kAmcorDry = 0b100; const uint8_t kAmcorAuto = 0b101; -const uint8_t kAmcorModeMask = 0b00000111; +const uint8_t kAmcorModeOffset = 0; +const uint8_t kAmcorModeSize = 3; // state[2] const uint8_t kAmcorTempByte = 2; // Temperature const uint8_t kAmcorMinTemp = 12; // Celsius const uint8_t kAmcorMaxTemp = 32; // Celsius -const uint8_t kAmcorTempMask = 0b01111110; +const uint8_t kAmcorTempOffset = 1; +const uint8_t kAmcorTempSize = 6; // Bits // state[5] // Power const uint8_t kAmcorPowerByte = 5; -const uint8_t kAmcorPowerMask = 0b11110000; -const uint8_t kAmcorPowerOn = 0b00110000; // 0x30 -const uint8_t kAmcorPowerOff = 0b11000000; // 0xC0 +const uint8_t kAmcorPowerOffset = 4; +const uint8_t kAmcorPowerSize = 4; +const uint8_t kAmcorPowerOn = 0b0011; // 0x3 +const uint8_t kAmcorPowerOff = 0b1100; // 0xC // state[6] const uint8_t kAmcorSpecialByte = 6; // Max Mode (aka "Lo" in Cool and "Hi" in Heat) -const uint8_t kAmcorMaxMask = 0b00000011; // 0x03 -// "Vent" Mode -const uint8_t kAmcorVentMask = 0b11000000; // 0xC0 +const uint8_t kAmcorMax = 0b11; +const uint8_t kAmcorMaxOffset = 0; +const uint8_t kAmcorMaxSize = 2; +// "Vent" Mode +const uint8_t kAmcorVentOn = 0b11; +const uint8_t kAmcorVentOffset = 6; +const uint8_t kAmcorVentSize = 2; // state[7] // Checksum byte. const uint8_t kAmcorChecksumByte = kAmcorStateLength - 1; diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Argo.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Argo.cpp old mode 100755 new mode 100644 similarity index 76% rename from lib/IRremoteESP8266-2.6.5/src/ir_Argo.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Argo.cpp index 522ede7e6..2721d3dc5 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Argo.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Argo.cpp @@ -7,10 +7,12 @@ Copyright 2019 crankyoldgit #include "ir_Argo.h" #include +#include #ifndef UNIT_TEST #include #endif // UNIT_TEST #include "IRremoteESP8266.h" +#include "IRtext.h" #include "IRutils.h" // Constants @@ -27,6 +29,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_ARGO // Send an Argo A/C message. @@ -55,8 +59,7 @@ void IRArgoAC::begin(void) { _irsend.begin(); } #if SEND_ARGO void IRArgoAC::send(const uint16_t repeat) { - this->checksum(); // Create valid checksum before sending - _irsend.sendArgo(argo, kArgoStateLength, repeat); + _irsend.sendArgo(getRaw(), kArgoStateLength, repeat); } #endif // SEND_ARGO @@ -105,73 +108,54 @@ uint8_t* IRArgoAC::getRaw(void) { } void IRArgoAC::setRaw(const uint8_t state[]) { - for (uint8_t i = 0; i < kArgoStateLength; i++) argo[i] = state[i]; + memcpy(argo, state, kArgoStateLength); } -void IRArgoAC::on(void) { - // Bit 5 of byte 9 is on/off - // in MSB first - argo[9]|= kArgoPowerBit; // Set ON/OFF bit to 1 -} +void IRArgoAC::on(void) { setPower(true); } -void IRArgoAC::off(void) { - // in MSB first - // bit 5 of byte 9 to off - argo[9] &= ~kArgoPowerBit; // Set on/off bit to 0 -} +void IRArgoAC::off(void) { setPower(false); } void IRArgoAC::setPower(const bool on) { - if (on) - this->on(); - else - this->off(); + setBit(&argo[9], kArgoPowerBitOffset, on); } -bool IRArgoAC::getPower(void) { return argo[9] & kArgoPowerBit; } +bool IRArgoAC::getPower(void) { return GETBIT8(argo[9], kArgoPowerBitOffset); } void IRArgoAC::setMax(const bool on) { - if (on) - argo[9] |= kArgoMaxBit; - else - argo[9] &= ~kArgoMaxBit; + setBit(&argo[9], kArgoMaxBitOffset, on); } -bool IRArgoAC::getMax(void) { return argo[9] & kArgoMaxBit; } +bool IRArgoAC::getMax(void) { return GETBIT8(argo[9], kArgoMaxBitOffset); } // Set the temp in deg C // Sending 0 equals +4 void IRArgoAC::setTemp(const uint8_t degrees) { uint8_t temp = std::max(kArgoMinTemp, degrees); - temp = std::min(kArgoMaxTemp, temp); - - // offset 4 degrees. "If I want 12 degrees, I need to send 8" - temp -= kArgoTempOffset; + // delta 4 degrees. "If I want 12 degrees, I need to send 8" + temp = std::min(kArgoMaxTemp, temp) - kArgoTempDelta; // Settemp = Bit 6,7 of byte 2, and bit 0-2 of byte 3 // mask out bits // argo[13] & 0x00000100; // mask out ON/OFF Bit - argo[2] &= ~kArgoTempLowMask; - argo[3] &= ~kArgoTempHighMask; - - // append to bit 6,7 - argo[2] += temp << 6; - // remove lowest to bits and append in 0-2 - argo[3] += ((temp >> 2) & kArgoTempHighMask); + setBits(&argo[2], kArgoTempLowOffset, kArgoTempLowSize, temp); + setBits(&argo[3], kArgoTempHighOffset, kArgoTempHighSize, + temp >> kArgoTempLowSize); } uint8_t IRArgoAC::getTemp(void) { - return (((argo[3] & kArgoTempHighMask) << 2 ) | (argo[2] >> 6)) + - kArgoTempOffset; + return ((GETBITS8(argo[3], kArgoTempHighOffset, + kArgoTempHighSize) << kArgoTempLowSize) | + GETBITS8(argo[2], kArgoTempLowOffset, kArgoTempLowSize)) + + kArgoTempDelta; } // Set the speed of the fan void IRArgoAC::setFan(const uint8_t fan) { - // Mask out bits - argo[3] &= ~kArgoFanMask; - // Set fan mode at bit positions - argo[3] |= (std::min(fan, kArgoFan3) << 3); + setBits(&argo[3], kArgoFanOffset, kArgoFanSize, std::min(fan, kArgoFan3)); } -uint8_t IRArgoAC::getFan(void) { return (argo[3] & kArgoFanMask) >> 3; } +uint8_t IRArgoAC::getFan(void) { + return GETBITS8(argo[3], kArgoFanOffset, kArgoFanSize); +} void IRArgoAC::setFlap(const uint8_t flap) { flap_mode = flap; @@ -181,7 +165,7 @@ void IRArgoAC::setFlap(const uint8_t flap) { uint8_t IRArgoAC::getFlap(void) { return flap_mode; } uint8_t IRArgoAC::getMode(void) { - return (argo[2] & kArgoModeMask) >> 3; + return GETBITS8(argo[2], kArgoModeOffset, kArgoModeSize); } void IRArgoAC::setMode(const uint8_t mode) { @@ -192,10 +176,7 @@ void IRArgoAC::setMode(const uint8_t mode) { case kArgoOff: case kArgoHeat: case kArgoHeatAuto: - // Mask out bits - argo[2] &= ~kArgoModeMask; - // Set the mode at bit positions - argo[2] |= ((mode << 3) & kArgoModeMask); + setBits(&argo[2], kArgoModeOffset, kArgoModeSize, mode); return; default: this->setMode(kArgoAuto); @@ -203,24 +184,16 @@ void IRArgoAC::setMode(const uint8_t mode) { } void IRArgoAC::setNight(const bool on) { - if (on) - // Set bit at night position: bit 2 - argo[9] |= kArgoNightBit; - else - argo[9] &= ~kArgoNightBit; + setBit(&argo[9], kArgoNightBitOffset, on); } -bool IRArgoAC::getNight(void) { return argo[9] & kArgoNightBit; } +bool IRArgoAC::getNight(void) { return GETBIT8(argo[9], kArgoNightBitOffset); } void IRArgoAC::setiFeel(const bool on) { - if (on) - // Set bit at iFeel position: bit 7 - argo[9] |= kArgoIFeelBit; - else - argo[9] &= ~kArgoIFeelBit; + setBit(&argo[9], kArgoIFeelBitOffset, on); } -bool IRArgoAC::getiFeel(void) { return argo[9] & kArgoIFeelBit; } +bool IRArgoAC::getiFeel(void) { return GETBIT8(argo[9], kArgoIFeelBitOffset); } void IRArgoAC::setTime(void) { // TODO(kaschmo): use function call from checksum to set time first @@ -228,19 +201,17 @@ void IRArgoAC::setTime(void) { void IRArgoAC::setRoomTemp(const uint8_t degrees) { uint8_t temp = std::min(degrees, kArgoMaxRoomTemp); - temp = std::max(temp, kArgoTempOffset); - temp -= kArgoTempOffset;; - // Mask out bits - argo[3] &= ~kArgoRoomTempLowMask; - argo[4] &= ~kArgoRoomTempHighMask; - - argo[3] += temp << 5; // Append to bit 5,6,7 - argo[4] += temp >> 3; // Remove lowest 3 bits and append in 0,1 + temp = std::max(temp, kArgoTempDelta) - kArgoTempDelta; + setBits(&argo[3], kArgoRoomTempLowOffset, kArgoRoomTempLowSize, temp); + setBits(&argo[4], kArgoRoomTempHighOffset, kArgoRoomTempHighSize, + temp >> kArgoRoomTempLowSize); } uint8_t IRArgoAC::getRoomTemp(void) { - return ((argo[4] & kArgoRoomTempHighMask) << 3 | (argo[3] >> 5)) + - kArgoTempOffset; + return ((GETBITS8(argo[4], kArgoRoomTempHighOffset, + kArgoRoomTempHighSize) << kArgoRoomTempLowSize) | + GETBITS8(argo[3], kArgoRoomTempLowOffset, kArgoRoomTempLowSize)) + + kArgoTempDelta; } // Convert a standard A/C mode into its native mode. @@ -341,56 +312,60 @@ stdAc::state_t IRArgoAC::toCommon(void) { } // Convert the internal state into a human readable string. -String IRArgoAC::toString() { +String IRArgoAC::toString(void) { String result = ""; result.reserve(100); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); - result += addIntToString(getMode(), F("Mode")); + result += addBoolToString(getPower(), kPowerStr, false); + result += addIntToString(getMode(), kModeStr); + result += kSpaceLBraceStr; switch (getMode()) { case kArgoAuto: - result += F(" (AUTO)"); + result += kAutoStr; break; case kArgoCool: - result += F(" (COOL)"); + result += kCoolStr; break; case kArgoHeat: - result += F(" (HEAT)"); + result += kHeatStr; break; case kArgoDry: - result += F(" (DRY)"); + result += kDryStr; break; case kArgoHeatAuto: - result += F(" (HEATAUTO)"); + result += kHeatStr + ' ' + kAutoStr; break; case kArgoOff: - result += F(" (OFF)"); + result += kOffStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } - result += addIntToString(getFan(), F("Fan")); + result += ')'; + result += addIntToString(getFan(), kFanStr); + result += kSpaceLBraceStr; switch (getFan()) { case kArgoFanAuto: - result += F(" (AUTO)"); + result += kAutoStr; break; case kArgoFan3: - result += F(" (MAX)"); + result += kMaxStr; break; case kArgoFan1: - result += F(" (MIN)"); + result += kMinStr; break; case kArgoFan2: - result += F(" (MED)"); + result += kMedStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } + result += ')'; result += addTempToString(getTemp()); - result += F(", Room "); + result += kCommaSpaceStr + kRoomStr + ' '; result += addTempToString(getRoomTemp(), true, false); - result += addBoolToString(getMax(), F("Max")); - result += addBoolToString(getiFeel(), F("iFeel")); - result += addBoolToString(getNight(), F("Night")); + result += addBoolToString(getMax(), kMaxStr); + result += addBoolToString(getiFeel(), kIFeelStr); + result += addBoolToString(getNight(), kNightStr); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Argo.h b/lib/IRremoteESP8266-2.7.0/src/ir_Argo.h old mode 100755 new mode 100644 similarity index 70% rename from lib/IRremoteESP8266-2.6.5/src/ir_Argo.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Argo.h index 49c8c42e5..3c1281ea3 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Argo.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Argo.h @@ -41,48 +41,64 @@ // byte[2] const uint8_t kArgoHeatBit = 0b00100000; -const uint8_t kArgoModeMask = 0b00111000; -const uint8_t kArgoTempLowMask = 0b11000000; -const uint8_t kArgoCool = 0b000; // 0b000 (LSB) 0 -const uint8_t kArgoDry = 0b001; // 0b100 (LSB) 1 -const uint8_t kArgoAuto = 0b010; // 0b010 (LSB) 2 -const uint8_t kArgoOff = 0b011; // 0b110 (LSB) 3 -const uint8_t kArgoHeat = 0b100; // 0b001 (LSB) 4 -const uint8_t kArgoHeatAuto = 0b101; // 0b101 (LSB) 5 +// kArgoTempLowMask = 0b11000000; +const uint8_t kArgoTempLowOffset = 5; +const uint8_t kArgoTempLowSize = 2; + +// Mode 0b00111000 +const uint8_t kArgoModeOffset = 3; +const uint8_t kArgoModeSize = 3; +const uint8_t kArgoCool = 0b000; +const uint8_t kArgoDry = 0b001; +const uint8_t kArgoAuto = 0b010; +const uint8_t kArgoOff = 0b011; +const uint8_t kArgoHeat = 0b100; +const uint8_t kArgoHeatAuto = 0b101; // ?no idea what mode that is -const uint8_t kArgoHeatBlink = 0b110; // 0b011 (LSB) 6 +const uint8_t kArgoHeatBlink = 0b110; // byte[3] -const uint8_t kArgoTempHighMask = 0b00000111; -const uint8_t kArgoFanMask = 0b00011000; -const uint8_t kArgoRoomTempLowMask = 0b11100000; -const uint8_t kArgoFanAuto = 0; // 0b00 -const uint8_t kArgoFan3 = 3; // 0b11 -const uint8_t kArgoFan2 = 2; // 0b01 -const uint8_t kArgoFan1 = 1; // 0b10 +// kArgoTempHighMask = 0b00000111; +const uint8_t kArgoTempHighOffset = 0; +const uint8_t kArgoTempHighSize = 3; +// Fan 0b00011000 +const uint8_t kArgoFanOffset = 3; +const uint8_t kArgoFanSize = 2; +const uint8_t kArgoFanAuto = 0; // 0b00 +const uint8_t kArgoFan1 = 1; // 0b01 +const uint8_t kArgoFan2 = 2; // 0b10 +const uint8_t kArgoFan3 = 3; // 0b11 +// kArgoRoomTempLowMask = 0b11100000; +const uint8_t kArgoRoomTempLowOffset = 5; +const uint8_t kArgoRoomTempLowSize = 3; // byte[4] -const uint8_t kArgoRoomTempHighMask = 0b00000011; -const uint8_t kArgoTempOffset = 4; -const uint8_t kArgoMaxRoomTemp = ((1 << 5) - 1) + kArgoTempOffset; // 35C +// kArgoRoomTempHighMask = 0b00000011; +const uint8_t kArgoRoomTempHighOffset = 0; +const uint8_t kArgoRoomTempHighSize = 2; + +const uint8_t kArgoTempDelta = 4; +const uint8_t kArgoMaxRoomTemp = + ((1 << (kArgoRoomTempHighSize + kArgoRoomTempLowSize)) - 1) + + kArgoTempDelta; // 35C // byte[9] -const uint8_t kArgoPowerBit = 0b00100000; -const uint8_t kArgoMaxBit = 0b00001000; -const uint8_t kArgoNightBit = 0b00000100; -const uint8_t kArgoIFeelBit = 0b10000000; +const uint8_t kArgoNightBitOffset = 2; +const uint8_t kArgoMaxBitOffset = 3; +const uint8_t kArgoPowerBitOffset = 5; +const uint8_t kArgoIFeelBitOffset = 7; -const uint8_t kArgoMinTemp = 10; // Celsius offset +4 +const uint8_t kArgoMinTemp = 10; // Celsius delta +4 const uint8_t kArgoMaxTemp = 32; // Celsius -const uint8_t kArgoFlapAuto = 0; // 0b000 -const uint8_t kArgoFlap1 = 1; // 0b100 -const uint8_t kArgoFlap2 = 2; // 0b010 -const uint8_t kArgoFlap3 = 3; // 0b110 -const uint8_t kArgoFlap4 = 4; // 0b001 -const uint8_t kArgoFlap5 = 5; // 0b101 -const uint8_t kArgoFlap6 = 6; // 0b011 -const uint8_t kArgoFlapFull = 7; // 0b111 +const uint8_t kArgoFlapAuto = 0; +const uint8_t kArgoFlap1 = 1; +const uint8_t kArgoFlap2 = 2; +const uint8_t kArgoFlap3 = 3; +const uint8_t kArgoFlap4 = 4; +const uint8_t kArgoFlap5 = 5; +const uint8_t kArgoFlap6 = 6; +const uint8_t kArgoFlapFull = 7; // Legacy defines. (Deperecated) #define ARGO_COOL_ON kArgoCoolOn diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Carrier.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Carrier.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Carrier.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Carrier.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Coolix.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Coolix.cpp old mode 100755 new mode 100644 similarity index 73% rename from lib/IRremoteESP8266-2.6.5/src/ir_Coolix.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Coolix.cpp index 616b417ce..2c840fe47 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Coolix.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Coolix.cpp @@ -8,6 +8,7 @@ #endif #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // Coolix A/C / heatpump added by (send) bakrus & (decode) crankyoldgit @@ -18,6 +19,7 @@ // Brand: Midea, Model: RG52D/BGE Remote // Brand: Midea, Model: MS12FU-10HRDN1-QRD0GW(B) A/C // Brand: Midea, Model: MSABAU-07HRFN1-QRD0GW A/C (circa 2016) +// Brand: Tokio, Model: AATOEMF17-12CHR1SW split-type RG51|50/BGE Remote // Ref: // https://github.com/crankyoldgit/IRremoteESP8266/issues/484 @@ -44,6 +46,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_COOLIX // Send a Coolix message @@ -100,21 +104,43 @@ IRCoolixAC::IRCoolixAC(const uint16_t pin, const bool inverted, const bool use_modulation) : _irsend(pin, inverted, use_modulation) { stateReset(); } -void IRCoolixAC::stateReset() { setRaw(kCoolixDefaultState); } +void IRCoolixAC::stateReset() { + setRaw(kCoolixDefaultState); + clearSensorTemp(); + powerFlag = false; + turboFlag = false; + ledFlag = false; + cleanFlag = false; + sleepFlag = false; + swingFlag = false; + swingHFlag = false; + swingVFlag = false; +} void IRCoolixAC::begin() { _irsend.begin(); } #if SEND_COOLIX void IRCoolixAC::send(const uint16_t repeat) { _irsend.sendCOOLIX(remote_state, kCoolixBits, repeat); + // make sure to remove special state from remote_state + // after command has being transmitted. + recoverSavedState(); } #endif // SEND_COOLIX uint32_t IRCoolixAC::getRaw() { return remote_state; } void IRCoolixAC::setRaw(const uint32_t new_code) { - remote_state = new_code; - saved_state = new_code; + if (!handleSpecialState(new_code)) { + // it isn`t special so might afect Temp|mode|Fan + if (new_code == kCoolixCmdFan) { + setMode(kCoolixFan); + } else { + // must be a command changing Temp|Mode|Fan + // it is safe to just copy to remote var + remote_state = new_code; + } + } } // Return true if the current state is a special state. @@ -125,13 +151,41 @@ bool IRCoolixAC::isSpecialState(void) { case kCoolixOff: case kCoolixSwing: case kCoolixSleep: - case kCoolixTurbo: - return true; - default: - return false; + case kCoolixTurbo: return true; + default: return false; } } +// Special state means commands that are not +// affecting Temperature/Mode/Fan +bool IRCoolixAC::handleSpecialState(const uint32_t data) { + switch (data) { + case kCoolixClean: + cleanFlag = !cleanFlag; + break; + case kCoolixLed: + ledFlag = !ledFlag; + break; + case kCoolixOff: + powerFlag = false; + break; + case kCoolixSwing: + swingFlag = !swingFlag; + break; + case kCoolixSleep: + sleepFlag = !sleepFlag; + break; + case kCoolixTurbo: + turboFlag = !turboFlag; + break; + default: + return false; + } + return true; +} + +// must be called before every special state +// to make sure the remote_state is safe void IRCoolixAC::updateSavedState(void) { if (!isSpecialState()) saved_state = remote_state; } @@ -144,18 +198,12 @@ void IRCoolixAC::recoverSavedState(void) { if (isSpecialState()) stateReset(); } -uint32_t IRCoolixAC::getNormalState(void) { - return isSpecialState() ? saved_state : remote_state; -} - void IRCoolixAC::setTempRaw(const uint8_t code) { - recoverSavedState(); - remote_state &= ~kCoolixTempMask; // Clear the old temp. - remote_state |= (code << 4); + setBits(&remote_state, kCoolixTempOffset, kCoolixTempSize, code); } uint8_t IRCoolixAC::getTempRaw() { - return (getNormalState() & kCoolixTempMask) >> 4; + return GETBITS32(remote_state, kCoolixTempOffset, kCoolixTempSize); } void IRCoolixAC::setTemp(const uint8_t desired) { @@ -166,17 +214,14 @@ void IRCoolixAC::setTemp(const uint8_t desired) { } uint8_t IRCoolixAC::getTemp() { - uint8_t code = getTempRaw(); - uint8_t i; - for (i = 0; i < kCoolixTempRange; i++) + const uint8_t code = getTempRaw(); + for (uint8_t i = 0; i < kCoolixTempRange; i++) if (kCoolixTempMap[i] == code) return kCoolixTempMin + i; - return kCoolixUnknown; // Not a temp we expected. + return kCoolixTempMax; // Not a temp we expected. } void IRCoolixAC::setSensorTempRaw(const uint8_t code) { - recoverSavedState(); - remote_state &= ~kCoolixSensorTempMask; // Clear previous sensor temp. - remote_state |= ((code & 0xF) << 8); + setBits(&remote_state, kCoolixSensorTempOffset, kCoolixSensorTempSize, code); } void IRCoolixAC::setSensorTemp(const uint8_t desired) { @@ -188,87 +233,89 @@ void IRCoolixAC::setSensorTemp(const uint8_t desired) { } uint8_t IRCoolixAC::getSensorTemp() { - return ((getNormalState() & kCoolixSensorTempMask) >> 8) + - kCoolixSensorTempMin; + return GETBITS32(remote_state, kCoolixSensorTempOffset, + kCoolixSensorTempSize) + kCoolixSensorTempMin; } bool IRCoolixAC::getPower() { // There is only an off state. Everything else is "on". - return remote_state != kCoolixOff; + return powerFlag; } -void IRCoolixAC::setPower(const bool power) { - if (power) { - // There really is no distinct "on" setting, just ensure it a normal state. - recoverSavedState(); +void IRCoolixAC::setPower(const bool on) { + if (powerFlag) { + if (!on) { + updateSavedState(); + remote_state = kCoolixOff; + } } else { - updateSavedState(); - remote_state = kCoolixOff; + if (on) { + // at this point remote_state must be ready + // to be transmitted + recoverSavedState(); + } } + powerFlag = on; } -void IRCoolixAC::on(void) { - this->setPower(true); -} +void IRCoolixAC::on(void) { this->setPower(true); } -void IRCoolixAC::off(void) { - this->setPower(false); -} +void IRCoolixAC::off(void) { this->setPower(false); } -bool IRCoolixAC::getSwing() { return remote_state == kCoolixSwing; } +bool IRCoolixAC::getSwing() { return swingFlag; } void IRCoolixAC::setSwing() { // Assumes that repeated sending "swing" toggles the action on the device. updateSavedState(); remote_state = kCoolixSwing; + swingFlag = !swingFlag; } -bool IRCoolixAC::getSleep() { return remote_state == kCoolixSleep; } +bool IRCoolixAC::getSleep() { return sleepFlag; } void IRCoolixAC::setSleep() { updateSavedState(); remote_state = kCoolixSleep; + sleepFlag = !sleepFlag; } -bool IRCoolixAC::getTurbo() { return remote_state == kCoolixTurbo; } +bool IRCoolixAC::getTurbo() { return turboFlag; } void IRCoolixAC::setTurbo() { // Assumes that repeated sending "turbo" toggles the action on the device. updateSavedState(); remote_state = kCoolixTurbo; + turboFlag = !turboFlag; } -bool IRCoolixAC::getLed() { return remote_state == kCoolixLed; } +bool IRCoolixAC::getLed() { return ledFlag; } void IRCoolixAC::setLed() { // Assumes that repeated sending "Led" toggles the action on the device. updateSavedState(); remote_state = kCoolixLed; + ledFlag = !ledFlag; } -bool IRCoolixAC::getClean() { return remote_state == kCoolixClean; } +bool IRCoolixAC::getClean() { return cleanFlag; } void IRCoolixAC::setClean() { updateSavedState(); remote_state = kCoolixClean; + cleanFlag = !cleanFlag; } bool IRCoolixAC::getZoneFollow() { - return getNormalState() & kCoolixZoneFollowMask; + return zoneFollowFlag; } // Internal use only. -void IRCoolixAC::setZoneFollow(bool state) { - recoverSavedState(); - if (state) { - remote_state |= kCoolixZoneFollowMask; - } else { - remote_state &= ~kCoolixZoneFollowMask; - } +void IRCoolixAC::setZoneFollow(bool on) { + zoneFollowFlag = on; + setBit(&remote_state, kCoolixZoneFollowMaskOffset, on); } void IRCoolixAC::clearSensorTemp() { - recoverSavedState(); setZoneFollow(false); setSensorTempRaw(kCoolixSensorTempIgnoreCode); } @@ -278,43 +325,40 @@ void IRCoolixAC::setMode(const uint8_t mode) { switch (actualmode) { case kCoolixAuto: case kCoolixDry: - if (this->getFan() == kCoolixFanAuto) - // No kCoolixFanAuto in Dry/Auto mode. - this->setFan(kCoolixFanAuto0, false); + setFan(kCoolixFanAuto0, false); break; case kCoolixCool: case kCoolixHeat: case kCoolixFan: - if (this->getFan() == kCoolixFanAuto0) - // kCoolixFanAuto0 only in Dry/Auto mode. - this->setFan(kCoolixFanAuto, false); + setFan(kCoolixFanAuto, false); break; default: // Anything else, go with Auto mode. - this->setMode(kCoolixAuto); + setMode(kCoolixAuto); + setFan(kCoolixFanAuto0, false); return; } - // Fan mode is a special case of Dry. - if (mode == kCoolixFan) actualmode = kCoolixDry; - recoverSavedState(); - remote_state = (remote_state & ~kCoolixModeMask) | (actualmode << 2); - // Force the temp into a known-good state. setTemp(getTemp()); - if (mode == kCoolixFan) setTempRaw(kCoolixFanTempCode); + // Fan mode is a special case of Dry. + if (mode == kCoolixFan) { + actualmode = kCoolixDry; + setTempRaw(kCoolixFanTempCode); + } + setBits(&remote_state, kCoolixModeOffset, kCoolixModeSize, actualmode); } uint8_t IRCoolixAC::getMode() { - uint8_t mode = (getNormalState() & kCoolixModeMask) >> 2; + uint8_t mode = GETBITS32(remote_state, kCoolixModeOffset, + kCoolixModeSize); if (mode == kCoolixDry) if (getTempRaw() == kCoolixFanTempCode) return kCoolixFan; return mode; } uint8_t IRCoolixAC::getFan() { - return (getNormalState() & kCoolixFanMask) >> 13; + return GETBITS32(remote_state, kCoolixFanOffset, kCoolixFanSize); } void IRCoolixAC::setFan(const uint8_t speed, const bool modecheck) { - recoverSavedState(); uint8_t newspeed = speed; switch (speed) { case kCoolixFanAuto: // Dry & Auto mode can't have this speed. @@ -323,6 +367,7 @@ void IRCoolixAC::setFan(const uint8_t speed, const bool modecheck) { case kCoolixAuto: case kCoolixDry: newspeed = kCoolixFanAuto0; + break; } } break; @@ -330,10 +375,8 @@ void IRCoolixAC::setFan(const uint8_t speed, const bool modecheck) { if (modecheck) { switch (this->getMode()) { case kCoolixAuto: - case kCoolixDry: - break; - default: - newspeed = kCoolixFanAuto; + case kCoolixDry: break; + default: newspeed = kCoolixFanAuto; } } break; @@ -345,24 +388,19 @@ void IRCoolixAC::setFan(const uint8_t speed, const bool modecheck) { break; default: // Unknown speed requested. newspeed = kCoolixFanAuto; + break; } - remote_state &= ~kCoolixFanMask; - remote_state |= ((newspeed << 13) & kCoolixFanMask); + setBits(&remote_state, kCoolixFanOffset, kCoolixFanSize, newspeed); } // Convert a standard A/C mode into its native mode. uint8_t IRCoolixAC::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kCoolixCool; - case stdAc::opmode_t::kHeat: - return kCoolixHeat; - case stdAc::opmode_t::kDry: - return kCoolixDry; - case stdAc::opmode_t::kFan: - return kCoolixFan; - default: - return kCoolixAuto; + case stdAc::opmode_t::kCool: return kCoolixCool; + case stdAc::opmode_t::kHeat: return kCoolixHeat; + case stdAc::opmode_t::kDry: return kCoolixDry; + case stdAc::opmode_t::kFan: return kCoolixFan; + default: return kCoolixAuto; } } @@ -370,15 +408,11 @@ uint8_t IRCoolixAC::convertMode(const stdAc::opmode_t mode) { uint8_t IRCoolixAC::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kCoolixFanMin; - case stdAc::fanspeed_t::kMedium: - return kCoolixFanMed; + case stdAc::fanspeed_t::kLow: return kCoolixFanMin; + case stdAc::fanspeed_t::kMedium: return kCoolixFanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kCoolixFanMax; - default: - return kCoolixFanAuto; + case stdAc::fanspeed_t::kMax: return kCoolixFanMax; + default: return kCoolixFanAuto; } } @@ -459,69 +493,69 @@ stdAc::state_t IRCoolixAC::toCommon(const stdAc::state_t *prev) { } // Convert the internal state into a human readable string. -String IRCoolixAC::toString() { +String IRCoolixAC::toString(void) { String result = ""; result.reserve(100); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); if (!getPower()) return result; // If it's off, there is no other info. // Special modes. if (getSwing()) { - result += F(", Swing: Toggle"); + result += kCommaSpaceStr + kSwingStr + kColonSpaceStr + kToggleStr; return result; } if (getSleep()) { - result += F(", Sleep: Toggle"); + result += kCommaSpaceStr + kSleepStr + kColonSpaceStr + kToggleStr; return result; } if (getTurbo()) { - result += F(", Turbo: Toggle"); + result += kCommaSpaceStr + kTurboStr + kColonSpaceStr + kToggleStr; return result; } if (getLed()) { - result += F(", Led: Toggle"); + result += kCommaSpaceStr + kLightStr + kColonSpaceStr + kToggleStr; return result; } if (getClean()) { - result += F(", Clean: Toggle"); + result += kCommaSpaceStr + kCleanStr + kColonSpaceStr + kToggleStr; return result; } - result += addModeToString(getMode(), kCoolixAuto, - kCoolixCool, kCoolixHeat, - kCoolixDry, kCoolixFan); - result += addIntToString(getFan(), F("Fan")); + result += addModeToString(getMode(), kCoolixAuto, kCoolixCool, kCoolixHeat, + kCoolixDry, kCoolixFan); + result += addIntToString(getFan(), kFanStr); + result += kSpaceLBraceStr; switch (getFan()) { case kCoolixFanAuto: - result += F(" (AUTO)"); + result += kAutoStr; break; case kCoolixFanAuto0: - result += F(" (AUTO0)"); + result += kAutoStr + '0'; break; case kCoolixFanMax: - result += F(" (MAX)"); + result += kMaxStr; break; case kCoolixFanMin: - result += F(" (MIN)"); + result += kMinStr; break; case kCoolixFanMed: - result += F(" (MED)"); + result += kMedStr; break; case kCoolixFanZoneFollow: - result += F(" (ZONEFOLLOW)"); + result += kZoneFollowStr; break; case kCoolixFanFixed: - result += F(" (FIXED)"); + result += kFixedStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } + result += ')'; // Fan mode doesn't have a temperature. if (getMode() != kCoolixFan) result += addTempToString(getTemp()); - result += addBoolToString(getZoneFollow(), F("Zone Follow")); - result += F(", Sensor Temp: "); - if (getSensorTemp() > kCoolixSensorTempMax) - result += F("Ignored"); - else - result += uint64ToString(getSensorTemp()) + F("C"); + result += addBoolToString(getZoneFollow(), kZoneFollowStr); + result += addLabeledString( + (getSensorTemp() > kCoolixSensorTempMax) + ? kOffStr : uint64ToString(getSensorTemp()) + F("C"), + kSensorStr + ' ' + kTempStr); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Coolix.h b/lib/IRremoteESP8266-2.7.0/src/ir_Coolix.h old mode 100755 new mode 100644 similarity index 68% rename from lib/IRremoteESP8266-2.6.5/src/ir_Coolix.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Coolix.h index 0c2e44676..c2fb2034d --- a/lib/IRremoteESP8266-2.6.5/src/ir_Coolix.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Coolix.h @@ -22,6 +22,7 @@ // Brand: Midea, Model: RG52D/BGE Remote // Brand: Midea, Model: MS12FU-10HRDN1-QRD0GW(B) A/C // Brand: Midea, Model: MSABAU-07HRFN1-QRD0GW A/C (circa 2016) +// Brand: Tokio, Model: AATOEMF17-12CHR1SW split-type RG51|50/BGE Remote // Ref: // https://github.com/crankyoldgit/IRremoteESP8266/issues/484 // Kudos: @@ -34,9 +35,15 @@ const uint8_t kCoolixDry = 0b001; const uint8_t kCoolixAuto = 0b010; const uint8_t kCoolixHeat = 0b011; const uint8_t kCoolixFan = 0b100; // Synthetic. -const uint32_t kCoolixModeMask = 0b000000000000000000001100; // 0xC -const uint32_t kCoolixZoneFollowMask = 0b000010000000000000000000; // 0x80000 +// const uint32_t kCoolixModeMask = 0b000000000000000000001100; // 0xC +const uint8_t kCoolixModeOffset = 2; +const uint8_t kCoolixModeSize = 2; +// const uint32_t kCoolixZoneFollowMask = 0b000010000000000000000000 0x80000 +const uint8_t kCoolixZoneFollowMaskOffset = 19; // Fan Control +// const uint32_t kCoolixFanMask = 0b000000001110000000000000; // 0x00E000 +const uint8_t kCoolixFanOffset = 13; +const uint8_t kCoolixFanSize = 3; const uint8_t kCoolixFanMin = 0b100; const uint8_t kCoolixFanMed = 0b010; const uint8_t kCoolixFanMax = 0b001; @@ -44,13 +51,14 @@ const uint8_t kCoolixFanAuto = 0b101; const uint8_t kCoolixFanAuto0 = 0b000; const uint8_t kCoolixFanZoneFollow = 0b110; const uint8_t kCoolixFanFixed = 0b111; -const uint32_t kCoolixFanMask = 0b000000001110000000000000; // 0x00E000 // Temperature const uint8_t kCoolixTempMin = 17; // Celsius const uint8_t kCoolixTempMax = 30; // Celsius const uint8_t kCoolixTempRange = kCoolixTempMax - kCoolixTempMin + 1; const uint8_t kCoolixFanTempCode = 0b1110; // Part of Fan Mode. -const uint32_t kCoolixTempMask = 0b11110000; +// const uint32_t kCoolixTempMask = 0b11110000; +const uint8_t kCoolixTempOffset = 4; +const uint8_t kCoolixTempSize = 4; const uint8_t kCoolixTempMap[kCoolixTempRange] = { 0b0000, // 17C 0b0001, // 18c @@ -70,18 +78,23 @@ const uint8_t kCoolixTempMap[kCoolixTempRange] = { const uint8_t kCoolixSensorTempMin = 16; // Celsius const uint8_t kCoolixSensorTempMax = 30; // Celsius const uint8_t kCoolixSensorTempIgnoreCode = 0b1111; -const uint32_t kCoolixSensorTempMask = 0b000000000000111100000000; // 0xF00 +// kCoolixSensorTempMask = 0b000000000000111100000000; // 0xF00 +const uint8_t kCoolixSensorTempOffset = 8; +const uint8_t kCoolixSensorTempSize = 4; // Fixed states/messages. const uint8_t kCoolixPrefix = 0b1011; // 0xB const uint8_t kCoolixUnknown = 0xFF; -const uint32_t kCoolixOff = 0b101100100111101111100000; // 0xB27BE0 -const uint32_t kCoolixSwing = 0b101100100110101111100000; // 0xB26BE0 -const uint32_t kCoolixSleep = 0b101100101110000000000011; // 0xB2E003 -const uint32_t kCoolixTurbo = 0b101101011111010110100010; // 0xB5F5A2 -const uint32_t kCoolixLed = 0b101101011111010110100101; // 0xB5F5A5 -const uint32_t kCoolixClean = 0b101101011111010110101010; // 0xB5F5AA +const uint32_t kCoolixOff = 0b101100100111101111100000; // 0xB27BE0 +const uint32_t kCoolixSwing = 0b101100100110101111100000; // 0xB26BE0 +const uint32_t kCoolixSwingH = 0b101100101111010110100010; // 0xB5F5A2 +const uint32_t kCoolixSwingV = 0b101100100000111111100000; // 0xB20FE0 +const uint32_t kCoolixSleep = 0b101100101110000000000011; // 0xB2E003 +const uint32_t kCoolixTurbo = 0b101101011111010110100010; // 0xB5F5A2 +const uint32_t kCoolixLed = 0b101101011111010110100101; // 0xB5F5A5 +const uint32_t kCoolixClean = 0b101101011111010110101010; // 0xB5F5AA +const uint32_t kCoolixCmdFan = 0b101100101011111111100100; // 0xB2BFE4 // On, 25C, Mode: Auto, Fan: Auto, Zone Follow: Off, Sensor Temp: Ignore. -const uint32_t kCoolixDefaultState = 0b101100101011111111001000; // 0xB2BFC8 +const uint32_t kCoolixDefaultState = 0b101100100001111111001000; // 0xB21FC8 // Classes class IRCoolixAC { @@ -134,13 +147,25 @@ class IRCoolixAC { #else IRsendTest _irsend; #endif + // internal state + bool powerFlag; + bool turboFlag; + bool ledFlag; + bool cleanFlag; + bool sleepFlag; + bool zoneFollowFlag; + bool swingFlag; + bool swingHFlag; + bool swingVFlag; + uint32_t remote_state; // The state of the IR remote in IR code form. uint32_t saved_state; // Copy of the state if we required a special mode. void setTempRaw(const uint8_t code); uint8_t getTempRaw(); void setSensorTempRaw(const uint8_t code); - void setZoneFollow(const bool state); + void setZoneFollow(const bool on); bool isSpecialState(void); + bool handleSpecialState(const uint32_t data); void updateSavedState(void); void recoverSavedState(void); uint32_t getNormalState(void); diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Daikin.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Daikin.cpp old mode 100755 new mode 100644 similarity index 70% rename from lib/IRremoteESP8266-2.6.5/src/ir_Daikin.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Daikin.cpp index 317526f5e..b90dd682b --- a/lib/IRremoteESP8266-2.6.5/src/ir_Daikin.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Daikin.cpp @@ -11,6 +11,7 @@ Copyright 2019 pasna (IRDaikin160 class / Daikin176 class) #include "ir_Daikin.h" #include +#include #ifndef ARDUINO #include #endif @@ -20,6 +21,7 @@ Copyright 2019 pasna (IRDaikin160 class / Daikin176 class) #ifdef UNIT_TEST #include "IRsend_test.h" #endif +#include "IRtext.h" #include "IRutils.h" // Constants @@ -29,6 +31,7 @@ Copyright 2019 pasna (IRDaikin160 class / Daikin176 class) // https://github.com/crankyoldgit/IRremoteESP8266/issues/582 using irutils::addBoolToString; +using irutils::addDayToString; using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; @@ -36,6 +39,8 @@ using irutils::addTempToString; using irutils::addFanToString; using irutils::bcdToUint8; using irutils::minsToString; +using irutils::setBit; +using irutils::setBits; using irutils::sumNibbles; using irutils::uint8ToBcd; @@ -101,8 +106,7 @@ void IRDaikinESP::begin(void) { _irsend.begin(); } #if SEND_DAIKIN void IRDaikinESP::send(const uint16_t repeat) { - this->checksum(); - _irsend.sendDaikin(remote, kDaikinStateLength, repeat); + _irsend.sendDaikin(getRaw(), kDaikinStateLength, repeat); } #endif // SEND_DAIKIN @@ -184,19 +188,16 @@ void IRDaikinESP::setRaw(const uint8_t new_code[], const uint16_t length) { remote[i + offset] = new_code[i]; } -void IRDaikinESP::on(void) { remote[kDaikinBytePower] |= kDaikinBitPower; } +void IRDaikinESP::on(void) { setPower(true); } -void IRDaikinESP::off(void) { remote[kDaikinBytePower] &= ~kDaikinBitPower; } +void IRDaikinESP::off(void) { setPower(false); } void IRDaikinESP::setPower(const bool on) { - if (on) - this->on(); - else - this->off(); + setBit(&remote[kDaikinBytePower], kDaikinBitPowerOffset, on); } bool IRDaikinESP::getPower(void) { - return remote[kDaikinBytePower] & kDaikinBitPower; + return GETBIT8(remote[kDaikinBytePower], kDaikinBitPowerOffset); } // Set the temp in deg C @@ -218,17 +219,19 @@ void IRDaikinESP::setFan(const uint8_t fan) { fanset = kDaikinFanAuto; else fanset = 2 + fan; - remote[kDaikinByteFan] &= 0x0F; - remote[kDaikinByteFan] |= (fanset << 4); + setBits(&remote[kDaikinByteFan], kDaikinFanOffset, kDaikinFanSize, fanset); } uint8_t IRDaikinESP::getFan(void) { - uint8_t fan = remote[kDaikinByteFan] >> 4; + uint8_t fan = GETBITS8(remote[kDaikinByteFan], kDaikinFanOffset, + kDaikinFanSize); if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2; return fan; } -uint8_t IRDaikinESP::getMode(void) { return remote[kDaikinBytePower] >> 4; } +uint8_t IRDaikinESP::getMode(void) { + return GETBITS8(remote[kDaikinBytePower], kDaikinModeOffset, kDaikinModeSize); +} void IRDaikinESP::setMode(const uint8_t mode) { switch (mode) { @@ -237,8 +240,8 @@ void IRDaikinESP::setMode(const uint8_t mode) { case kDaikinHeat: case kDaikinFan: case kDaikinDry: - remote[kDaikinBytePower] &= 0b10001111; - remote[kDaikinBytePower] |= (mode << 4); + setBits(&remote[kDaikinBytePower], kDaikinModeOffset, kDaikinModeSize, + mode); break; default: this->setMode(kDaikinAuto); @@ -246,146 +249,126 @@ void IRDaikinESP::setMode(const uint8_t mode) { } void IRDaikinESP::setSwingVertical(const bool on) { - if (on) - remote[kDaikinByteFan] |= 0x0F; - else - remote[kDaikinByteFan] &= 0xF0; + setBits(&remote[kDaikinByteFan], kDaikinSwingOffset, kDaikinSwingSize, + on ? kDaikinSwingOn : kDaikinSwingOff); } bool IRDaikinESP::getSwingVertical(void) { - return remote[kDaikinByteFan] & 0x0F; + return GETBITS8(remote[kDaikinByteFan], kDaikinSwingOffset, kDaikinSwingSize); } void IRDaikinESP::setSwingHorizontal(const bool on) { - if (on) - remote[kDaikinByteSwingH] |= 0x0F; - else - remote[kDaikinByteSwingH] &= 0xF0; + setBits(&remote[kDaikinByteSwingH], kDaikinSwingOffset, kDaikinSwingSize, + on ? kDaikinSwingOn : kDaikinSwingOff); } bool IRDaikinESP::getSwingHorizontal(void) { - return remote[kDaikinByteSwingH] & 0x0F; + return GETBITS8(remote[kDaikinByteSwingH], kDaikinSwingOffset, + kDaikinSwingSize); } void IRDaikinESP::setQuiet(const bool on) { - if (on) { - remote[kDaikinByteSilent] |= kDaikinBitSilent; - // Powerful & Quiet mode being on are mutually exclusive. - this->setPowerful(false); - } else { - remote[kDaikinByteSilent] &= ~kDaikinBitSilent; - } + setBit(&remote[kDaikinByteSilent], kDaikinBitSilentOffset, on); + // Powerful & Quiet mode being on are mutually exclusive. + if (on) this->setPowerful(false); } bool IRDaikinESP::getQuiet(void) { - return remote[kDaikinByteSilent] & kDaikinBitSilent; + return GETBIT8(remote[kDaikinByteSilent], kDaikinBitSilentOffset); } void IRDaikinESP::setPowerful(const bool on) { + setBit(&remote[kDaikinBytePowerful], kDaikinBitPowerfulOffset, on); if (on) { - remote[kDaikinBytePowerful] |= kDaikinBitPowerful; // Powerful, Quiet, & Econo mode being on are mutually exclusive. this->setQuiet(false); this->setEcono(false); - } else { - remote[kDaikinBytePowerful] &= ~kDaikinBitPowerful; } } bool IRDaikinESP::getPowerful(void) { - return remote[kDaikinBytePowerful] & kDaikinBitPowerful; + return GETBIT8(remote[kDaikinBytePowerful], kDaikinBitPowerfulOffset); } void IRDaikinESP::setSensor(const bool on) { - if (on) - remote[kDaikinByteSensor] |= kDaikinBitSensor; - else - remote[kDaikinByteSensor] &= ~kDaikinBitSensor; + setBit(&remote[kDaikinByteSensor], kDaikinBitSensorOffset, on); } bool IRDaikinESP::getSensor(void) { - return remote[kDaikinByteSensor] & kDaikinBitSensor; + return GETBIT8(remote[kDaikinByteSensor], kDaikinBitSensorOffset); } void IRDaikinESP::setEcono(const bool on) { - if (on) { - remote[kDaikinByteEcono] |= kDaikinBitEcono; - // Powerful & Econo mode being on are mutually exclusive. - this->setPowerful(false); - } else { - remote[kDaikinByteEcono] &= ~kDaikinBitEcono; - } + setBit(&remote[kDaikinByteEcono], kDaikinBitEconoOffset, on); + // Powerful & Econo mode being on are mutually exclusive. + if (on) this->setPowerful(false); } bool IRDaikinESP::getEcono(void) { - return remote[kDaikinByteEcono] & kDaikinBitEcono; + return GETBIT8(remote[kDaikinByteEcono], kDaikinBitEconoOffset); } void IRDaikinESP::setMold(const bool on) { - if (on) - remote[kDaikinByteMold] |= kDaikinBitMold; - else - remote[kDaikinByteMold] &= ~kDaikinBitMold; + setBit(&remote[kDaikinByteMold], kDaikinBitMoldOffset, on); } bool IRDaikinESP::getMold(void) { - return remote[kDaikinByteMold] & kDaikinBitMold; + return GETBIT8(remote[kDaikinByteMold], kDaikinBitMoldOffset); } void IRDaikinESP::setComfort(const bool on) { - if (on) - remote[kDaikinByteComfort] |= kDaikinBitComfort; - else - remote[kDaikinByteComfort] &= ~kDaikinBitComfort; + setBit(&remote[kDaikinByteComfort], kDaikinBitComfortOffset, on); } bool IRDaikinESP::getComfort(void) { - return remote[kDaikinByteComfort] & kDaikinBitComfort; + return GETBIT8(remote[kDaikinByteComfort], kDaikinBitComfortOffset); } // starttime: Number of minutes after midnight. void IRDaikinESP::enableOnTimer(const uint16_t starttime) { - remote[kDaikinByteOnTimer] |= kDaikinBitOnTimer; + setBit(&remote[kDaikinByteOnTimer], kDaikinBitOnTimerOffset); remote[kDaikinByteOnTimerMinsLow] = starttime; // only keep 4 bits - remote[kDaikinByteOnTimerMinsHigh] &= 0xF0; - remote[kDaikinByteOnTimerMinsHigh] |= ((starttime >> 8) & 0x0F); + setBits(&remote[kDaikinByteOnTimerMinsHigh], kDaikinOnTimerMinsHighOffset, + kDaikinOnTimerMinsHighSize, starttime >> 8); } void IRDaikinESP::disableOnTimer(void) { this->enableOnTimer(kDaikinUnusedTime); - remote[kDaikinByteOnTimer] &= ~kDaikinBitOnTimer; + setBit(&remote[kDaikinByteOnTimer], kDaikinBitOnTimerOffset, false); } uint16_t IRDaikinESP::getOnTime(void) { - return ((remote[kDaikinByteOnTimerMinsHigh] & 0x0F) << 8) + + return (GETBITS8(remote[kDaikinByteOnTimerMinsHigh], + kDaikinOnTimerMinsHighOffset, + kDaikinOnTimerMinsHighSize) << 8) + remote[kDaikinByteOnTimerMinsLow]; } bool IRDaikinESP::getOnTimerEnabled(void) { - return remote[kDaikinByteOnTimer] & kDaikinBitOnTimer; + return GETBIT8(remote[kDaikinByteOnTimer], kDaikinBitOnTimerOffset); } // endtime: Number of minutes after midnight. void IRDaikinESP::enableOffTimer(const uint16_t endtime) { - remote[kDaikinByteOffTimer] |= kDaikinBitOffTimer; - remote[kDaikinByteOffTimerMinsHigh] = endtime >> 4; - remote[kDaikinByteOffTimerMinsLow] &= 0x0F; - remote[kDaikinByteOffTimerMinsLow] |= ((endtime & 0x0F) << 4); + setBit(&remote[kDaikinByteOffTimer], kDaikinBitOffTimerOffset); + remote[kDaikinByteOffTimerMinsHigh] = endtime >> kNibbleSize; + setBits(&remote[kDaikinByteOffTimerMinsLow], kHighNibble, kNibbleSize, + endtime); } void IRDaikinESP::disableOffTimer(void) { this->enableOffTimer(kDaikinUnusedTime); - remote[kDaikinByteOffTimer] &= ~kDaikinBitOffTimer; + setBit(&remote[kDaikinByteOffTimer], kDaikinBitOffTimerOffset, false); } uint16_t IRDaikinESP::getOffTime(void) { - return (remote[kDaikinByteOffTimerMinsHigh] << 4) + - ((remote[kDaikinByteOffTimerMinsLow] & 0xF0) >> 4); + return (remote[kDaikinByteOffTimerMinsHigh] << kNibbleSize) + + GETBITS8(remote[kDaikinByteOffTimerMinsLow], kHighNibble, kNibbleSize); } bool IRDaikinESP::getOffTimerEnabled(void) { - return remote[kDaikinByteOffTimer] & kDaikinBitOffTimer; + return GETBIT8(remote[kDaikinByteOffTimer], kDaikinBitOffTimerOffset); } void IRDaikinESP::setCurrentTime(const uint16_t mins_since_midnight) { @@ -393,70 +376,56 @@ void IRDaikinESP::setCurrentTime(const uint16_t mins_since_midnight) { if (mins > 24 * 60) mins = 0; // If > 23:59, set to 00:00 remote[kDaikinByteClockMinsLow] = mins; // only keep 3 bits - remote[kDaikinByteClockMinsHigh] &= 0xF8; - remote[kDaikinByteClockMinsHigh] |= ((mins >> 8) & 0x07); + setBits(&remote[kDaikinByteClockMinsHigh], kDaikinClockMinsHighOffset, + kDaikinClockMinsHighSize, mins >> 8); } uint16_t IRDaikinESP::getCurrentTime(void) { - return ((remote[kDaikinByteClockMinsHigh] & 0x07) << 8) + + return (GETBITS8(remote[kDaikinByteClockMinsHigh], kDaikinClockMinsHighOffset, + kDaikinClockMinsHighSize) << 8) + remote[kDaikinByteClockMinsLow]; } void IRDaikinESP::setCurrentDay(const uint8_t day_of_week) { // 1 is SUN, 2 is MON, ..., 7 is SAT - uint8_t days = day_of_week; - if (days > 7) days = 0; // Enforce the limit - // Update bits 5-3 - remote[kDaikinByteClockMinsHigh] &= 0xc7; - remote[kDaikinByteClockMinsHigh] |= days << 3; + setBits(&remote[kDaikinByteClockMinsHigh], kDaikinDoWOffset, kDaikinDoWSize, + day_of_week); } uint8_t IRDaikinESP::getCurrentDay(void) { - return ((remote[kDaikinByteClockMinsHigh] & 0x38) >> 3); + return GETBITS8(remote[kDaikinByteClockMinsHigh], kDaikinDoWOffset, + kDaikinDoWSize); } void IRDaikinESP::setWeeklyTimerEnable(const bool on) { - if (on) - remote[kDaikinByteWeeklyTimer] &= ~kDaikinBitWeeklyTimer; // Clear the bit. - else - remote[kDaikinByteWeeklyTimer] |= kDaikinBitWeeklyTimer; // Set the bit. + // Bit is cleared for `on`. + setBit(&remote[kDaikinByteWeeklyTimer], kDaikinBitWeeklyTimerOffset, !on); } bool IRDaikinESP::getWeeklyTimerEnable(void) { - return !(remote[kDaikinByteWeeklyTimer] & kDaikinBitWeeklyTimer); + return !GETBIT8(remote[kDaikinByteWeeklyTimer], kDaikinBitWeeklyTimerOffset); } // Convert a standard A/C mode into its native mode. uint8_t IRDaikinESP::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kDaikinCool; - case stdAc::opmode_t::kHeat: - return kDaikinHeat; - case stdAc::opmode_t::kDry: - return kDaikinDry; - case stdAc::opmode_t::kFan: - return kDaikinFan; - default: - return kDaikinAuto; + case stdAc::opmode_t::kCool: return kDaikinCool; + case stdAc::opmode_t::kHeat: return kDaikinHeat; + case stdAc::opmode_t::kDry: return kDaikinDry; + case stdAc::opmode_t::kFan: return kDaikinFan; + default: return kDaikinAuto; } } // Convert a standard A/C Fan speed into its native fan speed. uint8_t IRDaikinESP::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { - case stdAc::fanspeed_t::kMin: - return kDaikinFanQuiet; - case stdAc::fanspeed_t::kLow: - return kDaikinFanMin; - case stdAc::fanspeed_t::kMedium: - return kDaikinFanMin + 1; - case stdAc::fanspeed_t::kHigh: - return kDaikinFanMax - 1; - case stdAc::fanspeed_t::kMax: - return kDaikinFanMax; - default: - return kDaikinFanAuto; + case stdAc::fanspeed_t::kMin: return kDaikinFanQuiet; + case stdAc::fanspeed_t::kLow: return kDaikinFanMin; + case stdAc::fanspeed_t::kMedium: return kDaikinFanMed; + case stdAc::fanspeed_t::kHigh: return kDaikinFanMax - 1; + case stdAc::fanspeed_t::kMax: return kDaikinFanMax; + default: return kDaikinFanAuto; } } @@ -476,6 +445,7 @@ stdAc::fanspeed_t IRDaikinESP::toCommonFanSpeed(const uint8_t speed) { switch (speed) { case kDaikinFanMax: return stdAc::fanspeed_t::kMax; case kDaikinFanMax - 1: return stdAc::fanspeed_t::kHigh; + case kDaikinFanMed: case kDaikinFanMin + 1: return stdAc::fanspeed_t::kMedium; case kDaikinFanMin: return stdAc::fanspeed_t::kLow; case kDaikinFanQuiet: return stdAc::fanspeed_t::kMin; @@ -514,47 +484,28 @@ stdAc::state_t IRDaikinESP::toCommon(void) { String IRDaikinESP::toString(void) { String result = ""; result.reserve(230); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kDaikinAuto, kDaikinCool, kDaikinHeat, kDaikinDry, kDaikinFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kDaikinFanMax, kDaikinFanMin, kDaikinFanAuto, kDaikinFanQuiet, kDaikinFanMed); - result += addBoolToString(getPowerful(), F("Powerful")); - result += addBoolToString(getQuiet(), F("Quiet")); - result += addBoolToString(getSensor(), F("Sensor")); - result += addBoolToString(getMold(), F("Mold")); - result += addBoolToString(getComfort(), F("Comfort")); - result += addBoolToString(getSwingHorizontal(), F("Swing (Horizontal)")); - result += addBoolToString(getSwingVertical(), F("Swing (Vertical)")); - result += addLabeledString(minsToString(this->getCurrentTime()), - F("Current Time")); - result += F(", Current Day: "); - switch (this->getCurrentDay()) { - case 1: - result +=F("SUN"); break; - case 2: - result +=F("MON"); break; - case 3: - result +=F("TUE"); break; - case 4: - result +=F("WED"); break; - case 5: - result +=F("THU"); break; - case 6: - result +=F("FRI"); break; - case 7: - result +=F("SAT"); break; - default: - result +=F("(UNKNOWN)"); break; - } + result += addBoolToString(getPowerful(), kPowerfulStr); + result += addBoolToString(getQuiet(), kQuietStr); + result += addBoolToString(getSensor(), kSensorStr); + result += addBoolToString(getMold(), kMouldStr); + result += addBoolToString(getComfort(), kComfortStr); + result += addBoolToString(getSwingHorizontal(), kSwingHStr); + result += addBoolToString(getSwingVertical(), kSwingVStr); + result += addLabeledString(minsToString(this->getCurrentTime()), kClockStr); + result += addDayToString(getCurrentDay(), -1); result += addLabeledString(getOnTimerEnabled() - ? minsToString(this->getOnTime()) : F("Off"), - F("On Time")); + ? minsToString(this->getOnTime()) : kOffStr, + kOnTimerStr); result += addLabeledString(getOffTimerEnabled() - ? minsToString(this->getOffTime()) : F("Off"), - F("Off Time")); - result += addBoolToString(getWeeklyTimerEnable(), F("Weekly Timer")); + ? minsToString(this->getOffTime()) : kOffStr, + kOffTimerStr); + result += addBoolToString(getWeeklyTimerEnable(), kWeeklyTimerStr); return result; } @@ -567,7 +518,7 @@ String IRDaikinESP::toString(void) { // Returns: // boolean: True if it can decode it, false if it can't. // -// Status: BETA / Should be working. +// Status: STABLE / Reported as working. // // Ref: // https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote @@ -683,12 +634,11 @@ IRDaikin2::IRDaikin2(const uint16_t pin, const bool inverted, const bool use_modulation) : _irsend(pin, inverted, use_modulation) { stateReset(); } -void IRDaikin2::begin() { _irsend.begin(); } +void IRDaikin2::begin(void) { _irsend.begin(); } #if SEND_DAIKIN2 void IRDaikin2::send(const uint16_t repeat) { - checksum(); - _irsend.sendDaikin2(remote_state, kDaikin2StateLength, repeat); + _irsend.sendDaikin2(getRaw(), kDaikin2StateLength, repeat); } #endif // SEND_DAIKIN2 @@ -713,14 +663,14 @@ bool IRDaikin2::validChecksum(uint8_t state[], const uint16_t length) { } // Calculate and set the checksum values for the internal state. -void IRDaikin2::checksum() { +void IRDaikin2::checksum(void) { remote_state[kDaikin2Section1Length - 1] = sumBytes( remote_state, kDaikin2Section1Length - 1); remote_state[kDaikin2StateLength -1 ] = sumBytes( remote_state + kDaikin2Section1Length, kDaikin2Section2Length - 1); } -void IRDaikin2::stateReset() { +void IRDaikin2::stateReset(void) { for (uint8_t i = 0; i < kDaikin2StateLength; i++) remote_state[i] = 0x0; remote_state[0] = 0x11; @@ -754,53 +704,43 @@ void IRDaikin2::stateReset() { checksum(); } -uint8_t *IRDaikin2::getRaw() { +uint8_t *IRDaikin2::getRaw(void) { checksum(); // Ensure correct settings before sending. return remote_state; } void IRDaikin2::setRaw(const uint8_t new_code[]) { - for (uint8_t i = 0; i < kDaikin2StateLength; i++) - remote_state[i] = new_code[i]; + memcpy(remote_state, new_code, kDaikin2StateLength); } -void IRDaikin2::on() { - remote_state[25] |= kDaikinBitPower; - remote_state[6] &= ~kDaikin2BitPower; +void IRDaikin2::on(void) { setPower(true); } + +void IRDaikin2::off(void) { setPower(false); } + +void IRDaikin2::setPower(const bool on) { + setBit(&remote_state[25], kDaikinBitPowerOffset, on); + setBit(&remote_state[6], kDaikin2BitPowerOffset, !on); } -void IRDaikin2::off() { - remote_state[25] &= ~kDaikinBitPower; - remote_state[6] |= kDaikin2BitPower; +bool IRDaikin2::getPower(void) { + return GETBIT8(remote_state[25], kDaikinBitPowerOffset) && + !GETBIT8(remote_state[6], kDaikin2BitPowerOffset); } -void IRDaikin2::setPower(const bool state) { - if (state) - on(); - else - off(); +uint8_t IRDaikin2::getMode(void) { + return GETBITS8(remote_state[25], kHighNibble, kModeBitsSize); } -bool IRDaikin2::getPower() { - return (remote_state[25] & kDaikinBitPower) && - !(remote_state[6] & kDaikin2BitPower); -} - -uint8_t IRDaikin2::getMode() { return remote_state[25] >> 4; } - void IRDaikin2::setMode(const uint8_t desired_mode) { uint8_t mode = desired_mode; switch (mode) { case kDaikinCool: case kDaikinHeat: case kDaikinFan: - case kDaikinDry: - break; - default: - mode = kDaikinAuto; + case kDaikinDry: break; + default: mode = kDaikinAuto; } - remote_state[25] &= 0b10001111; - remote_state[25] |= (mode << 4); + setBits(&remote_state[25], kHighNibble, kModeBitsSize, mode); // Redo the temp setting as Cool mode has a different min temp. if (mode == kDaikinCool) this->setTemp(this->getTemp()); } @@ -811,8 +751,7 @@ void IRDaikin2::setTemp(const uint8_t desired) { uint8_t temp = std::max( (this->getMode() == kDaikinCool) ? kDaikin2MinCoolTemp : kDaikinMinTemp, desired); - temp = std::min(kDaikinMaxTemp, temp); - remote_state[26] = temp * 2; + remote_state[26] = std::min(kDaikinMaxTemp, temp) << 1; } // Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet @@ -825,17 +764,20 @@ void IRDaikin2::setFan(const uint8_t fan) { fanset = kDaikinFanAuto; else fanset = 2 + fan; - remote_state[28] &= 0x0F; - remote_state[28] |= (fanset << 4); + setBits(&remote_state[kDaikin2FanByte], kHighNibble, kNibbleSize, fanset); } -uint8_t IRDaikin2::getFan() { - uint8_t fan = remote_state[28] >> 4; - if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2; - return fan; +uint8_t IRDaikin2::getFan(void) { + const uint8_t fan = GETBITS8(remote_state[kDaikin2FanByte], kHighNibble, + kNibbleSize); + switch (fan) { + case kDaikinFanAuto: + case kDaikinFanQuiet: return fan; + default: return fan - 2; + } } -uint8_t IRDaikin2::getTemp() { return remote_state[26] / 2; } +uint8_t IRDaikin2::getTemp(void) { return remote_state[26] >> 1; } void IRDaikin2::setSwingVertical(const uint8_t position) { switch (position) { @@ -845,247 +787,16 @@ void IRDaikin2::setSwingVertical(const uint8_t position) { case 4: case 5: case kDaikin2SwingVLow: + case kDaikin2SwingVSwing: case kDaikin2SwingVBreeze: case kDaikin2SwingVCirculate: case kDaikin2SwingVAuto: - remote_state[18] &= 0xF0; - remote_state[18] |= (position & 0x0F); + setBits(&remote_state[18], kLowNibble, kNibbleSize, position); } } -uint8_t IRDaikin2::getSwingVertical() { return remote_state[18] & 0x0F; } - -void IRDaikin2::setSwingHorizontal(const uint8_t position) { - remote_state[17] = position; -} - -uint8_t IRDaikin2::getSwingHorizontal() { return remote_state[17]; } - -void IRDaikin2::setCurrentTime(const uint16_t numMins) { - uint16_t mins = numMins; - if (numMins > 24 * 60) mins = 0; // If > 23:59, set to 00:00 - remote_state[5] = (uint8_t)(mins & 0xFF); - // only keep 4 bits - remote_state[6] &= 0xF0; - remote_state[6] |= (uint8_t)((mins >> 8) & 0x0F); -} - -uint16_t IRDaikin2::getCurrentTime() { - return ((remote_state[6] & 0x0F) << 8) + remote_state[5]; -} - -// starttime: Number of minutes after midnight. -// Note: Timer location is shared with sleep timer. -void IRDaikin2::enableOnTimer(const uint16_t starttime) { - clearSleepTimerFlag(); - remote_state[25] |= kDaikinBitOnTimer; // Set the On Timer flag. - remote_state[30] = (uint8_t)(starttime & 0xFF); - // only keep 4 bits - remote_state[31] &= 0xF0; - remote_state[31] |= (uint8_t)((starttime >> 8) & 0x0F); -} - -void IRDaikin2::clearOnTimerFlag() { - remote_state[25] &= ~kDaikinBitOnTimer; -} - -void IRDaikin2::disableOnTimer() { - enableOnTimer(kDaikinUnusedTime); - clearOnTimerFlag(); - clearSleepTimerFlag(); -} - -uint16_t IRDaikin2::getOnTime() { - return ((remote_state[31] & 0x0F) << 8) + remote_state[30]; -} - -bool IRDaikin2::getOnTimerEnabled() { - return remote_state[25] & kDaikinBitOnTimer; -} - -// endtime: Number of minutes after midnight. -void IRDaikin2::enableOffTimer(const uint16_t endtime) { - remote_state[25] |= kDaikinBitOffTimer; // Set the Off Timer flag. - remote_state[32] = (uint8_t)((endtime >> 4) & 0xFF); - remote_state[31] &= 0x0F; - remote_state[31] |= (uint8_t)((endtime & 0xF) << 4); -} - -void IRDaikin2::disableOffTimer() { - enableOffTimer(kDaikinUnusedTime); - remote_state[25] &= ~kDaikinBitOffTimer; // Clear the Off Timer flag. -} - -uint16_t IRDaikin2::getOffTime() { - return (remote_state[32] << 4) + (remote_state[31] >> 4); -} - -bool IRDaikin2::getOffTimerEnabled() { - return remote_state[25] & kDaikinBitOffTimer; -} - -uint8_t IRDaikin2::getBeep() { - return remote_state[7] >> 6; -} - -void IRDaikin2::setBeep(const uint8_t beep) { - remote_state[7] &= ~kDaikin2BeepMask; - remote_state[7] |= ((beep << 6) & kDaikin2BeepMask); -} - -uint8_t IRDaikin2::getLight() { - return (remote_state[7] & kDaikin2LightMask) >> 4; -} - -void IRDaikin2::setLight(const uint8_t light) { - remote_state[7] &= ~kDaikin2LightMask; - remote_state[7] |= ((light << 4) & kDaikin2LightMask); -} - -void IRDaikin2::setMold(const bool on) { - if (on) - remote_state[8] |= kDaikin2BitMold; - else - remote_state[8] &= ~kDaikin2BitMold; -} - -bool IRDaikin2::getMold() { - return remote_state[8] & kDaikin2BitMold; -} - -// Auto clean setting. -void IRDaikin2::setClean(const bool on) { - if (on) - remote_state[8] |= kDaikin2BitClean; - else - remote_state[8] &= ~kDaikin2BitClean; -} - -bool IRDaikin2::getClean() { - return remote_state[8] & kDaikin2BitClean; -} - -// Fresh Air settings. -void IRDaikin2::setFreshAir(const bool on) { - if (on) - remote_state[8] |= kDaikin2BitFreshAir; - else - remote_state[8] &= ~kDaikin2BitFreshAir; -} - -bool IRDaikin2::getFreshAir() { - return remote_state[8] & kDaikin2BitFreshAir; -} - -void IRDaikin2::setFreshAirHigh(const bool on) { - if (on) - remote_state[8] |= kDaikin2BitFreshAirHigh; - else - remote_state[8] &= ~kDaikin2BitFreshAirHigh; -} - -bool IRDaikin2::getFreshAirHigh() { - return remote_state[8] & kDaikin2BitFreshAirHigh; -} - -void IRDaikin2::setEyeAuto(bool on) { - if (on) - remote_state[13] |= kDaikin2BitEyeAuto; - else - remote_state[13] &= ~kDaikin2BitEyeAuto; -} - -bool IRDaikin2::getEyeAuto() { - return remote_state[13] & kDaikin2BitEyeAuto; -} - -void IRDaikin2::setEye(bool on) { - if (on) - remote_state[36] |= kDaikin2BitEye; - else - remote_state[36] &= ~kDaikin2BitEye; -} - -bool IRDaikin2::getEye() { - return remote_state[36] & kDaikin2BitEye; -} - -void IRDaikin2::setEcono(bool on) { - if (on) - remote_state[36] |= kDaikinBitEcono; - else - remote_state[36] &= ~kDaikinBitEcono; -} - -bool IRDaikin2::getEcono() { - return remote_state[36] & kDaikinBitEcono; -} - -// sleeptime: Number of minutes. -// Note: Timer location is shared with On Timer. -void IRDaikin2::enableSleepTimer(const uint16_t sleeptime) { - enableOnTimer(sleeptime); - clearOnTimerFlag(); - remote_state[36] |= kDaikin2BitSleepTimer; // Set the Sleep Timer flag. -} - -void IRDaikin2::clearSleepTimerFlag() { - remote_state[36] &= ~kDaikin2BitSleepTimer; -} - -void IRDaikin2::disableSleepTimer() { - disableOnTimer(); -} - -uint16_t IRDaikin2::getSleepTime() { - return getOnTime(); -} - -bool IRDaikin2::getSleepTimerEnabled() { - return remote_state[36] & kDaikin2BitSleepTimer; -} - -void IRDaikin2::setQuiet(const bool on) { - if (on) { - remote_state[33] |= kDaikinBitSilent; - // Powerful & Quiet mode being on are mutually exclusive. - setPowerful(false); - } else { - remote_state[33] &= ~kDaikinBitSilent; - } -} - -bool IRDaikin2::getQuiet() { return remote_state[33] & kDaikinBitSilent; } - -void IRDaikin2::setPowerful(const bool on) { - if (on) { - remote_state[33] |= kDaikinBitPowerful; - // Powerful & Quiet mode being on are mutually exclusive. - setQuiet(false); - } else { - remote_state[33] &= ~kDaikinBitPowerful; - } -} - -bool IRDaikin2::getPowerful() { return remote_state[33] & kDaikinBitPowerful; } - -void IRDaikin2::setPurify(const bool on) { - if (on) - remote_state[36] |= kDaikin2BitPurify; - else - remote_state[36] &= ~kDaikin2BitPurify; -} - -bool IRDaikin2::getPurify() { return remote_state[36] & kDaikin2BitPurify; } - -// Convert a standard A/C mode into its native mode. -uint8_t IRDaikin2::convertMode(const stdAc::opmode_t mode) { - return IRDaikinESP::convertMode(mode); -} - -// Convert a standard A/C Fan speed into its native fan speed. -uint8_t IRDaikin2::convertFan(const stdAc::fanspeed_t speed) { - return IRDaikinESP::convertFan(speed); +uint8_t IRDaikin2::getSwingVertical(void) { + return GETBITS8(remote_state[18], kLowNibble, kNibbleSize); } // Convert a standard A/C vertical swing into its native version. @@ -1097,8 +808,8 @@ uint8_t IRDaikin2::convertSwingV(const stdAc::swingv_t position) { case stdAc::swingv_t::kLow: case stdAc::swingv_t::kLowest: return (uint8_t)position + kDaikin2SwingVHigh; - default: - return kDaikin2SwingVAuto; + case stdAc::swingv_t::kAuto: return kDaikin2SwingVSwing; + default: return kDaikin2SwingVAuto; } } @@ -1111,15 +822,241 @@ stdAc::swingv_t IRDaikin2::toCommonSwingV(const uint8_t setting) { case kDaikin2SwingVHigh + 3: return stdAc::swingv_t::kMiddle; case kDaikin2SwingVLow - 1: return stdAc::swingv_t::kLow; case kDaikin2SwingVLow: return stdAc::swingv_t::kLowest; + case kDaikin2SwingVAuto: return stdAc::swingv_t::kOff; default: return stdAc::swingv_t::kAuto; } } +void IRDaikin2::setSwingHorizontal(const uint8_t position) { + remote_state[17] = position; +} + +uint8_t IRDaikin2::getSwingHorizontal(void) { return remote_state[17]; } + +void IRDaikin2::setCurrentTime(const uint16_t numMins) { + uint16_t mins = numMins; + if (numMins > 24 * 60) mins = 0; // If > 23:59, set to 00:00 + remote_state[5] = mins; + setBits(&remote_state[6], kLowNibble, kNibbleSize, mins >> 8); +} + +uint16_t IRDaikin2::getCurrentTime(void) { + return (GETBITS8(remote_state[6], kLowNibble, kNibbleSize) << 8) | + remote_state[5]; +} + +// starttime: Number of minutes after midnight. +// Note: Timer location is shared with sleep timer. +void IRDaikin2::enableOnTimer(const uint16_t starttime) { + clearSleepTimerFlag(); + setBit(&remote_state[25], kDaikinBitOnTimerOffset); // Set the On Timer flag. + remote_state[30] = starttime; + setBits(&remote_state[31], kLowNibble, kNibbleSize, starttime >> 8); +} + +void IRDaikin2::clearOnTimerFlag(void) { + setBit(&remote_state[25], kDaikinBitOnTimerOffset, false); +} + +void IRDaikin2::disableOnTimer(void) { + enableOnTimer(kDaikinUnusedTime); + clearOnTimerFlag(); + clearSleepTimerFlag(); +} + +uint16_t IRDaikin2::getOnTime(void) { + return (GETBITS8(remote_state[31], kLowNibble, kNibbleSize) << 8) + + remote_state[30]; +} + +bool IRDaikin2::getOnTimerEnabled(void) { + return GETBIT8(remote_state[25], kDaikinBitOnTimerOffset); +} + +// endtime: Number of minutes after midnight. +void IRDaikin2::enableOffTimer(const uint16_t endtime) { + // Set the Off Timer flag. + setBit(&remote_state[25], kDaikinBitOffTimerOffset); + remote_state[32] = endtime >> 4; + setBits(&remote_state[31], kHighNibble, kNibbleSize, endtime); +} + +void IRDaikin2::disableOffTimer(void) { + enableOffTimer(kDaikinUnusedTime); + // Clear the Off Timer flag. + setBit(&remote_state[25], kDaikinBitOffTimerOffset, false); +} + +uint16_t IRDaikin2::getOffTime(void) { + return (remote_state[32] << 4) + GETBITS8(remote_state[31], kHighNibble, + kNibbleSize); +} + +bool IRDaikin2::getOffTimerEnabled(void) { + return GETBIT8(remote_state[25], kDaikinBitOffTimerOffset); +} + +uint8_t IRDaikin2::getBeep(void) { + return GETBITS8(remote_state[7], kDaikin2BeepOffset, kDaikin2BeepSize); +} + +void IRDaikin2::setBeep(const uint8_t beep) { + setBits(&remote_state[7], kDaikin2BeepOffset, kDaikin2BeepSize, beep); +} + +uint8_t IRDaikin2::getLight(void) { + return GETBITS8(remote_state[7], kDaikin2LightOffset, kDaikin2LightSize); +} + +void IRDaikin2::setLight(const uint8_t light) { + setBits(&remote_state[7], kDaikin2LightOffset, kDaikin2LightSize, light); +} + +void IRDaikin2::setMold(const bool on) { + setBit(&remote_state[8], kDaikin2BitMoldOffset, on); +} + +bool IRDaikin2::getMold(void) { + return GETBIT8(remote_state[8], kDaikin2BitMoldOffset); +} + +// Auto clean setting. +void IRDaikin2::setClean(const bool on) { + setBit(&remote_state[8], kDaikin2BitCleanOffset, on); +} + +bool IRDaikin2::getClean(void) { + return GETBIT8(remote_state[8], kDaikin2BitCleanOffset); +} + +// Fresh Air settings. +void IRDaikin2::setFreshAir(const bool on) { + setBit(&remote_state[8], kDaikin2BitFreshAirOffset, on); +} + +bool IRDaikin2::getFreshAir(void) { + return GETBIT8(remote_state[8], kDaikin2BitFreshAirOffset); +} + +void IRDaikin2::setFreshAirHigh(const bool on) { + setBit(&remote_state[8], kDaikin2BitFreshAirHighOffset, on); +} + +bool IRDaikin2::getFreshAirHigh(void) { + return GETBIT8(remote_state[8], kDaikin2BitFreshAirHighOffset); +} + +void IRDaikin2::setEyeAuto(bool on) { + setBit(&remote_state[13], kDaikin2BitEyeAutoOffset, on); +} + +bool IRDaikin2::getEyeAuto(void) { + return GETBIT8(remote_state[13], kDaikin2BitEyeAutoOffset); +} + +void IRDaikin2::setEye(bool on) { + setBit(&remote_state[36], kDaikin2BitEyeOffset, on); +} + +bool IRDaikin2::getEye(void) { + return GETBIT8(remote_state[36], kDaikin2BitEyeOffset); +} + +void IRDaikin2::setEcono(bool on) { + setBit(&remote_state[36], kDaikinBitEconoOffset, on); +} + +bool IRDaikin2::getEcono(void) { + return GETBIT8(remote_state[36], kDaikinBitEconoOffset); +} + +// sleeptime: Number of minutes. +// Note: Timer location is shared with On Timer. +void IRDaikin2::enableSleepTimer(const uint16_t sleeptime) { + enableOnTimer(sleeptime); + clearOnTimerFlag(); + // Set the Sleep Timer flag. + setBit(&remote_state[36], kDaikin2BitSleepTimerOffset); +} + +void IRDaikin2::clearSleepTimerFlag(void) { + setBit(&remote_state[36], kDaikin2BitSleepTimerOffset, false); +} + +void IRDaikin2::disableSleepTimer(void) { + disableOnTimer(); +} + +uint16_t IRDaikin2::getSleepTime(void) { + return getOnTime(); +} + +bool IRDaikin2::getSleepTimerEnabled(void) { + return GETBIT8(remote_state[36], kDaikin2BitSleepTimerOffset); +} + +void IRDaikin2::setQuiet(const bool on) { + setBit(&remote_state[33], kDaikinBitSilentOffset, on); + // Powerful & Quiet mode being on are mutually exclusive. + if (on) setPowerful(false); +} + +bool IRDaikin2::getQuiet(void) { + return GETBIT8(remote_state[33], kDaikinBitSilentOffset); +} + +void IRDaikin2::setPowerful(const bool on) { + setBit(&remote_state[33], kDaikinBitPowerfulOffset, on); + // Powerful & Quiet mode being on are mutually exclusive. + if (on) setQuiet(false); +} + +bool IRDaikin2::getPowerful(void) { + return GETBIT8(remote_state[33], kDaikinBitPowerfulOffset); +} + +void IRDaikin2::setPurify(const bool on) { + setBit(&remote_state[36], kDaikin2BitPurifyOffset, on); +} + +bool IRDaikin2::getPurify(void) { + return GETBIT8(remote_state[36], kDaikin2BitPurifyOffset); +} + +// Convert a standard A/C mode into its native mode. +uint8_t IRDaikin2::convertMode(const stdAc::opmode_t mode) { + return IRDaikinESP::convertMode(mode); +} + +// Convert a standard A/C Fan speed into its native fan speed. +uint8_t IRDaikin2::convertFan(const stdAc::fanspeed_t speed) { + return IRDaikinESP::convertFan(speed); +} + +// Convert a standard A/C horizontal swing into its native version. +uint8_t IRDaikin2::convertSwingH(const stdAc::swingh_t position) { + switch (position) { + case stdAc::swingh_t::kAuto: return kDaikin2SwingHSwing; + case stdAc::swingh_t::kLeftMax: return kDaikin2SwingHLeftMax; + case stdAc::swingh_t::kLeft: return kDaikin2SwingHLeft; + case stdAc::swingh_t::kMiddle: return kDaikin2SwingHMiddle; + case stdAc::swingh_t::kRight: return kDaikin2SwingHRight; + case stdAc::swingh_t::kRightMax: return kDaikin2SwingHRightMax; + case stdAc::swingh_t::kWide: return kDaikin2SwingHWide; + default: return kDaikin2SwingHAuto; + } +} + // Convert a native horizontal swing to it's common equivalent. stdAc::swingh_t IRDaikin2::toCommonSwingH(const uint8_t setting) { switch (setting) { - case kDaikin2SwingHSwing: - case kDaikin2SwingHAuto: return stdAc::swingh_t::kAuto; + case kDaikin2SwingHSwing: return stdAc::swingh_t::kAuto; + case kDaikin2SwingHLeftMax: return stdAc::swingh_t::kLeftMax; + case kDaikin2SwingHLeft: return stdAc::swingh_t::kLeft; + case kDaikin2SwingHMiddle: return stdAc::swingh_t::kMiddle; + case kDaikin2SwingHRight: return stdAc::swingh_t::kRight; + case kDaikin2SwingHRightMax: return stdAc::swingh_t::kRightMax; + case kDaikin2SwingHWide: return stdAc::swingh_t::kWide; default: return stdAc::swingh_t::kOff; } } @@ -1137,12 +1074,12 @@ stdAc::state_t IRDaikin2::toCommon(void) { result.swingv = this->toCommonSwingV(this->getSwingVertical()); result.swingh = this->toCommonSwingH(this->getSwingHorizontal()); result.quiet = this->getQuiet(); - result.light = this->getLight(); + result.light = this->getLight() != 3; // 3 is Off, everything else is On. result.turbo = this->getPowerful(); result.clean = this->getMold(); result.econo = this->getEcono(); result.filter = this->getPurify(); - result.beep = this->getBeep(); + result.beep = this->getBeep() != 3; // 3 is Off, everything else is On. result.sleep = this->getSleepTimerEnabled() ? this->getSleepTime() : -1; // Not supported. result.clock = -1; @@ -1150,97 +1087,109 @@ stdAc::state_t IRDaikin2::toCommon(void) { } // Convert the internal state into a human readable string. -String IRDaikin2::toString() { +String IRDaikin2::toString(void) { String result = ""; result.reserve(310); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kDaikinAuto, kDaikinCool, kDaikinHeat, kDaikinDry, kDaikinFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kDaikinFanMax, kDaikinFanMin, kDaikinFanAuto, kDaikinFanQuiet, kDaikinFanMed); - result += addIntToString(getSwingVertical(), F("Swing (V)")); + result += addIntToString(getSwingVertical(), kSwingVStr); + result += kSpaceLBraceStr; switch (getSwingVertical()) { case kDaikin2SwingVHigh: - result += F(" (Highest)"); + result += kHighestStr; break; - case 2: - case 3: - case 4: - case 5: + case 2: result += kHighStr; break; + case 3: result += kUpperStr + kMiddleStr; break; + case 4: result += kLowerStr + kMiddleStr; break; + case 5: result += kLowStr; break; break; case kDaikin2SwingVLow: - result += F(" (Lowest)"); + result += kLowestStr; break; case kDaikin2SwingVBreeze: - result += F(" (Breeze)"); + result += kBreezeStr; break; case kDaikin2SwingVCirculate: - result += F(" (Circulate)"); + result += kCirculateStr; break; case kDaikin2SwingVAuto: - result += F(" (Auto)"); + result += kAutoStr; + break; + case kDaikin2SwingVSwing: + result += kSwingStr; break; default: - result += F(" (Unknown)"); + result += kUnknownStr; } - result += addIntToString(getSwingHorizontal(), F("Swing (H)")); + result += ')'; + result += addIntToString(getSwingHorizontal(), kSwingHStr); + result += kSpaceLBraceStr; switch (getSwingHorizontal()) { case kDaikin2SwingHAuto: - result += F(" (Auto)"); + result += kAutoStr; break; case kDaikin2SwingHSwing: - result += F(" (Swing)"); + result += kSwingStr; break; + default: result += kUnknownStr; } - result += addLabeledString(minsToString(getCurrentTime()), F("Clock")); + result += ')'; + result += addLabeledString(minsToString(getCurrentTime()), kClockStr); result += addLabeledString( - getOnTimerEnabled() ? minsToString(getOnTime()) : F("Off"), F("On Time")); + getOnTimerEnabled() ? minsToString(getOnTime()) : kOffStr, kOnTimerStr); result += addLabeledString( - getOffTimerEnabled() ? minsToString(getOffTime()) : F("Off"), - F("Off Time")); + getOffTimerEnabled() ? minsToString(getOffTime()) : kOffStr, + kOffTimerStr); result += addLabeledString( - getSleepTimerEnabled() ? minsToString(getSleepTime()) : F("Off"), - F("Sleep Time")); - result += addIntToString(getBeep(), F("Beep")); + getSleepTimerEnabled() ? minsToString(getSleepTime()) : kOffStr, + kSleepStr + ' ' + kTimerStr); + result += addIntToString(getBeep(), kBeepStr); + result += kSpaceLBraceStr; switch (getBeep()) { case kDaikinBeepLoud: - result += F(" (Loud)"); + result += kLoudStr; break; case kDaikinBeepQuiet: - result += F(" (Quiet)"); + result += kQuietStr; break; case kDaikinBeepOff: - result += F(" (Off)"); + result += kOffStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } - result += addIntToString(getLight(), F("Light")); + result += ')'; + result += addIntToString(getLight(), kLightStr); + result += kSpaceLBraceStr; switch (getLight()) { case kDaikinLightBright: - result += F(" (Bright)"); + result += kHighStr; break; case kDaikinLightDim: - result += F(" (Dim)"); + result += kLowStr; break; case kDaikinLightOff: - result += F(" (Off)"); + result += kOffStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } - result += addBoolToString(getMold(), F("Mold")); - result += addBoolToString(getClean(), F("Clean")); + result += ')'; + result += addBoolToString(getMold(), kMouldStr); + result += addBoolToString(getClean(), kCleanStr); result += addLabeledString( - getFreshAir() ? (getFreshAirHigh() ? F("High") : F("On")) : F("Off"), - F("Fresh Air")); - result += addBoolToString(getEye(), F("Eye")); - result += addBoolToString(getEyeAuto(), F("Eye Auto")); - result += addBoolToString(getQuiet(), F("Quiet")); - result += addBoolToString(getPowerful(), F("Powerful")); - result += addBoolToString(getPurify(), F("Purify")); - result += addBoolToString(getEcono(), F("Econo")); + getFreshAir() ? (getFreshAirHigh() ? kHighStr : kOnStr) : kOffStr, + kFreshStr); + result += addBoolToString(getEye(), kEyeStr); + result += addBoolToString(getEyeAuto(), kEyeStr + ' ' + kAutoStr); + result += addBoolToString(getQuiet(), kQuietStr); + result += addBoolToString(getPowerful(), kPowerfulStr); + result += addBoolToString(getPurify(), kPurifyStr); + result += addBoolToString(getEcono(), kEconoStr); return result; } @@ -1365,12 +1314,11 @@ IRDaikin216::IRDaikin216(const uint16_t pin, const bool inverted, const bool use_modulation) : _irsend(pin, inverted, use_modulation) { stateReset(); } -void IRDaikin216::begin() { _irsend.begin(); } +void IRDaikin216::begin(void) { _irsend.begin(); } #if SEND_DAIKIN216 void IRDaikin216::send(const uint16_t repeat) { - checksum(); - _irsend.sendDaikin216(remote_state, kDaikin216StateLength, repeat); + _irsend.sendDaikin216(getRaw(), kDaikin216StateLength, repeat); } #endif // SEND_DAIKIN216 @@ -1395,14 +1343,14 @@ bool IRDaikin216::validChecksum(uint8_t state[], const uint16_t length) { } // Calculate and set the checksum values for the internal state. -void IRDaikin216::checksum() { +void IRDaikin216::checksum(void) { remote_state[kDaikin216Section1Length - 1] = sumBytes( remote_state, kDaikin216Section1Length - 1); remote_state[kDaikin216StateLength - 1] = sumBytes( remote_state + kDaikin216Section1Length, kDaikin216Section2Length - 1); } -void IRDaikin216::stateReset() { +void IRDaikin216::stateReset(void) { for (uint8_t i = 0; i < kDaikin216StateLength; i++) remote_state[i] = 0x00; remote_state[0] = 0x11; remote_state[1] = 0xDA; @@ -1416,38 +1364,29 @@ void IRDaikin216::stateReset() { // remote_state[26] is a checksum byte, it will be set by checksum(). } -uint8_t *IRDaikin216::getRaw() { +uint8_t *IRDaikin216::getRaw(void) { checksum(); // Ensure correct settings before sending. return remote_state; } void IRDaikin216::setRaw(const uint8_t new_code[]) { - for (uint8_t i = 0; i < kDaikin216StateLength; i++) - remote_state[i] = new_code[i]; + memcpy(remote_state, new_code, kDaikin216StateLength); } +void IRDaikin216::on(void) { setPower(true); } -void IRDaikin216::on() { - remote_state[kDaikin216BytePower] |= kDaikinBitPower; +void IRDaikin216::off(void) { setPower(false); } + +void IRDaikin216::setPower(const bool on) { + setBit(&remote_state[kDaikin216BytePower], kDaikinBitPowerOffset, on); } -void IRDaikin216::off() { - remote_state[kDaikin216BytePower] &= ~kDaikinBitPower; +bool IRDaikin216::getPower(void) { + return GETBIT8(remote_state[kDaikin216BytePower], kDaikinBitPowerOffset); } -void IRDaikin216::setPower(const bool state) { - if (state) - on(); - else - off(); -} - -bool IRDaikin216::getPower() { - return remote_state[kDaikin216BytePower] & kDaikinBitPower; -} - -uint8_t IRDaikin216::getMode() { - return (remote_state[kDaikin216ByteMode] & kDaikin216MaskMode) >> 4; +uint8_t IRDaikin216::getMode(void) { + return GETBITS8(remote_state[kDaikin216ByteMode], kHighNibble, kModeBitsSize); } void IRDaikin216::setMode(const uint8_t mode) { @@ -1457,8 +1396,8 @@ void IRDaikin216::setMode(const uint8_t mode) { case kDaikinHeat: case kDaikinFan: case kDaikinDry: - remote_state[kDaikin216ByteMode] &= ~kDaikin216MaskMode; - remote_state[kDaikin216ByteMode] |= (mode << 4); + setBits(&remote_state[kDaikin216ByteMode], kHighNibble, kModeBitsSize, + mode); break; default: this->setMode(kDaikinAuto); @@ -1474,12 +1413,13 @@ uint8_t IRDaikin216::convertMode(const stdAc::opmode_t mode) { void IRDaikin216::setTemp(const uint8_t temp) { uint8_t degrees = std::max(temp, kDaikinMinTemp); degrees = std::min(degrees, kDaikinMaxTemp); - remote_state[kDaikin216ByteTemp] &= ~kDaikin216MaskTemp; - remote_state[kDaikin216ByteTemp] |= (degrees << 1); + setBits(&remote_state[kDaikin216ByteTemp], kDaikin216TempOffset, + kDaikin216TempSize, degrees); } uint8_t IRDaikin216::getTemp(void) { - return (remote_state[kDaikin216ByteTemp] & kDaikin216MaskTemp) >> 1; + return GETBITS8(remote_state[kDaikin216ByteTemp], kDaikin216TempOffset, + kDaikin216TempSize); } // Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet @@ -1492,12 +1432,13 @@ void IRDaikin216::setFan(const uint8_t fan) { fanset = kDaikinFanAuto; else fanset = 2 + fan; - remote_state[kDaikin216ByteFan] &= ~kDaikin216MaskFan; - remote_state[kDaikin216ByteFan] |= (fanset << 4); + setBits(&remote_state[kDaikin216ByteFan], kHighNibble, kDaikinFanSize, + fanset); } -uint8_t IRDaikin216::getFan() { - uint8_t fan = remote_state[kDaikin216ByteFan] >> 4; +uint8_t IRDaikin216::getFan(void) { + uint8_t fan = GETBITS8(remote_state[kDaikin216ByteFan], kHighNibble, + kDaikinFanSize); if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2; return fan; } @@ -1508,25 +1449,23 @@ uint8_t IRDaikin216::convertFan(const stdAc::fanspeed_t speed) { } void IRDaikin216::setSwingVertical(const bool on) { - if (on) - remote_state[kDaikin216ByteSwingV] |= kDaikin216MaskSwingV; - else - remote_state[kDaikin216ByteSwingV] &= ~kDaikin216MaskSwingV; + setBits(&remote_state[kDaikin216ByteSwingV], kLowNibble, kDaikin216SwingSize, + on ? kDaikin216SwingOn : kDaikin216SwingOff); } bool IRDaikin216::getSwingVertical(void) { - return remote_state[kDaikin216ByteSwingV] & kDaikin216MaskSwingV; + return GETBITS8(remote_state[kDaikin216ByteSwingV], kLowNibble, + kDaikin216SwingSize); } void IRDaikin216::setSwingHorizontal(const bool on) { - if (on) - remote_state[kDaikin216ByteSwingH] |= kDaikin216MaskSwingH; - else - remote_state[kDaikin216ByteSwingH] &= ~kDaikin216MaskSwingH; + setBits(&remote_state[kDaikin216ByteSwingH], kLowNibble, kDaikin216SwingSize, + on ? kDaikin216SwingOn : kDaikin216SwingOff); } bool IRDaikin216::getSwingHorizontal(void) { - return remote_state[kDaikin216ByteSwingH] & kDaikin216MaskSwingH; + return GETBITS8(remote_state[kDaikin216ByteSwingH], kLowNibble, + kDaikin216SwingSize); } // This is a horrible hack till someone works out the quiet mode bit. @@ -1546,17 +1485,14 @@ bool IRDaikin216::getQuiet(void) { } void IRDaikin216::setPowerful(const bool on) { - if (on) { - remote_state[kDaikin216BytePowerful] |= kDaikinBitPowerful; - // Powerful & Quiet mode being on are mutually exclusive. - this->setQuiet(false); - } else { - remote_state[kDaikin216BytePowerful] &= ~kDaikinBitPowerful; - } + setBit(&remote_state[kDaikin216BytePowerful], kDaikinBitPowerfulOffset, on); + // Powerful & Quiet mode being on are mutually exclusive. + if (on) this->setQuiet(false); } -bool IRDaikin216::getPowerful() { - return remote_state[kDaikin216BytePowerful] & kDaikinBitPowerful; +bool IRDaikin216::getPowerful(void) { + return GETBIT8(remote_state[kDaikin216BytePowerful], + kDaikinBitPowerfulOffset); } // Convert the A/C state to it's common equivalent. @@ -1587,19 +1523,19 @@ stdAc::state_t IRDaikin216::toCommon(void) { } // Convert the internal state into a human readable string. -String IRDaikin216::toString() { +String IRDaikin216::toString(void) { String result = ""; result.reserve(120); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kDaikinAuto, kDaikinCool, kDaikinHeat, kDaikinDry, kDaikinFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kDaikinFanMax, kDaikinFanMin, kDaikinFanAuto, kDaikinFanQuiet, kDaikinFanMed); - result += addBoolToString(getSwingHorizontal(), F("Swing (Horizontal)")); - result += addBoolToString(getSwingVertical(), F("Swing (Vertical)")); - result += addBoolToString(getQuiet(), F("Quiet")); - result += addBoolToString(getPowerful(), F("Powerful")); + result += addBoolToString(getSwingHorizontal(), kSwingHStr); + result += addBoolToString(getSwingVertical(), kSwingVStr); + result += addBoolToString(getQuiet(), kQuietStr); + result += addBoolToString(getPowerful(), kPowerfulStr); return result; } @@ -1713,7 +1649,7 @@ IRDaikin160::IRDaikin160(const uint16_t pin, const bool inverted, const bool use_modulation) : _irsend(pin, inverted, use_modulation) { stateReset(); } -void IRDaikin160::begin() { _irsend.begin(); } +void IRDaikin160::begin(void) { _irsend.begin(); } // Verify the checksum is valid for a given state. // Args: @@ -1736,14 +1672,14 @@ bool IRDaikin160::validChecksum(uint8_t state[], const uint16_t length) { } // Calculate and set the checksum values for the internal state. -void IRDaikin160::checksum() { +void IRDaikin160::checksum(void) { remote_state[kDaikin160Section1Length - 1] = sumBytes( remote_state, kDaikin160Section1Length - 1); remote_state[kDaikin160StateLength - 1] = sumBytes( remote_state + kDaikin160Section1Length, kDaikin160Section2Length - 1); } -void IRDaikin160::stateReset() { +void IRDaikin160::stateReset(void) { for (uint8_t i = 0; i < kDaikin160StateLength; i++) remote_state[i] = 0x00; remote_state[0] = 0x11; remote_state[1] = 0xDA; @@ -1763,44 +1699,35 @@ void IRDaikin160::stateReset() { // remote_state[19] is a checksum byte, it will be set by checksum(). } -uint8_t *IRDaikin160::getRaw() { +uint8_t *IRDaikin160::getRaw(void) { checksum(); // Ensure correct settings before sending. return remote_state; } void IRDaikin160::setRaw(const uint8_t new_code[]) { - for (uint8_t i = 0; i < kDaikin160StateLength; i++) - remote_state[i] = new_code[i]; + memcpy(remote_state, new_code, kDaikin160StateLength); } #if SEND_DAIKIN160 void IRDaikin160::send(const uint16_t repeat) { - checksum(); - _irsend.sendDaikin160(remote_state, kDaikin160StateLength, repeat); + _irsend.sendDaikin160(getRaw(), kDaikin160StateLength, repeat); } #endif // SEND_DAIKIN160 -void IRDaikin160::on() { - remote_state[kDaikin160BytePower] |= kDaikinBitPower; +void IRDaikin160::on(void) { setPower(true); } + +void IRDaikin160::off(void) { setPower(false); } + +void IRDaikin160::setPower(const bool on) { + setBit(&remote_state[kDaikin160BytePower], kDaikinBitPowerOffset, on); } -void IRDaikin160::off() { - remote_state[kDaikin160BytePower] &= ~kDaikinBitPower; +bool IRDaikin160::getPower(void) { + return GETBIT8(remote_state[kDaikin160BytePower], kDaikinBitPowerOffset); } -void IRDaikin160::setPower(const bool state) { - if (state) - on(); - else - off(); -} - -bool IRDaikin160::getPower() { - return remote_state[kDaikin160BytePower] & kDaikinBitPower; -} - -uint8_t IRDaikin160::getMode() { - return (remote_state[kDaikin160ByteMode] & kDaikin160MaskMode) >> 4; +uint8_t IRDaikin160::getMode(void) { + return GETBITS8(remote_state[kDaikin160ByteMode], kHighNibble, kModeBitsSize); } void IRDaikin160::setMode(const uint8_t mode) { @@ -1810,11 +1737,10 @@ void IRDaikin160::setMode(const uint8_t mode) { case kDaikinHeat: case kDaikinFan: case kDaikinDry: - remote_state[kDaikin160ByteMode] &= ~kDaikin160MaskMode; - remote_state[kDaikin160ByteMode] |= (mode << 4); + setBits(&remote_state[kDaikin160ByteMode], kHighNibble, kModeBitsSize, + mode); break; - default: - this->setMode(kDaikinAuto); + default: this->setMode(kDaikinAuto); } } @@ -1826,13 +1752,14 @@ uint8_t IRDaikin160::convertMode(const stdAc::opmode_t mode) { // Set the temp in deg C void IRDaikin160::setTemp(const uint8_t temp) { uint8_t degrees = std::max(temp, kDaikinMinTemp); - degrees = std::min(degrees, kDaikinMaxTemp) * 2 - 20; - remote_state[kDaikin160ByteTemp] &= ~kDaikin160MaskTemp; - remote_state[kDaikin160ByteTemp] |= degrees; + degrees = std::min(degrees, kDaikinMaxTemp) - 10; + setBits(&remote_state[kDaikin160ByteTemp], kDaikin160TempOffset, + kDaikin160TempSize, degrees); } uint8_t IRDaikin160::getTemp(void) { - return (((remote_state[kDaikin160ByteTemp] & kDaikin160MaskTemp) / 2 ) + 10); + return GETBITS8(remote_state[kDaikin160ByteTemp], kDaikin160TempOffset, + kDaikin160TempSize) + 10; } // Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet @@ -1845,12 +1772,12 @@ void IRDaikin160::setFan(const uint8_t fan) { else fanset = 2 + fan; // Set the fan speed bits, leave *upper* 4 bits alone - remote_state[kDaikin160ByteFan] &= ~kDaikin160MaskFan; - remote_state[kDaikin160ByteFan] |= fanset; + setBits(&remote_state[kDaikin160ByteFan], kLowNibble, kDaikinFanSize, fanset); } -uint8_t IRDaikin160::getFan() { - uint8_t fan = remote_state[kDaikin160ByteFan] & kDaikin160MaskFan; +uint8_t IRDaikin160::getFan(void) { + uint8_t fan = GETBITS8(remote_state[kDaikin160ByteFan], kLowNibble, + kDaikinFanSize); if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2; return fan; } @@ -1876,16 +1803,16 @@ void IRDaikin160::setSwingVertical(const uint8_t position) { case kDaikin160SwingVHigh: case kDaikin160SwingVHighest: case kDaikin160SwingVAuto: - remote_state[kDaikin160ByteSwingV] &= ~kDaikin160MaskSwingV; - remote_state[kDaikin160ByteSwingV] |= (position << 4); + setBits(&remote_state[kDaikin160ByteSwingV], kHighNibble, + kDaikinSwingSize, position); break; - default: - setSwingVertical(kDaikin160SwingVAuto); + default: setSwingVertical(kDaikin160SwingVAuto); } } uint8_t IRDaikin160::getSwingVertical(void) { - return remote_state[kDaikin160ByteSwingV] >> 4; + return GETBITS8(remote_state[kDaikin160ByteSwingV], kHighNibble, + kDaikinSwingSize); } // Convert a standard A/C vertical swing into its native version. @@ -1941,26 +1868,27 @@ stdAc::state_t IRDaikin160::toCommon(void) { } // Convert the internal state into a human readable string. -String IRDaikin160::toString() { +String IRDaikin160::toString(void) { String result = ""; result.reserve(150); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kDaikinAuto, kDaikinCool, kDaikinHeat, kDaikinDry, kDaikinFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kDaikinFanMax, kDaikinFanMin, kDaikinFanAuto, kDaikinFanQuiet, kDaikinFanMed); - result += addIntToString(getSwingVertical(), F("Vent Position (V)")); + result += addIntToString(getSwingVertical(), kSwingVStr); + result += kSpaceLBraceStr; switch (getSwingVertical()) { - case kDaikin160SwingVHighest: result += F(" (Highest)"); break; - case kDaikin160SwingVHigh: result += F(" (High)"); break; - case kDaikin160SwingVMiddle: result += F(" (Middle)"); break; - case kDaikin160SwingVLow: result += F(" (Low)"); break; - case kDaikin160SwingVLowest: result += F(" (Lowest)"); break; - case kDaikin160SwingVAuto: result += F(" (Auto)"); break; - default: - result += F(" (Unknown)"); + case kDaikin160SwingVHighest: result += kHighestStr; break; + case kDaikin160SwingVHigh: result += kHighStr; break; + case kDaikin160SwingVMiddle: result += kMiddleStr; break; + case kDaikin160SwingVLow: result += kLowStr; break; + case kDaikin160SwingVLowest: result += kLowestStr; break; + case kDaikin160SwingVAuto: result += kAutoStr; break; + default: result += kUnknownStr; } + result += ')'; return result; } @@ -2069,7 +1997,7 @@ IRDaikin176::IRDaikin176(const uint16_t pin, const bool inverted, const bool use_modulation) : _irsend(pin, inverted, use_modulation) { stateReset(); } -void IRDaikin176::begin() { _irsend.begin(); } +void IRDaikin176::begin(void) { _irsend.begin(); } // Verify the checksum is valid for a given state. // Args: @@ -2092,14 +2020,14 @@ bool IRDaikin176::validChecksum(uint8_t state[], const uint16_t length) { } // Calculate and set the checksum values for the internal state. -void IRDaikin176::checksum() { +void IRDaikin176::checksum(void) { remote_state[kDaikin176Section1Length - 1] = sumBytes( remote_state, kDaikin176Section1Length - 1); remote_state[kDaikin176StateLength - 1] = sumBytes( remote_state + kDaikin176Section1Length, kDaikin176Section2Length - 1); } -void IRDaikin176::stateReset() { +void IRDaikin176::stateReset(void) { for (uint8_t i = 0; i < kDaikin176StateLength; i++) remote_state[i] = 0x00; remote_state[0] = 0x11; remote_state[1] = 0xDA; @@ -2119,42 +2047,37 @@ void IRDaikin176::stateReset() { _saved_temp = getTemp(); } -uint8_t *IRDaikin176::getRaw() { +uint8_t *IRDaikin176::getRaw(void) { checksum(); // Ensure correct settings before sending. return remote_state; } void IRDaikin176::setRaw(const uint8_t new_code[]) { - for (uint8_t i = 0; i < kDaikin176StateLength; i++) - remote_state[i] = new_code[i]; + memcpy(remote_state, new_code, kDaikin176StateLength); _saved_temp = getTemp(); } #if SEND_DAIKIN176 void IRDaikin176::send(const uint16_t repeat) { - checksum(); - _irsend.sendDaikin176(remote_state, kDaikin176StateLength, repeat); + _irsend.sendDaikin176(getRaw(), kDaikin176StateLength, repeat); } #endif // SEND_DAIKIN176 -void IRDaikin176::on() { setPower(true); } +void IRDaikin176::on(void) { setPower(true); } -void IRDaikin176::off() { setPower(false); } +void IRDaikin176::off(void) { setPower(false); } -void IRDaikin176::setPower(const bool state) { +void IRDaikin176::setPower(const bool on) { remote_state[kDaikin176ByteModeButton] = 0; - if (state) - remote_state[kDaikin176BytePower] |= kDaikinBitPower; - else - remote_state[kDaikin176BytePower] &= ~kDaikinBitPower; + setBit(&remote_state[kDaikin176BytePower], kDaikinBitPowerOffset, on); } -bool IRDaikin176::getPower() { - return remote_state[kDaikin176BytePower] & kDaikinBitPower; +bool IRDaikin176::getPower(void) { + return GETBIT8(remote_state[kDaikin176BytePower], kDaikinBitPowerOffset); } -uint8_t IRDaikin176::getMode() { - return (remote_state[kDaikin176ByteMode] & kDaikin176MaskMode) >> 4; +uint8_t IRDaikin176::getMode(void) { + return GETBITS8(remote_state[kDaikin176ByteMode], kHighNibble, kModeBitsSize); } void IRDaikin176::setMode(const uint8_t mode) { @@ -2166,11 +2089,9 @@ void IRDaikin176::setMode(const uint8_t mode) { default: this->setMode(kDaikin176Cool); return; } // Set the mode. - remote_state[kDaikin176ByteMode] &= ~kDaikin176MaskMode; - remote_state[kDaikin176ByteMode] |= (mode << 4); - // Set the altmode - remote_state[kDaikin176BytePower] &= ~kDaikin176MaskMode; - remote_state[kDaikin176BytePower] |= (altmode << 4); + setBits(&remote_state[kDaikin176ByteMode], kHighNibble, kModeBitsSize, mode); + setBits(&remote_state[kDaikin176BytePower], kHighNibble, kModeBitsSize, + altmode); setTemp(_saved_temp); // Needs to happen after setTemp() as it will clear it. remote_state[kDaikin176ByteModeButton] = kDaikin176ModeButton; @@ -2179,13 +2100,10 @@ void IRDaikin176::setMode(const uint8_t mode) { // Convert a standard A/C mode into its native mode. uint8_t IRDaikin176::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kDry: - return kDaikinDry; + case stdAc::opmode_t::kDry: return kDaikinDry; case stdAc::opmode_t::kHeat: // Heat not supported, but fan is the closest. - case stdAc::opmode_t::kFan: - return kDaikinFan; - default: - return kDaikin176Cool; + case stdAc::opmode_t::kFan: return kDaikinFan; + default: return kDaikin176Cool; } } @@ -2208,14 +2126,14 @@ void IRDaikin176::setTemp(const uint8_t temp) { case kDaikinFan: degrees = kDaikin176DryFanTemp; } - degrees = degrees * 2 - 18; - remote_state[kDaikin176ByteTemp] &= ~kDaikin176MaskTemp; - remote_state[kDaikin176ByteTemp] |= degrees; + setBits(&remote_state[kDaikin176ByteTemp], kDaikin176TempOffset, + kDaikin176TempSize, degrees - 9); remote_state[kDaikin176ByteModeButton] = 0; } uint8_t IRDaikin176::getTemp(void) { - return (((remote_state[kDaikin176ByteTemp] & kDaikin176MaskTemp) / 2 ) + 9); + return GETBITS8(remote_state[kDaikin176ByteTemp], kDaikin176TempOffset, + kDaikin176TempSize) + 9; } // Set the speed of the fan, 1 for Min or 3 for Max @@ -2223,8 +2141,8 @@ void IRDaikin176::setFan(const uint8_t fan) { switch (fan) { case kDaikinFanMin: case kDaikin176FanMax: - remote_state[kDaikin176ByteFan] &= ~kDaikin176MaskFan; - remote_state[kDaikin176ByteFan] |= (fan << 4); + setBits(&remote_state[kDaikin176ByteFan], kHighNibble, kDaikinFanSize, + fan); remote_state[kDaikin176ByteModeButton] = 0; break; default: @@ -2232,16 +2150,16 @@ void IRDaikin176::setFan(const uint8_t fan) { } } -uint8_t IRDaikin176::getFan() { return remote_state[kDaikin176ByteFan] >> 4; } +uint8_t IRDaikin176::getFan(void) { + return GETBITS8(remote_state[kDaikin176ByteFan], kHighNibble, kDaikinFanSize); +} // Convert a standard A/C Fan speed into its native fan speed. uint8_t IRDaikin176::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kDaikinFanMin; - default: - return kDaikin176FanMax; + case stdAc::fanspeed_t::kLow: return kDaikinFanMin; + default: return kDaikin176FanMax; } } @@ -2249,27 +2167,24 @@ void IRDaikin176::setSwingHorizontal(const uint8_t position) { switch (position) { case kDaikin176SwingHOff: case kDaikin176SwingHAuto: - remote_state[kDaikin176ByteSwingH] &= ~kDaikin176MaskSwingH; - remote_state[kDaikin176ByteSwingH] |= position; + setBits(&remote_state[kDaikin176ByteSwingH], kLowNibble, kDaikinSwingSize, + position); break; - default: - setSwingHorizontal(kDaikin176SwingHAuto); + default: setSwingHorizontal(kDaikin176SwingHAuto); } } -uint8_t IRDaikin176::getSwingHorizontal() { - return remote_state[kDaikin176ByteSwingH] & kDaikin176MaskSwingH; +uint8_t IRDaikin176::getSwingHorizontal(void) { + return GETBITS8(remote_state[kDaikin176ByteSwingH], kLowNibble, + kDaikinSwingSize); } // Convert a standard A/C horizontal swing into its native version. uint8_t IRDaikin176::convertSwingH(const stdAc::swingh_t position) { switch (position) { - case stdAc::swingh_t::kOff: - return kDaikin176SwingHOff; - case stdAc::swingh_t::kAuto: - return kDaikin176SwingHAuto; - default: - return kDaikin176SwingHAuto; + case stdAc::swingh_t::kOff: return kDaikin176SwingHOff; + case stdAc::swingh_t::kAuto: return kDaikin176SwingHAuto; + default: return kDaikin176SwingHAuto; } } // Convert a native horizontal swing to it's common equivalent. @@ -2315,27 +2230,28 @@ stdAc::state_t IRDaikin176::toCommon(void) { } // Convert the internal state into a human readable string. -String IRDaikin176::toString() { +String IRDaikin176::toString(void) { String result = ""; result.reserve(80); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kDaikinAuto, kDaikin176Cool, kDaikinHeat, kDaikinDry, kDaikinFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kDaikin176FanMax, kDaikinFanMin, kDaikinFanMin, kDaikinFanMin, kDaikinFanMin); - result += F(", Swing (H): "); - result += uint64ToString(getSwingHorizontal()); + result += addIntToString(getSwingHorizontal(), kSwingHStr); + result += kSpaceLBraceStr; switch (getSwingHorizontal()) { case kDaikin176SwingHAuto: - result += F(" (Auto)"); + result += kAutoStr; break; case kDaikin176SwingHOff: - result += F(" (Off)"); + result += kOffStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } + result += ')'; return result; } @@ -2453,7 +2369,7 @@ IRDaikin128::IRDaikin128(const uint16_t pin, const bool inverted, const bool use_modulation) : _irsend(pin, inverted, use_modulation) { stateReset(); } -void IRDaikin128::begin() { _irsend.begin(); } +void IRDaikin128::begin(void) { _irsend.begin(); } uint8_t IRDaikin128::calcFirstChecksum(const uint8_t state[]) { return sumNibbles(state, kDaikin128SectionLength - 1, @@ -2481,14 +2397,14 @@ bool IRDaikin128::validChecksum(uint8_t state[]) { } // Calculate and set the checksum values for the internal state. -void IRDaikin128::checksum() { +void IRDaikin128::checksum(void) { remote_state[kDaikin128SectionLength - 1] &= 0x0F; // Clear upper half. remote_state[kDaikin128SectionLength - 1] |= (calcFirstChecksum(remote_state) << 4); remote_state[kDaikin128StateLength - 1] = calcSecondChecksum(remote_state); } -void IRDaikin128::stateReset() { +void IRDaikin128::stateReset(void) { for (uint8_t i = 0; i < kDaikin128StateLength; i++) remote_state[i] = 0x00; remote_state[0] = 0x16; remote_state[7] = 0x04; // Most significant nibble is a checksum. @@ -2496,36 +2412,34 @@ void IRDaikin128::stateReset() { // remote_state[15] is a checksum byte, it will be set by checksum(). } -uint8_t *IRDaikin128::getRaw() { +uint8_t *IRDaikin128::getRaw(void) { checksum(); // Ensure correct settings before sending. return remote_state; } void IRDaikin128::setRaw(const uint8_t new_code[]) { - for (uint8_t i = 0; i < kDaikin128StateLength; i++) - remote_state[i] = new_code[i]; + memcpy(remote_state, new_code, kDaikin128StateLength); } #if SEND_DAIKIN128 void IRDaikin128::send(const uint16_t repeat) { - checksum(); - _irsend.sendDaikin128(remote_state, kDaikin128StateLength, repeat); + _irsend.sendDaikin128(getRaw(), kDaikin128StateLength, repeat); } #endif // SEND_DAIKIN128 void IRDaikin128::setPowerToggle(const bool toggle) { - if (toggle) - remote_state[kDaikin128BytePowerSwingSleep] |= kDaikin128BitPowerToggle; - else - remote_state[kDaikin128BytePowerSwingSleep] &= ~kDaikin128BitPowerToggle; + setBit(&remote_state[kDaikin128BytePowerSwingSleep], + kDaikin128BitPowerToggleOffset, toggle); } bool IRDaikin128::getPowerToggle(void) { - return remote_state[kDaikin128BytePowerSwingSleep] & kDaikin128BitPowerToggle; + return GETBIT8(remote_state[kDaikin128BytePowerSwingSleep], + kDaikin128BitPowerToggleOffset); } -uint8_t IRDaikin128::getMode() { - return remote_state[kDaikin128ByteModeFan] & kDaikin128MaskMode; +uint8_t IRDaikin128::getMode(void) { + return GETBITS8(remote_state[kDaikin128ByteModeFan], kLowNibble, + kDaikin128ModeSize); } void IRDaikin128::setMode(const uint8_t mode) { @@ -2535,8 +2449,8 @@ void IRDaikin128::setMode(const uint8_t mode) { case kDaikin128Heat: case kDaikin128Fan: case kDaikin128Dry: - remote_state[kDaikin128ByteModeFan] &= ~kDaikin128MaskMode; - remote_state[kDaikin128ByteModeFan] |= mode; + setBits(&remote_state[kDaikin128ByteModeFan], kLowNibble, + kDaikin128ModeSize, mode); break; default: this->setMode(kDaikin128Auto); @@ -2550,16 +2464,11 @@ void IRDaikin128::setMode(const uint8_t mode) { // Convert a standard A/C mode into its native mode. uint8_t IRDaikin128::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kDaikin128Cool; - case stdAc::opmode_t::kHeat: - return kDaikin128Heat; - case stdAc::opmode_t::kDry: - return kDaikinDry; - case stdAc::opmode_t::kFan: - return kDaikin128Fan; - default: - return kDaikin128Auto; + case stdAc::opmode_t::kCool: return kDaikin128Cool; + case stdAc::opmode_t::kHeat: return kDaikin128Heat; + case stdAc::opmode_t::kDry: return kDaikinDry; + case stdAc::opmode_t::kFan: return kDaikin128Fan; + default: return kDaikin128Auto; } } @@ -2584,8 +2493,9 @@ uint8_t IRDaikin128::getTemp(void) { return bcdToUint8(remote_state[kDaikin128ByteTemp]); } -uint8_t IRDaikin128::getFan() { - return (remote_state[kDaikin128ByteModeFan] & kDaikin128MaskFan) >> 4; +uint8_t IRDaikin128::getFan(void) { + return GETBITS8(remote_state[kDaikin128ByteModeFan], kHighNibble, + kDaikinFanSize); } void IRDaikin128::setFan(const uint8_t speed) { @@ -2600,9 +2510,8 @@ void IRDaikin128::setFan(const uint8_t speed) { case kDaikin128FanHigh: case kDaikin128FanMed: case kDaikin128FanLow: - // if (mode == kDaikinDry) new_speed = kDaikin128FanMed; - remote_state[kDaikin128ByteModeFan] &= ~kDaikin128MaskFan; - remote_state[kDaikin128ByteModeFan] |= (new_speed << 4); + setBits(&remote_state[kDaikin128ByteModeFan], kHighNibble, kDaikinFanSize, + new_speed); break; default: this->setFan(kDaikin128FanAuto); @@ -2634,37 +2543,34 @@ stdAc::fanspeed_t IRDaikin128::toCommonFanSpeed(const uint8_t speed) { } void IRDaikin128::setSwingVertical(const bool on) { - if (on) - remote_state[kDaikin128BytePowerSwingSleep] |= kDaikin128BitSwing; - else - remote_state[kDaikin128BytePowerSwingSleep] &= ~kDaikin128BitSwing; + setBit(&remote_state[kDaikin128BytePowerSwingSleep], kDaikin128BitSwingOffset, + on); } bool IRDaikin128::getSwingVertical(void) { - return remote_state[kDaikin128BytePowerSwingSleep] & kDaikin128BitSwing; + return GETBIT8(remote_state[kDaikin128BytePowerSwingSleep], + kDaikin128BitSwingOffset); } void IRDaikin128::setSleep(const bool on) { - if (on) - remote_state[kDaikin128BytePowerSwingSleep] |= kDaikin128BitSleep; - else - remote_state[kDaikin128BytePowerSwingSleep] &= ~kDaikin128BitSleep; + setBit(&remote_state[kDaikin128BytePowerSwingSleep], kDaikin128BitSleepOffset, + on); } bool IRDaikin128::getSleep(void) { - return remote_state[kDaikin128BytePowerSwingSleep] & kDaikin128BitSleep; + return GETBIT8(remote_state[kDaikin128BytePowerSwingSleep], + kDaikin128BitSleepOffset); } void IRDaikin128::setEcono(const bool on) { uint8_t mode = getMode(); - if (on && (mode == kDaikin128Cool || mode == kDaikin128Heat)) - remote_state[kDaikin128ByteEconoLight] |= kDaikin128BitEcono; - else - remote_state[kDaikin128ByteEconoLight] &= ~kDaikin128BitEcono; + setBit(&remote_state[kDaikin128ByteEconoLight], kDaikin128BitEconoOffset, + on && (mode == kDaikin128Cool || mode == kDaikin128Heat)); } bool IRDaikin128::getEcono(void) { - return remote_state[kDaikin128ByteEconoLight] & kDaikin128BitEcono; + return GETBIT8(remote_state[kDaikin128ByteEconoLight], + kDaikin128BitEconoOffset); } void IRDaikin128::setQuiet(const bool on) { @@ -2707,14 +2613,13 @@ uint16_t IRDaikin128::getClock(void) { } void IRDaikin128::setOnTimerEnabled(const bool on) { - if (on) - remote_state[kDaikin128ByteOnTimer] |= kDaikin128BitTimerEnabled; - else - remote_state[kDaikin128ByteOnTimer] &= ~kDaikin128BitTimerEnabled; + setBit(&remote_state[kDaikin128ByteOnTimer], kDaikin128BitTimerEnabledOffset, + on); } bool IRDaikin128::getOnTimerEnabled(void) { - return remote_state[kDaikin128ByteOnTimer] & kDaikin128BitTimerEnabled; + return GETBIT8(remote_state[kDaikin128ByteOnTimer], + kDaikin128BitTimerEnabledOffset); } // Timer is rounds down to the nearest half hour. @@ -2724,11 +2629,11 @@ bool IRDaikin128::getOnTimerEnabled(void) { void IRDaikin128::setTimer(uint8_t *ptr, const uint16_t mins_since_midnight) { uint16_t mins = mins_since_midnight; if (mins_since_midnight >= 24 * 60) mins = 0; // Bounds check. - // Clear the time component - *ptr &= kDaikin128BitTimerEnabled; - uint8_t bcdhours = uint8ToBcd(mins / 60); - bool addhalf = (mins % 60) >= 30; - *ptr |= ((addhalf << 6) | bcdhours); + // Set the half hour bit + setBit(ptr, kDaikin128HalfHourOffset, (mins % 60) >= 30); + // Set the nr of whole hours. + setBits(ptr, kDaikin128HoursOffset, kDaikin128HoursSize, + uint8ToBcd(mins / 60)); } // Timer is stored in nr of half hours internally. @@ -2737,9 +2642,9 @@ void IRDaikin128::setTimer(uint8_t *ptr, const uint16_t mins_since_midnight) { // Returns: // A uint16_t containing the number of minutes since midnight. uint16_t IRDaikin128::getTimer(const uint8_t *ptr) { - uint8_t bcdhours = *ptr & kDaikin128MaskHours; - bool addhalf = *ptr & kDaikin128BitHalfHour; - return bcdToUint8(bcdhours) * 60 + (addhalf ? 30 : 0); + return bcdToUint8(GETBITS8(*ptr, kDaikin128HoursOffset, + kDaikin128HoursSize)) * 60 + + (GETBIT8(*ptr, kDaikin128HalfHourOffset) ? 30 : 0); } void IRDaikin128::setOnTimer(const uint16_t mins_since_midnight) { @@ -2751,14 +2656,13 @@ uint16_t IRDaikin128::getOnTimer(void) { } void IRDaikin128::setOffTimerEnabled(const bool on) { - if (on) - remote_state[kDaikin128ByteOffTimer] |= kDaikin128BitTimerEnabled; - else - remote_state[kDaikin128ByteOffTimer] &= ~kDaikin128BitTimerEnabled; + setBit(&remote_state[kDaikin128ByteOffTimer], kDaikin128BitTimerEnabledOffset, + on); } bool IRDaikin128::getOffTimerEnabled(void) { - return remote_state[kDaikin128ByteOffTimer] & kDaikin128BitTimerEnabled; + return GETBIT8(remote_state[kDaikin128ByteOffTimer], + kDaikin128BitTimerEnabledOffset); } void IRDaikin128::setOffTimer(const uint16_t mins_since_midnight) { @@ -2771,9 +2675,9 @@ uint16_t IRDaikin128::getOffTimer(void) { void IRDaikin128::setLightToggle(const uint8_t unit) { switch (unit) { + case 0: case kDaikin128BitCeiling: case kDaikin128BitWall: - case 0: remote_state[kDaikin128ByteEconoLight] &= ~kDaikin128MaskLight; remote_state[kDaikin128ByteEconoLight] |= unit; break; @@ -2789,30 +2693,31 @@ uint8_t IRDaikin128::getLightToggle(void) { String IRDaikin128::toString(void) { String result = ""; result.reserve(240); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPowerToggle(), F("Power Toggle"), false); + result += addBoolToString(getPowerToggle(), kPowerStr + ' ' + kToggleStr, + false); result += addModeToString(getMode(), kDaikin128Auto, kDaikin128Cool, kDaikin128Heat, kDaikin128Dry, kDaikin128Fan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kDaikin128FanHigh, kDaikin128FanLow, kDaikin128FanAuto, kDaikin128FanQuiet, kDaikin128FanMed); - result += addBoolToString(getPowerful(), F("Powerful")); - result += addBoolToString(getQuiet(), F("Quiet")); - result += addBoolToString(getSwingVertical(), F("Swing (V)")); - result += addBoolToString(getSleep(), F("Sleep")); - result += addBoolToString(getEcono(), F("Econo")); - result += addLabeledString(minsToString(getClock()), F("Clock")); - result += addBoolToString(getOnTimerEnabled(), F("On Timer")); - result += addLabeledString(minsToString(getOnTimer()), F("On Time")); - result += addBoolToString(getOffTimerEnabled(), F("Off Timer")); - result += addLabeledString(minsToString(getOffTimer()), F("Off Time")); - result += addIntToString(getLightToggle(), F("Light Toggle")); - result += F(" ("); + result += addBoolToString(getPowerful(), kPowerfulStr); + result += addBoolToString(getQuiet(), kQuietStr); + result += addBoolToString(getSwingVertical(), kSwingVStr); + result += addBoolToString(getSleep(), kSleepStr); + result += addBoolToString(getEcono(), kEconoStr); + result += addLabeledString(minsToString(getClock()), kClockStr); + result += addBoolToString(getOnTimerEnabled(), kOnTimerStr); + result += addLabeledString(minsToString(getOnTimer()), kOnTimerStr); + result += addBoolToString(getOffTimerEnabled(), kOffTimerStr); + result += addLabeledString(minsToString(getOffTimer()), kOffTimerStr); + result += addIntToString(getLightToggle(), kLightStr + ' ' + kToggleStr); + result += kSpaceLBraceStr; switch (getLightToggle()) { - case kDaikin128BitCeiling: result += F("Ceiling"); break; - case kDaikin128BitWall: result += F("Wall"); break; - case 0: result += F("Off"); break; - default: result += F("UNKNOWN"); + case kDaikin128BitCeiling: result += kCeilingStr; break; + case kDaikin128BitWall: result += kWallStr; break; + case 0: result += kOffStr; break; + default: result += kUnknownStr; } result += ')'; return result; @@ -2924,7 +2829,7 @@ bool IRrecv::decodeDaikin128(decode_results *results, const uint16_t nbits, // Supported devices: // - Daikin ARC480A5 remote. // -// Status: Beta / Probably working. +// Status: STABLE / Known working. // // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/873 void IRsend::sendDaikin152(const unsigned char data[], const uint16_t nbytes, @@ -2957,7 +2862,7 @@ void IRsend::sendDaikin152(const unsigned char data[], const uint16_t nbytes, // Supported devices: // - Daikin ARC480A5 remote. // -// Status: Beta / Probably working. +// Status: STABLE / Known working. // // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/873 bool IRrecv::decodeDaikin152(decode_results *results, const uint16_t nbits, @@ -3017,16 +2922,17 @@ bool IRrecv::decodeDaikin152(decode_results *results, const uint16_t nbits, // // Ref: // https://github.com/crankyoldgit/IRremoteESP8266/issues/873 +// https://github.com/ToniA/arduino-heatpumpir/blob/master/DaikinHeatpumpARC480A14IR.cpp +// https://github.com/ToniA/arduino-heatpumpir/blob/master/DaikinHeatpumpARC480A14IR.h IRDaikin152::IRDaikin152(const uint16_t pin, const bool inverted, const bool use_modulation) : _irsend(pin, inverted, use_modulation) { stateReset(); } -void IRDaikin152::begin() { _irsend.begin(); } +void IRDaikin152::begin(void) { _irsend.begin(); } #if SEND_DAIKIN152 void IRDaikin152::send(const uint16_t repeat) { - checksum(); - _irsend.sendDaikin152(remote_state, kDaikin152StateLength, repeat); + _irsend.sendDaikin152(getRaw(), kDaikin152StateLength, repeat); } #endif // SEND_DAIKIN152 @@ -3045,25 +2951,223 @@ bool IRDaikin152::validChecksum(uint8_t state[], const uint16_t length) { } // Calculate and set the checksum values for the internal state. -void IRDaikin152::checksum() { +void IRDaikin152::checksum(void) { remote_state[kDaikin152StateLength - 1] = sumBytes( remote_state, kDaikin152StateLength - 1); } -void IRDaikin152::stateReset() { +void IRDaikin152::stateReset(void) { for (uint8_t i = 3; i < kDaikin152StateLength; i++) remote_state[i] = 0x00; remote_state[0] = 0x11; remote_state[1] = 0xDA; remote_state[2] = 0x27; + remote_state[15] = 0xC5; // remote_state[19] is a checksum byte, it will be set by checksum(). } -uint8_t *IRDaikin152::getRaw() { +uint8_t *IRDaikin152::getRaw(void) { checksum(); // Ensure correct settings before sending. return remote_state; } void IRDaikin152::setRaw(const uint8_t new_code[]) { - for (uint8_t i = 0; i < kDaikin152StateLength; i++) - remote_state[i] = new_code[i]; + memcpy(remote_state, new_code, kDaikin152StateLength); +} + +void IRDaikin152::on(void) { setPower(true); } + +void IRDaikin152::off(void) { setPower(false); } + +void IRDaikin152::setPower(const bool on) { + setBit(&remote_state[kDaikin152PowerByte], kDaikinBitPowerOffset, on); +} + +bool IRDaikin152::getPower(void) { + return GETBIT8(remote_state[kDaikin152PowerByte], kDaikinBitPowerOffset); +} + +uint8_t IRDaikin152::getMode(void) { + return GETBITS8(remote_state[kDaikin152ModeByte], kDaikinModeOffset, + kDaikinModeSize); +} + +void IRDaikin152::setMode(const uint8_t mode) { + switch (mode) { + case kDaikinFan: + setTemp(kDaikin152FanTemp); // Handle special temp for fan mode. + break; + case kDaikinDry: + setTemp(kDaikin152DryTemp); // Handle special temp for dry mode. + break; + case kDaikinAuto: + case kDaikinCool: + case kDaikinHeat: + break; + default: + this->setMode(kDaikinAuto); + return; + } + setBits(&remote_state[kDaikin152ModeByte], kDaikinModeOffset, + kDaikinModeSize, mode); +} + +// Convert a standard A/C mode into its native mode. +uint8_t IRDaikin152::convertMode(const stdAc::opmode_t mode) { + return IRDaikinESP::convertMode(mode); +} + +// Set the temp in deg C +void IRDaikin152::setTemp(const uint8_t temp) { + uint8_t degrees = std::max( + temp, (getMode() == kDaikinHeat) ? kDaikinMinTemp : kDaikin2MinCoolTemp); + degrees = std::min(degrees, kDaikinMaxTemp); + if (temp == kDaikin152FanTemp) degrees = temp; // Handle fan only temp. + setBits(&remote_state[kDaikin152TempByte], kDaikinTempOffset, + kDaikin152TempSize, degrees); +} + +uint8_t IRDaikin152::getTemp(void) { + return GETBITS8(remote_state[kDaikin152TempByte], kDaikinTempOffset, + kDaikin152TempSize); +} + +// Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet +void IRDaikin152::setFan(const uint8_t fan) { + // Set the fan speed bits, leave low 4 bits alone + uint8_t fanset; + if (fan == kDaikinFanQuiet || fan == kDaikinFanAuto) + fanset = fan; + else if (fan < kDaikinFanMin || fan > kDaikinFanMax) + fanset = kDaikinFanAuto; + else + fanset = 2 + fan; + setBits(&remote_state[kDaikin152FanByte], kHighNibble, kNibbleSize, fanset); +} + +uint8_t IRDaikin152::getFan(void) { + const uint8_t fan = GETBITS8(remote_state[kDaikin152FanByte], kHighNibble, + kNibbleSize); + switch (fan) { + case kDaikinFanAuto: + case kDaikinFanQuiet: return fan; + default: return fan - 2; + } +} + +// Convert a standard A/C Fan speed into its native fan speed. +uint8_t IRDaikin152::convertFan(const stdAc::fanspeed_t speed) { + return IRDaikinESP::convertFan(speed); +} + +void IRDaikin152::setSwingV(const bool on) { + setBits(&remote_state[kDaikin152SwingVByte], kDaikinSwingOffset, + kDaikinSwingSize, on ? kDaikinSwingOn : kDaikinSwingOff); +} + +bool IRDaikin152::getSwingV(void) { + return GETBITS8(remote_state[kDaikin152SwingVByte], kDaikinSwingOffset, + kDaikinSwingSize); +} + +void IRDaikin152::setQuiet(const bool on) { + setBit(&remote_state[kDaikin152QuietByte], kDaikinBitSilentOffset, on); + // Powerful & Quiet mode being on are mutually exclusive. + if (on) this->setPowerful(false); +} + +bool IRDaikin152::getQuiet(void) { + return GETBIT8(remote_state[kDaikin152QuietByte], kDaikinBitSilentOffset); +} + +void IRDaikin152::setPowerful(const bool on) { + setBit(&remote_state[kDaikin152PowerfulByte], kDaikinBitPowerfulOffset, on); + if (on) { + // Powerful, Quiet, Comfortm & Econo mode being on are mutually exclusive. + this->setQuiet(false); + this->setComfort(false); + this->setEcono(false); + } +} + +bool IRDaikin152::getPowerful(void) { + return GETBIT8(remote_state[kDaikin152PowerfulByte], + kDaikinBitPowerfulOffset); +} + +void IRDaikin152::setEcono(const bool on) { + setBit(&remote_state[kDaikin152EconoByte], kDaikinBitEconoOffset, on); + // Powerful & Econo mode being on are mutually exclusive. + if (on) this->setPowerful(false); +} + +bool IRDaikin152::getEcono(void) { + return GETBIT8(remote_state[kDaikin152EconoByte], kDaikinBitEconoOffset); +} + +void IRDaikin152::setSensor(const bool on) { + setBit(&remote_state[kDaikin152SensorByte], kDaikin152SensorOffset, on); +} + +bool IRDaikin152::getSensor(void) { + return GETBIT8(remote_state[kDaikin152SensorByte], kDaikin152SensorOffset); +} + +void IRDaikin152::setComfort(const bool on) { + setBit(&remote_state[kDaikin152ComfortByte], kDaikin152ComfortOffset, on); + if (on) { + // Comfort mode is incompatible with Powerful mode. + setPowerful(false); + // It also sets the fan to auto and turns off swingv. + setFan(kDaikinFanAuto); + setSwingV(false); + } +} + +bool IRDaikin152::getComfort(void) { + return GETBIT8(remote_state[kDaikin152ComfortByte], kDaikin152ComfortOffset); +} + +// Convert the A/C state to it's common equivalent. +stdAc::state_t IRDaikin152::toCommon(void) { + stdAc::state_t result; + result.protocol = decode_type_t::DAIKIN152; + result.model = -1; // No models used. + result.power = this->getPower(); + result.mode = IRDaikinESP::toCommonMode(this->getMode()); + result.celsius = true; + result.degrees = this->getTemp(); + result.fanspeed = IRDaikinESP::toCommonFanSpeed(this->getFan()); + result.swingv = this->getSwingV() ? stdAc::swingv_t::kAuto + : stdAc::swingv_t::kOff; + result.quiet = this->getQuiet(); + result.turbo = this->getPowerful(); + result.econo = this->getEcono(); + // Not supported. + result.swingh = stdAc::swingh_t::kOff; + result.clean = false; + result.filter = false; + result.light = false; + result.beep = false; + result.sleep = -1; + result.clock = -1; + return result; +} + +// Convert the internal state into a human readable string. +String IRDaikin152::toString(void) { + String result = ""; + result.reserve(180); // Reserve some heap for the string to reduce fragging. + result += addBoolToString(getPower(), kPowerStr, false); + result += addModeToString(getMode(), kDaikinAuto, kDaikinCool, kDaikinHeat, + kDaikinDry, kDaikinFan); + result += addTempToString(getTemp()); + result += addFanToString(getFan(), kDaikinFanMax, kDaikinFanMin, + kDaikinFanAuto, kDaikinFanQuiet, kDaikinFanMed); + result += addBoolToString(getSwingV(), kSwingVStr); + result += addBoolToString(getPowerful(), kPowerfulStr); + result += addBoolToString(getQuiet(), kQuietStr); + result += addBoolToString(getEcono(), kEconoStr); + result += addBoolToString(getSensor(), kSensorStr); + result += addBoolToString(getComfort(), kComfortStr); + return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Daikin.h b/lib/IRremoteESP8266-2.7.0/src/ir_Daikin.h old mode 100755 new mode 100644 similarity index 76% rename from lib/IRremoteESP8266-2.6.5/src/ir_Daikin.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Daikin.h index 98a38c640..42039b07b --- a/lib/IRremoteESP8266-2.6.5/src/ir_Daikin.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Daikin.h @@ -91,17 +91,25 @@ // Constants const uint8_t kDaikinAuto = 0b000; -const uint8_t kDaikinDry = 0b010; +const uint8_t kDaikinDry = 0b010; const uint8_t kDaikinCool = 0b011; const uint8_t kDaikinHeat = 0b100; -const uint8_t kDaikinFan = 0b110; +const uint8_t kDaikinFan = 0b110; +const uint8_t kDaikinModeOffset = 4; +const uint8_t kDaikinModeSize = 3; const uint8_t kDaikinMinTemp = 10; // Celsius const uint8_t kDaikinMaxTemp = 32; // Celsius const uint8_t kDaikinFanMin = 1; const uint8_t kDaikinFanMed = 3; const uint8_t kDaikinFanMax = 5; -const uint8_t kDaikinFanAuto = 0b1010; -const uint8_t kDaikinFanQuiet = 0b1011; +const uint8_t kDaikinFanAuto = 0b1010; // 10 / 0xA +const uint8_t kDaikinFanQuiet = 0b1011; // 11 / 0xB +const uint8_t kDaikinFanOffset = 4; +const uint8_t kDaikinFanSize = 4; +const uint8_t kDaikinSwingOffset = 0; +const uint8_t kDaikinSwingSize = 4; +const uint8_t kDaikinSwingOn = 0b1111; +const uint8_t kDaikinSwingOff = 0b0000; const uint16_t kDaikinHeaderLength = 5; const uint8_t kDaikinSections = 3; const uint8_t kDaikinSection1Length = 8; @@ -110,37 +118,55 @@ const uint8_t kDaikinSection3Length = kDaikinStateLength - kDaikinSection1Length - kDaikinSection2Length; const uint8_t kDaikinByteComfort = 6; const uint8_t kDaikinByteChecksum1 = 7; -const uint8_t kDaikinBitComfort = 0b00010000; +const uint8_t kDaikinBitComfortOffset = 4; +const uint8_t kDaikinBitComfort = 1 << kDaikinBitComfortOffset; const uint8_t kDaikinByteClockMinsLow = 13; const uint8_t kDaikinByteClockMinsHigh = 14; +const uint8_t kDaikinClockMinsHighOffset = 0; +const uint8_t kDaikinClockMinsHighSize = 3; +const uint8_t kDaikinDoWOffset = 3; +const uint8_t kDaikinDoWSize = 3; const uint8_t kDaikinByteChecksum2 = 15; const uint8_t kDaikinBytePower = 21; -const uint8_t kDaikinBitPower = 0b00000001; +const uint8_t kDaikinBitPowerOffset = 0; +const uint8_t kDaikinBitPower = 1 << kDaikinBitPowerOffset; +const uint8_t kDaikinTempOffset = 1; +const uint8_t kDaikinTempSize = 6; const uint8_t kDaikinByteTemp = 22; const uint8_t kDaikinByteFan = 24; const uint8_t kDaikinByteSwingH = 25; const uint8_t kDaikinByteOnTimerMinsLow = 26; const uint8_t kDaikinByteOnTimerMinsHigh = 27; +const uint8_t kDaikinOnTimerMinsHighOffset = 0; +const uint8_t kDaikinOnTimerMinsHighSize = 4; const uint8_t kDaikinByteOffTimerMinsLow = kDaikinByteOnTimerMinsHigh; const uint8_t kDaikinByteOffTimerMinsHigh = 28; const uint8_t kDaikinBytePowerful = 29; -const uint8_t kDaikinBitPowerful = 0b00000001; +const uint8_t kDaikinBitPowerfulOffset = 0; +const uint8_t kDaikinBitPowerful = 1 << kDaikinBitPowerfulOffset; const uint8_t kDaikinByteSilent = kDaikinBytePowerful; -const uint8_t kDaikinBitSilent = 0b00100000; +const uint8_t kDaikinBitSilentOffset = 5; +const uint8_t kDaikinBitSilent = 1 << kDaikinBitSilentOffset; const uint8_t kDaikinByteSensor = 32; -const uint8_t kDaikinBitSensor = 0b00000010; +const uint8_t kDaikinBitSensorOffset = 1; +const uint8_t kDaikinBitSensor = 1 << kDaikinBitSensorOffset; const uint8_t kDaikinByteEcono = kDaikinByteSensor; -const uint8_t kDaikinBitEcono = 0b00000100; +const uint8_t kDaikinBitEconoOffset = 2; +const uint8_t kDaikinBitEcono = 1 << kDaikinBitEconoOffset; const uint8_t kDaikinByteEye = kDaikinByteSensor; const uint8_t kDaikinBitEye = 0b10000000; const uint8_t kDaikinByteWeeklyTimer = kDaikinByteSensor; -const uint8_t kDaikinBitWeeklyTimer = 0b10000000; +const uint8_t kDaikinBitWeeklyTimerOffset = 7; +const uint8_t kDaikinBitWeeklyTimer = 1 << kDaikinBitWeeklyTimerOffset; const uint8_t kDaikinByteMold = 33; -const uint8_t kDaikinBitMold = 0b00000010; +const uint8_t kDaikinBitMoldOffset = 1; +const uint8_t kDaikinBitMold = 1 << kDaikinBitMoldOffset; const uint8_t kDaikinByteOffTimer = kDaikinBytePower; -const uint8_t kDaikinBitOffTimer = 0b00000100; +const uint8_t kDaikinBitOffTimerOffset = 2; +const uint8_t kDaikinBitOffTimer = 1 << kDaikinBitOffTimerOffset; const uint8_t kDaikinByteOnTimer = kDaikinByteOffTimer; -const uint8_t kDaikinBitOnTimer = 0b00000010; +const uint8_t kDaikinBitOnTimerOffset = 1; +const uint8_t kDaikinBitOnTimer = 1 << kDaikinBitOnTimerOffset; const uint8_t kDaikinByteChecksum3 = kDaikinStateLength - 1; const uint16_t kDaikinUnusedTime = 0x600; const uint8_t kDaikinBeepQuiet = 1; @@ -177,25 +203,49 @@ const uint16_t kDaikin2Sections = 2; const uint16_t kDaikin2Section1Length = 20; const uint16_t kDaikin2Section2Length = 19; const uint8_t kDaikin2Tolerance = 5; // Extra percentage tolerance - -const uint8_t kDaikin2BitSleepTimer = 0b00100000; -const uint8_t kDaikin2BitPurify = 0b00010000; -const uint8_t kDaikin2BitEye = 0b00000010; -const uint8_t kDaikin2BitEyeAuto = 0b10000000; -const uint8_t kDaikin2BitMold = 0b00001000; -const uint8_t kDaikin2BitClean = 0b00100000; -const uint8_t kDaikin2BitFreshAir = 0b00000001; -const uint8_t kDaikin2BitFreshAirHigh = 0b10000000; -const uint8_t kDaikin2BitPower = 0b10000000; -const uint8_t kDaikin2LightMask = 0b00110000; -const uint8_t kDaikin2BeepMask = 0b11000000; +const uint8_t kDaikin2BitSleepTimerOffset = 5; +const uint8_t kDaikin2BitSleepTimer = 1 << kDaikin2BitSleepTimerOffset; +const uint8_t kDaikin2BitPurifyOffset = 4; +const uint8_t kDaikin2BitPurify = 1 << kDaikin2BitPurifyOffset; // 0b00010000 +const uint8_t kDaikin2BitEyeOffset = 1; +const uint8_t kDaikin2BitEye = 1 << kDaikin2BitEyeOffset; // 0b00000010 +const uint8_t kDaikin2BitEyeAutoOffset = 7; +const uint8_t kDaikin2BitEyeAuto = 1 << kDaikin2BitEyeAutoOffset; // 0b10000000 +const uint8_t kDaikin2BitMoldOffset = 3; +const uint8_t kDaikin2BitMold = 1 << kDaikin2BitMoldOffset; // 0b00001000 +const uint8_t kDaikin2BitCleanOffset = 5; // Byte[8] +const uint8_t kDaikin2BitClean = 1 << kDaikin2BitCleanOffset; // 0b00100000 +const uint8_t kDaikin2BitFreshAirOffset = 0; +const uint8_t kDaikin2BitFreshAir = 1 << kDaikin2BitFreshAirOffset; +const uint8_t kDaikin2BitFreshAirHighOffset = 7; +const uint8_t kDaikin2BitFreshAirHigh = 1 << kDaikin2BitFreshAirHighOffset; +const uint8_t kDaikin2BitPowerOffset = 7; +const uint8_t kDaikin2BitPower = 1 << kDaikin2BitPowerOffset; // 0b10000000 +// const uint8_t kDaikin2LightMask = 0b00110000; // Byte[7] +const uint8_t kDaikin2LightOffset = 4; // Byte[7] +const uint8_t kDaikin2LightSize = 2; +// const uint8_t kDaikin2BeepMask = 0b11000000; // Byte[7] +const uint8_t kDaikin2BeepOffset = 6; // Byte[7] +const uint8_t kDaikin2BeepSize = 2; const uint8_t kDaikin2SwingVHigh = 0x1; const uint8_t kDaikin2SwingVLow = 0x6; +const uint8_t kDaikin2SwingVSwing = 0xF; +const uint8_t kDaikin2SwingVAuto = 0xE; const uint8_t kDaikin2SwingVBreeze = 0xC; const uint8_t kDaikin2SwingVCirculate = 0xD; -const uint8_t kDaikin2SwingVAuto = 0xE; -const uint8_t kDaikin2SwingHAuto = 0xBE; -const uint8_t kDaikin2SwingHSwing = 0xBF; +const uint8_t kDaikin2FanByte = 28; + +// Ref: +// https://docs.google.com/spreadsheets/d/1f8EGfIbBUo2B-CzUFdrgKQprWakoYNKM80IKZN4KXQE/edit#gid=236366525&range=B25:D32 +const uint8_t kDaikin2SwingHWide = 0xA3; +const uint8_t kDaikin2SwingHLeftMax = 0xA8; +const uint8_t kDaikin2SwingHLeft = 0xA9; +const uint8_t kDaikin2SwingHMiddle = 0xAA; +const uint8_t kDaikin2SwingHRight = 0xAB; +const uint8_t kDaikin2SwingHRightMax = 0xAC; +const uint8_t kDaikin2SwingHAuto = 0xBE; +const uint8_t kDaikin2SwingHSwing = 0xBF; + const uint8_t kDaikin2MinCoolTemp = 18; // Min temp (in C) when in Cool mode. // Another variant of the protocol for the Daikin ARC433B69 remote. @@ -212,15 +262,20 @@ const uint16_t kDaikin216Section2Length = kDaikin216StateLength - kDaikin216Section1Length; const uint8_t kDaikin216BytePower = 13; const uint8_t kDaikin216ByteMode = kDaikin216BytePower; -const uint8_t kDaikin216MaskMode = 0b01110000; +// const uint8_t kDaikin216MaskMode = 0b01110000; const uint8_t kDaikin216ByteTemp = 14; -const uint8_t kDaikin216MaskTemp = 0b01111110; +// const uint8_t kDaikin216MaskTemp = 0b01111110; +const uint8_t kDaikin216TempOffset = 1; +const uint8_t kDaikin216TempSize = 6; + const uint8_t kDaikin216ByteFan = 16; const uint8_t kDaikin216MaskFan = 0b11110000; const uint8_t kDaikin216ByteSwingV = 16; -const uint8_t kDaikin216MaskSwingV = 0b00001111; +// const uint8_t kDaikin216MaskSwingV = 0b00001111; +const uint8_t kDaikin216SwingSize = 4; +const uint8_t kDaikin216SwingOn = 0b1111; +const uint8_t kDaikin216SwingOff = 0b0000; const uint8_t kDaikin216ByteSwingH = 17; -const uint8_t kDaikin216MaskSwingH = kDaikin216MaskSwingV; const uint8_t kDaikin216BytePowerful = 21; // Another variant of the protocol for the Daikin ARC423A5 remote. @@ -237,9 +292,11 @@ const uint16_t kDaikin160Section2Length = kDaikin160StateLength - kDaikin160Section1Length; const uint8_t kDaikin160BytePower = 12; const uint8_t kDaikin160ByteMode = kDaikin160BytePower; -const uint8_t kDaikin160MaskMode = 0b01110000; +// const uint8_t kDaikin160MaskMode = 0b01110000; const uint8_t kDaikin160ByteTemp = 16; -const uint8_t kDaikin160MaskTemp = 0b01111110; +// const uint8_t kDaikin160MaskTemp = 0b01111110; +const uint8_t kDaikin160TempOffset = 1; +const uint8_t kDaikin160TempSize = 6; const uint8_t kDaikin160ByteFan = 17; const uint8_t kDaikin160MaskFan = 0b00001111; const uint8_t kDaikin160ByteSwingV = 13; @@ -270,13 +327,15 @@ const uint8_t kDaikin176MaskMode = 0b01110000; const uint8_t kDaikin176ByteModeButton = 13; const uint8_t kDaikin176ModeButton = 0b00000100; const uint8_t kDaikin176ByteTemp = 17; -const uint8_t kDaikin176MaskTemp = 0b01111110; +// const uint8_t kDaikin176MaskTemp = 0b01111110; +const uint8_t kDaikin176TempOffset = 1; +const uint8_t kDaikin176TempSize = 6; const uint8_t kDaikin176DryFanTemp = 17; // Dry/Fan mode is always 17 Celsius. const uint8_t kDaikin176ByteFan = 18; const uint8_t kDaikin176MaskFan = 0b11110000; const uint8_t kDaikin176FanMax = 3; const uint8_t kDaikin176ByteSwingH = 18; -const uint8_t kDaikin176MaskSwingH = 0b00001111; +// const uint8_t kDaikin176MaskSwingH = 0b00001111; const uint8_t kDaikin176SwingHAuto = 0x5; const uint8_t kDaikin176SwingHOff = 0x6; @@ -295,7 +354,8 @@ const uint16_t kDaikin128FooterMark = kDaikin128HdrMark; const uint16_t kDaikin128Sections = 2; const uint16_t kDaikin128SectionLength = 8; const uint8_t kDaikin128ByteModeFan = 1; -const uint8_t kDaikin128MaskMode = 0b00001111; +// const uint8_t kDaikin128MaskMode = 0b00001111; +const uint8_t kDaikin128ModeSize = 4; const uint8_t kDaikin128Dry = 0b00000001; const uint8_t kDaikin128Cool = 0b00000010; const uint8_t kDaikin128Fan = 0b00000100; @@ -312,18 +372,28 @@ const uint8_t kDaikin128ByteClockMins = 2; const uint8_t kDaikin128ByteClockHours = 3; const uint8_t kDaikin128ByteOnTimer = 4; const uint8_t kDaikin128ByteOffTimer = 5; -const uint8_t kDaikin128BitTimerEnabled = 0b10000000; -const uint8_t kDaikin128BitHalfHour = 0b01000000; -const uint8_t kDaikin128MaskHours = 0b00111111; +const uint8_t kDaikin128BitTimerEnabledOffset = 7; +const uint8_t kDaikin128BitTimerEnabled = 1 << kDaikin128BitTimerEnabledOffset; +const uint8_t kDaikin128TimerOffset = 0; +const uint8_t kDaikin128TimerSize = 7; +const uint8_t kDaikin128HalfHourOffset = 6; +const uint8_t kDaikin128BitHalfHour = 1 << kDaikin128HalfHourOffset; +// const uint8_t kDaikin128MaskHours = 0b00111111; +const uint8_t kDaikin128HoursOffset = 0; +const uint8_t kDaikin128HoursSize = 6; const uint8_t kDaikin128ByteTemp = 6; const uint8_t kDaikin128MinTemp = 16; // C const uint8_t kDaikin128MaxTemp = 30; // C const uint8_t kDaikin128BytePowerSwingSleep = 7; -const uint8_t kDaikin128BitSwing = 0b00000001; -const uint8_t kDaikin128BitSleep = 0b00000010; -const uint8_t kDaikin128BitPowerToggle = 0b00001000; +const uint8_t kDaikin128BitSwingOffset = 0; +const uint8_t kDaikin128BitSwing = 1 << kDaikin128BitSwingOffset; // 0b00000001 +const uint8_t kDaikin128BitSleepOffset = 1; +const uint8_t kDaikin128BitSleep = 1 << kDaikin128BitSleepOffset; // 0b00000010 +const uint8_t kDaikin128BitPowerToggleOffset = 3; +const uint8_t kDaikin128BitPowerToggle = 1 << kDaikin128BitPowerToggleOffset; const uint8_t kDaikin128ByteEconoLight = 9; -const uint8_t kDaikin128BitEcono = 0b00000100; +const uint8_t kDaikin128BitEconoOffset = 2; +const uint8_t kDaikin128BitEcono = 1 << kDaikin128BitEconoOffset; // 0b00000100 const uint8_t kDaikin128BitWall = 0b00001000; const uint8_t kDaikin128BitCeiling = 0b00000001; const uint8_t kDaikin128MaskLight = kDaikin128BitWall | kDaikin128BitCeiling; @@ -339,6 +409,28 @@ const uint16_t kDaikin152OneSpace = 1529; const uint16_t kDaikin152ZeroSpace = kDaikin152BitMark; const uint16_t kDaikin152Gap = 25182; +// Byte[5] +const uint8_t kDaikin152ModeByte = 5; // Mask 0b01110000 +const uint8_t kDaikin152PowerByte = kDaikin152ModeByte; // Mask 0b00000001 +// Byte[6] +const uint8_t kDaikin152TempByte = 6; // Mask 0b11111110 +const uint8_t kDaikin152TempSize = 7; +const uint8_t kDaikin152DryTemp = kDaikin2MinCoolTemp; // Celsius +const uint8_t kDaikin152FanTemp = 0x60; // 96 Celsius +// Byte[8] +const uint8_t kDaikin152FanByte = 8; +const uint8_t kDaikin152SwingVByte = kDaikin152FanByte; +// Byte[13] +const uint8_t kDaikin152QuietByte = 13; // Mask 0b00100000 +const uint8_t kDaikin152PowerfulByte = kDaikin152QuietByte; // Mask 0b00000001 +// Byte[16] +const uint8_t kDaikin152EconoByte = 16; // Mask 0b00000100 +const uint8_t kDaikin152ComfortByte = kDaikin152EconoByte; // Mask 0b00000010 +const uint8_t kDaikin152ComfortOffset = 1; // Mask 0b00000010 +const uint8_t kDaikin152SensorByte = kDaikin152EconoByte; // Mask 0b00001000 +const uint8_t kDaikin152SensorOffset = 3; // Mask 0b00001000 + + // Legacy defines. #define DAIKIN_COOL kDaikinCool #define DAIKIN_HEAT kDaikinHeat @@ -499,7 +591,8 @@ class IRDaikin2 { const uint16_t length = kDaikin2StateLength); static uint8_t convertMode(const stdAc::opmode_t mode); static uint8_t convertFan(const stdAc::fanspeed_t speed); - uint8_t convertSwingV(const stdAc::swingv_t position); + static uint8_t convertSwingV(const stdAc::swingv_t position); + static uint8_t convertSwingH(const stdAc::swingh_t position); static stdAc::swingv_t toCommonSwingV(const uint8_t setting); static stdAc::swingh_t toCommonSwingH(const uint8_t setting); stdAc::state_t toCommon(void); @@ -748,6 +841,34 @@ class IRDaikin152 { void setRaw(const uint8_t new_code[]); static bool validChecksum(uint8_t state[], const uint16_t length = kDaikin152StateLength); + void on(void); + void off(void); + void setPower(const bool on); + bool getPower(void); + void setTemp(const uint8_t temp); + uint8_t getTemp(); + void setFan(const uint8_t fan); + uint8_t getFan(void); + void setMode(const uint8_t mode); + uint8_t getMode(void); + void setSwingV(const bool on); + bool getSwingV(void); + bool getQuiet(void); + void setQuiet(const bool on); + bool getPowerful(void); + void setPowerful(const bool on); + void setSensor(const bool on); + bool getSensor(void); + void setEcono(const bool on); + bool getEcono(void); + void setComfort(const bool on); + bool getComfort(void); + 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); + String toString(void); #ifndef UNIT_TEST private: diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Denon.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Denon.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Denon.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Denon.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Dish.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Dish.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Dish.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Dish.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Electra.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Electra.cpp old mode 100755 new mode 100644 similarity index 79% rename from lib/IRremoteESP8266-2.6.5/src/ir_Electra.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Electra.cpp index 6b945aa3f..e423bfa0a --- a/lib/IRremoteESP8266-2.6.5/src/ir_Electra.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Electra.cpp @@ -2,8 +2,10 @@ #include "ir_Electra.h" #include +#include #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // Electra A/C added by crankyoldgit @@ -29,6 +31,8 @@ using irutils::addLabeledString; using irutils::addModeToString; using irutils::addFanToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_ELECTRA_AC // Send a Electra message @@ -60,8 +64,7 @@ IRElectraAc::IRElectraAc(const uint16_t pin, const bool inverted, } void IRElectraAc::stateReset(void) { - for (uint8_t i = 1; i < kElectraAcStateLength - 2; i++) - remote_state[i] = 0; + for (uint8_t i = 1; i < kElectraAcStateLength - 2; i++) remote_state[i] = 0; remote_state[0] = 0xC3; remote_state[11] = 0x08; // [12] is the checksum. @@ -100,8 +103,7 @@ uint8_t *IRElectraAc::getRaw(void) { } void IRElectraAc::setRaw(const uint8_t new_code[], const uint16_t length) { - for (uint8_t i = 0; i < length && i < kElectraAcStateLength; i++) - remote_state[i] = new_code[i]; + memcpy(remote_state, new_code, std::min(length, kElectraAcStateLength)); } void IRElectraAc::on(void) { this->setPower(true); } @@ -109,14 +111,11 @@ void IRElectraAc::on(void) { this->setPower(true); } void IRElectraAc::off(void) { this->setPower(false); } void IRElectraAc::setPower(const bool on) { - if (on) - remote_state[9] |= kElectraAcPowerMask; - else - remote_state[9] &= ~kElectraAcPowerMask; + setBit(&remote_state[9], kElectraAcPowerOffset, on); } bool IRElectraAc::getPower(void) { - return remote_state[9] & kElectraAcPowerMask; + return GETBIT8(remote_state[9], kElectraAcPowerOffset); } void IRElectraAc::setMode(const uint8_t mode) { @@ -126,8 +125,7 @@ void IRElectraAc::setMode(const uint8_t mode) { case kElectraAcCool: case kElectraAcHeat: case kElectraAcFan: - remote_state[6] &= ~kElectraAcModeMask; - remote_state[6] |= (mode << 5); + setBits(&remote_state[6], kElectraAcModeOffset, kModeBitsSize, mode); break; default: // If we get an unexpected mode, default to AUTO. @@ -136,22 +134,17 @@ void IRElectraAc::setMode(const uint8_t mode) { } uint8_t IRElectraAc::getMode(void) { - return (remote_state[6] & kElectraAcModeMask) >> 5; + return GETBITS8(remote_state[6], kElectraAcModeOffset, kModeBitsSize); } // Convert a standard A/C mode into its native mode. uint8_t IRElectraAc::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kElectraAcCool; - case stdAc::opmode_t::kHeat: - return kElectraAcHeat; - case stdAc::opmode_t::kDry: - return kElectraAcDry; - case stdAc::opmode_t::kFan: - return kElectraAcFan; - default: - return kElectraAcAuto; + case stdAc::opmode_t::kCool: return kElectraAcCool; + case stdAc::opmode_t::kHeat: return kElectraAcHeat; + case stdAc::opmode_t::kDry: return kElectraAcDry; + case stdAc::opmode_t::kFan: return kElectraAcFan; + default: return kElectraAcAuto; } } @@ -160,23 +153,23 @@ stdAc::opmode_t IRElectraAc::toCommonMode(const uint8_t mode) { switch (mode) { case kElectraAcCool: return stdAc::opmode_t::kCool; case kElectraAcHeat: return stdAc::opmode_t::kHeat; - case kElectraAcDry: return stdAc::opmode_t::kDry; - case kElectraAcFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kElectraAcDry: return stdAc::opmode_t::kDry; + case kElectraAcFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } // Set the temp. in deg C void IRElectraAc::setTemp(const uint8_t temp) { uint8_t newtemp = std::max(kElectraAcMinTemp, temp); - newtemp = std::min(kElectraAcMaxTemp, newtemp); - remote_state[1] = (remote_state[1] & ~kElectraAcTempMask) | - ((newtemp - kElectraAcOffsetTemp) << 3); + newtemp = std::min(kElectraAcMaxTemp, newtemp) - kElectraAcTempDelta; + setBits(&remote_state[1], kElectraAcTempOffset, kElectraAcTempSize, newtemp); } // Return the set temp. in deg C uint8_t IRElectraAc::getTemp(void) { - return ((remote_state[1] & kElectraAcTempMask) >> 3) + kElectraAcOffsetTemp; + return GETBITS8(remote_state[1], kElectraAcTempOffset, kElectraAcTempSize) + + kElectraAcTempDelta; } // Set the speed of the fan, 0-3, 0 is auto, 1-3 is the speed @@ -186,8 +179,7 @@ void IRElectraAc::setFan(const uint8_t speed) { case kElectraAcFanHigh: case kElectraAcFanMed: case kElectraAcFanLow: - remote_state[4] &= ~kElectraAcFanMask; - remote_state[4] |= (speed << 5); + setBits(&remote_state[4], kElectraAcFanOffset, kElectraAcFanSize, speed); break; default: // If we get an unexpected speed, default to Auto. @@ -196,22 +188,18 @@ void IRElectraAc::setFan(const uint8_t speed) { } uint8_t IRElectraAc::getFan(void) { - return (remote_state[4] & kElectraAcFanMask) >> 5; + return GETBITS8(remote_state[4], kElectraAcFanOffset, kElectraAcFanSize); } // Convert a standard A/C Fan speed into its native fan speed. uint8_t IRElectraAc::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kElectraAcFanLow; - case stdAc::fanspeed_t::kMedium: - return kElectraAcFanMed; + case stdAc::fanspeed_t::kLow: return kElectraAcFanLow; + case stdAc::fanspeed_t::kMedium: return kElectraAcFanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kElectraAcFanHigh; - default: - return kElectraAcFanAuto; + case stdAc::fanspeed_t::kMax: return kElectraAcFanHigh; + default: return kElectraAcFanAuto; } } @@ -226,25 +214,23 @@ stdAc::fanspeed_t IRElectraAc::toCommonFanSpeed(const uint8_t speed) { } void IRElectraAc::setSwingV(const bool on) { - if (on) - remote_state[1] &= ~kElectraAcSwingVMask; - else - remote_state[1] |= kElectraAcSwingVMask; + setBits(&remote_state[1], kElectraAcSwingVOffset, kElectraAcSwingSize, + on ? kElectraAcSwingOn : kElectraAcSwingOff); } bool IRElectraAc::getSwingV(void) { - return !(remote_state[1] & kElectraAcSwingVMask); + return !GETBITS8(remote_state[1], kElectraAcSwingVOffset, + kElectraAcSwingSize); } void IRElectraAc::setSwingH(const bool on) { - if (on) - remote_state[2] &= ~kElectraAcSwingHMask; - else - remote_state[2] |= kElectraAcSwingHMask; + setBits(&remote_state[2], kElectraAcSwingHOffset, kElectraAcSwingSize, + on ? kElectraAcSwingOn : kElectraAcSwingOff); } bool IRElectraAc::getSwingH(void) { - return !(remote_state[2] & kElectraAcSwingHMask); + return !GETBITS8(remote_state[2], kElectraAcSwingHOffset, + kElectraAcSwingSize); } // Convert the A/C state to it's common equivalent. @@ -278,15 +264,15 @@ stdAc::state_t IRElectraAc::toCommon(void) { String IRElectraAc::toString(void) { String result = ""; result.reserve(80); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kElectraAcAuto, kElectraAcCool, kElectraAcHeat, kElectraAcDry, kElectraAcFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kElectraAcFanHigh, kElectraAcFanLow, kElectraAcFanAuto, kElectraAcFanAuto, kElectraAcFanMed); - result += addBoolToString(getSwingV(), F("Swing(V)")); - result += addBoolToString(getSwingH(), F("Swing(H)")); + result += addBoolToString(getSwingV(), kSwingVStr); + result += addBoolToString(getSwingH(), kSwingHStr); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Electra.h b/lib/IRremoteESP8266-2.7.0/src/ir_Electra.h old mode 100755 new mode 100644 similarity index 78% rename from lib/IRremoteESP8266-2.6.5/src/ir_Electra.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Electra.h index c9c6f018e..ef28b44cf --- a/lib/IRremoteESP8266-2.6.5/src/ir_Electra.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Electra.h @@ -25,28 +25,39 @@ // Constants // state[1] -const uint8_t kElectraAcTempMask = 0b11111000; +// Temp 0b11111000 +const uint8_t kElectraAcTempOffset = 3; +const uint8_t kElectraAcTempSize = 5; // Bits const uint8_t kElectraAcMinTemp = 16; // 16C const uint8_t kElectraAcMaxTemp = 32; // 32C -const uint8_t kElectraAcOffsetTemp = 8; -const uint8_t kElectraAcSwingVMask = 0b00000111; +const uint8_t kElectraAcTempDelta = 8; +const uint8_t kElectraAcSwingSize = 3; // Bits +const uint8_t kElectraAcSwingOn = 0b000; +const uint8_t kElectraAcSwingOff = 0b111; +// SwingVMask = 0b00000111; +const uint8_t kElectraAcSwingVOffset = 0; // state[2] -const uint8_t kElectraAcSwingHMask = 0b11100000; +// SwingHMask = 0b11100000; +const uint8_t kElectraAcSwingHOffset = 5; // state[4] -const uint8_t kElectraAcFanMask = 0b11100000; +// FanMask = 0b11100000; +const uint8_t kElectraAcFanOffset = 5; +const uint8_t kElectraAcFanSize = 3; // Bits + const uint8_t kElectraAcFanAuto = 0b101; const uint8_t kElectraAcFanLow = 0b011; const uint8_t kElectraAcFanMed = 0b010; const uint8_t kElectraAcFanHigh = 0b001; // state[6] -const uint8_t kElectraAcModeMask = 0b11100000; +// Mode 0b11100000 +const uint8_t kElectraAcModeOffset = 5; const uint8_t kElectraAcAuto = 0b000; const uint8_t kElectraAcCool = 0b001; const uint8_t kElectraAcDry = 0b010; const uint8_t kElectraAcHeat = 0b100; const uint8_t kElectraAcFan = 0b110; // state[9] -const uint8_t kElectraAcPowerMask = 0b00100000; +const uint8_t kElectraAcPowerOffset = 5; // Classes diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Fujitsu.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Fujitsu.cpp old mode 100755 new mode 100644 similarity index 76% rename from lib/IRremoteESP8266-2.6.5/src/ir_Fujitsu.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Fujitsu.cpp index fa6a0ce8c..fe8c2bfed --- a/lib/IRremoteESP8266-2.6.5/src/ir_Fujitsu.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Fujitsu.cpp @@ -6,6 +6,7 @@ #include #endif #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // Fujitsu A/C support added by Jonny Graham & David Conran @@ -31,8 +32,11 @@ using irutils::addBoolToString; using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; +using irutils::addModelToString; using irutils::addFanToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_FUJITSU_AC // Send a Fujitsu A/C message. @@ -72,13 +76,14 @@ IRFujitsuAC::IRFujitsuAC(const uint16_t pin, void IRFujitsuAC::setModel(const fujitsu_ac_remote_model_t model) { _model = model; switch (model) { - case ARDB1: - case ARJW2: + case fujitsu_ac_remote_model_t::ARDB1: + case fujitsu_ac_remote_model_t::ARJW2: _state_length = kFujitsuAcStateLength - 1; _state_length_short = kFujitsuAcStateLengthShort - 1; break; - case ARRAH2E: - case ARREB1E: + case fujitsu_ac_remote_model_t::ARRY4: + case fujitsu_ac_remote_model_t::ARRAH2E: + case fujitsu_ac_remote_model_t::ARREB1E: default: _state_length = kFujitsuAcStateLength; _state_length_short = kFujitsuAcStateLengthShort; @@ -94,6 +99,8 @@ void IRFujitsuAC::stateReset(void) { _mode = kFujitsuAcModeCool; _swingMode = kFujitsuAcSwingBoth; _cmd = kFujitsuAcCmdTurnOn; + _filter = false; + _clean = false; this->buildState(); } @@ -127,12 +134,13 @@ void IRFujitsuAC::buildState(void) { break; default: switch (_model) { - case ARRAH2E: - case ARREB1E: + case fujitsu_ac_remote_model_t::ARRY4: + case fujitsu_ac_remote_model_t::ARRAH2E: + case fujitsu_ac_remote_model_t::ARREB1E: remote_state[5] = 0xFE; break; - case ARDB1: - case ARJW2: + case fujitsu_ac_remote_model_t::ARDB1: + case fujitsu_ac_remote_model_t::ARJW2: remote_state[5] = 0xFC; break; } @@ -151,21 +159,30 @@ void IRFujitsuAC::buildState(void) { remote_state[11] = 0; // timerOff values remote_state[12] = 0; // timerOff/On values remote_state[13] = 0; // timerOn values - remote_state[14] = 0; + switch (_model) { + case fujitsu_ac_remote_model_t::ARRY4: + remote_state[14] = _filter << 3; + remote_state[9] |= (_clean << 3); + break; + default: + remote_state[14] = 0; + } uint8_t checksum = 0; uint8_t checksum_complement = 0; switch (_model) { - case ARDB1: - case ARJW2: + case fujitsu_ac_remote_model_t::ARDB1: + case fujitsu_ac_remote_model_t::ARJW2: checksum = sumBytes(remote_state, _state_length - 1); checksum_complement = 0x9B; break; - case ARREB1E: - remote_state[14] |= (_outsideQuiet << 7); + case fujitsu_ac_remote_model_t::ARREB1E: + setBit(&remote_state[14], kFujitsuAcOutsideQuietOffset, _outsideQuiet); // FALL THRU - case ARRAH2E: - remote_state[14] |= 0x20; - remote_state[10] |= _swingMode << 4; + case fujitsu_ac_remote_model_t::ARRAH2E: + case fujitsu_ac_remote_model_t::ARRY4: + setBit(&remote_state[14], 5); // |= 0b00100000 + setBits(&remote_state[10], kHighNibble, kFujitsuAcSwingSize, + _swingMode); // FALL THRU default: checksum = sumBytes(remote_state + _state_length_short, @@ -175,8 +192,9 @@ void IRFujitsuAC::buildState(void) { remote_state[_state_length - 1] = checksum_complement - checksum; } else { // short codes switch (_model) { - case ARRAH2E: - case ARREB1E: + case fujitsu_ac_remote_model_t::ARRY4: + case fujitsu_ac_remote_model_t::ARRAH2E: + case fujitsu_ac_remote_model_t::ARREB1E: // The last byte is the inverse of penultimate byte remote_state[_state_length_short - 1] = ~remote_state[_state_length_short - 2]; @@ -192,8 +210,12 @@ void IRFujitsuAC::buildState(void) { uint8_t IRFujitsuAC::getStateLength(void) { this->buildState(); // Force an update of the internal state. - if (((_model == ARRAH2E || _model == ARREB1E) && remote_state[5] != 0xFE) || - ((_model == ARDB1 || _model == ARJW2) && remote_state[5] != 0xFC)) + if (((_model == fujitsu_ac_remote_model_t::ARRAH2E || + _model == fujitsu_ac_remote_model_t::ARREB1E || + _model == fujitsu_ac_remote_model_t::ARRY4) && + remote_state[5] != 0xFE) || + ((_model == fujitsu_ac_remote_model_t::ARDB1 || + _model == fujitsu_ac_remote_model_t::ARJW2) && remote_state[5] != 0xFC)) return _state_length_short; else return _state_length; @@ -209,9 +231,10 @@ void IRFujitsuAC::buildFromState(const uint16_t length) { switch (length) { case kFujitsuAcStateLength - 1: case kFujitsuAcStateLengthShort - 1: - this->setModel(ARDB1); + this->setModel(fujitsu_ac_remote_model_t::ARDB1); // ARJW2 has horizontal swing. - if (this->getSwing(true) > kFujitsuAcSwingVert) this->setModel(ARJW2); + if (this->getSwing(true) > kFujitsuAcSwingVert) + this->setModel(fujitsu_ac_remote_model_t::ARJW2); break; default: switch (this->getCmd(true)) { @@ -226,21 +249,28 @@ void IRFujitsuAC::buildFromState(const uint16_t length) { switch (remote_state[6]) { case 8: if (this->getModel() != fujitsu_ac_remote_model_t::ARJW2) - this->setModel(ARDB1); + this->setModel(fujitsu_ac_remote_model_t::ARDB1); break; case 9: if (this->getModel() != fujitsu_ac_remote_model_t::ARREB1E) - this->setModel(ARRAH2E); + this->setModel(fujitsu_ac_remote_model_t::ARRAH2E); break; } setTemp((remote_state[8] >> 4) + kFujitsuAcMinTemp); - if (remote_state[8] & 0x1) + if (GETBIT8(remote_state[8], 0)) setCmd(kFujitsuAcCmdTurnOn); else setCmd(kFujitsuAcCmdStayOn); - setMode(remote_state[9] & 0b111); - setFanSpeed(remote_state[10] & 0b111); - setSwing(remote_state[10] >> 4); + setMode(GETBITS8(remote_state[9], kLowNibble, kModeBitsSize)); + setFanSpeed(GETBITS8(remote_state[10], kLowNibble, kFujitsuAcFanSize)); + setSwing(GETBITS8(remote_state[10], kHighNibble, kFujitsuAcSwingSize)); + setClean(getClean(true)); + setFilter(getFilter(true)); + // Currently the only way we know how to tell ARRAH2E & ARRY4 apart is if + // either the raw Filter or Clean setting is on. + if (getModel() == fujitsu_ac_remote_model_t::ARRAH2E && (getFilter(true) || + getClean(true))) + setModel(fujitsu_ac_remote_model_t::ARRY4); switch (remote_state[5]) { case kFujitsuAcCmdTurnOff: case kFujitsuAcCmdStepHoriz: @@ -298,9 +328,9 @@ void IRFujitsuAC::setCmd(const uint8_t cmd) { case kFujitsuAcCmdStepHoriz: case kFujitsuAcCmdToggleSwingHoriz: switch (_model) { - // Only these remotes have step horizontal. - case ARRAH2E: - case ARJW2: + // Only these remotes have horizontal. + case fujitsu_ac_remote_model_t::ARRAH2E: + case fujitsu_ac_remote_model_t::ARJW2: _cmd = cmd; break; default: @@ -358,7 +388,7 @@ void IRFujitsuAC::setOutsideQuiet(const bool on) { // A boolean for if it is set or not. bool IRFujitsuAC::getOutsideQuiet(const bool raw) { if (_state_length == kFujitsuAcStateLength && raw) { - _outsideQuiet = remote_state[14] & 0b10000000; + _outsideQuiet = GETBIT8(remote_state[14], kFujitsuAcOutsideQuietOffset); // Only ARREB1E seems to have this mode. if (_outsideQuiet) this->setModel(fujitsu_ac_remote_model_t::ARREB1E); } @@ -400,14 +430,15 @@ void IRFujitsuAC::setSwing(const uint8_t swingMode) { _swingMode = swingMode; switch (_model) { // No Horizontal support. - case ARDB1: - case ARREB1E: + case fujitsu_ac_remote_model_t::ARDB1: + case fujitsu_ac_remote_model_t::ARREB1E: + case fujitsu_ac_remote_model_t::ARRY4: // Set the mode to max if out of range if (swingMode > kFujitsuAcSwingVert) _swingMode = kFujitsuAcSwingVert; break; // Has Horizontal support. - case ARRAH2E: - case ARJW2: + case fujitsu_ac_remote_model_t::ARRAH2E: + case fujitsu_ac_remote_model_t::ARJW2: default: // Set the mode to max if out of range if (swingMode > kFujitsuAcSwingBoth) _swingMode = kFujitsuAcSwingBoth; @@ -421,22 +452,55 @@ void IRFujitsuAC::setSwing(const uint8_t swingMode) { // Returns: // A uint8_t containing the contents of the swing state. uint8_t IRFujitsuAC::getSwing(const bool raw) { - if (raw) _swingMode = remote_state[10] >> 4; + if (raw) _swingMode = GETBITS8(remote_state[10], kHighNibble, + kFujitsuAcSwingSize); return _swingMode; } +void IRFujitsuAC::setClean(const bool on) { + _clean = on; + this->setCmd(kFujitsuAcCmdStayOn); // No special command involved. +} + +bool IRFujitsuAC::getClean(const bool raw) { + if (raw) { + return GETBIT8(remote_state[9], kFujitsuAcCleanOffset); + } else { + switch (getModel()) { + case fujitsu_ac_remote_model_t::ARRY4: return _clean; + default: return false; + } + } +} + +void IRFujitsuAC::setFilter(const bool on) { + _filter = on; + this->setCmd(kFujitsuAcCmdStayOn); // No special command involved. +} + +bool IRFujitsuAC::getFilter(const bool raw) { + if (raw) { + return GETBIT8(remote_state[14], kFujitsuAcFilterOffset); + } else { + switch (getModel()) { + case fujitsu_ac_remote_model_t::ARRY4: return _filter; + default: return false; + } + } +} + bool IRFujitsuAC::validChecksum(uint8_t state[], const uint16_t length) { uint8_t sum = 0; uint8_t sum_complement = 0; uint8_t checksum = state[length - 1]; switch (length) { - case kFujitsuAcStateLengthShort: // ARRAH2E & ARREB1E + case kFujitsuAcStateLengthShort: // ARRAH2E, ARREB1E, & ARRY4 return state[length - 1] == (uint8_t)~state[length - 2]; case kFujitsuAcStateLength - 1: // ARDB1 & ARJW2 sum = sumBytes(state, length - 1); sum_complement = 0x9B; break; - case kFujitsuAcStateLength: // ARRAH2E & ARREB1E + case kFujitsuAcStateLength: // ARRAH2E, ARRY4, & ARREB1E sum = sumBytes(state + kFujitsuAcStateLengthShort, length - 1 - kFujitsuAcStateLengthShort); break; @@ -449,33 +513,23 @@ bool IRFujitsuAC::validChecksum(uint8_t state[], const uint16_t length) { // Convert a standard A/C mode into its native mode. uint8_t IRFujitsuAC::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kFujitsuAcModeCool; - case stdAc::opmode_t::kHeat: - return kFujitsuAcModeHeat; - case stdAc::opmode_t::kDry: - return kFujitsuAcModeDry; - case stdAc::opmode_t::kFan: - return kFujitsuAcModeFan; - default: - return kFujitsuAcModeAuto; + case stdAc::opmode_t::kCool: return kFujitsuAcModeCool; + case stdAc::opmode_t::kHeat: return kFujitsuAcModeHeat; + case stdAc::opmode_t::kDry: return kFujitsuAcModeDry; + case stdAc::opmode_t::kFan: return kFujitsuAcModeFan; + default: return kFujitsuAcModeAuto; } } // Convert a standard A/C Fan speed into its native fan speed. uint8_t IRFujitsuAC::convertFan(stdAc::fanspeed_t speed) { switch (speed) { - case stdAc::fanspeed_t::kMin: - return kFujitsuAcFanQuiet; - case stdAc::fanspeed_t::kLow: - return kFujitsuAcFanLow; - case stdAc::fanspeed_t::kMedium: - return kFujitsuAcFanMed; + case stdAc::fanspeed_t::kMin: return kFujitsuAcFanQuiet; + case stdAc::fanspeed_t::kLow: return kFujitsuAcFanLow; + case stdAc::fanspeed_t::kMedium: return kFujitsuAcFanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kFujitsuAcFanHigh; - default: - return kFujitsuAcFanAuto; + case stdAc::fanspeed_t::kMax: return kFujitsuAcFanHigh; + default: return kFujitsuAcFanAuto; } } @@ -484,20 +538,20 @@ stdAc::opmode_t IRFujitsuAC::toCommonMode(const uint8_t mode) { switch (mode) { case kFujitsuAcModeCool: return stdAc::opmode_t::kCool; case kFujitsuAcModeHeat: return stdAc::opmode_t::kHeat; - case kFujitsuAcModeDry: return stdAc::opmode_t::kDry; - case kFujitsuAcModeFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kFujitsuAcModeDry: return stdAc::opmode_t::kDry; + case kFujitsuAcModeFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } // Convert a native fan speed to it's common equivalent. stdAc::fanspeed_t IRFujitsuAC::toCommonFanSpeed(const uint8_t speed) { switch (speed) { - case kFujitsuAcFanHigh: return stdAc::fanspeed_t::kMax; - case kFujitsuAcFanMed: return stdAc::fanspeed_t::kMedium; - case kFujitsuAcFanLow: return stdAc::fanspeed_t::kLow; + case kFujitsuAcFanHigh: return stdAc::fanspeed_t::kMax; + case kFujitsuAcFanMed: return stdAc::fanspeed_t::kMedium; + case kFujitsuAcFanLow: return stdAc::fanspeed_t::kLow; case kFujitsuAcFanQuiet: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + default: return stdAc::fanspeed_t::kAuto; } } @@ -515,6 +569,9 @@ stdAc::state_t IRFujitsuAC::toCommon(void) { switch (result.model) { case fujitsu_ac_remote_model_t::ARREB1E: case fujitsu_ac_remote_model_t::ARRAH2E: + case fujitsu_ac_remote_model_t::ARRY4: + result.clean = _clean; + result.filter = _filter; result.swingv = (swing & kFujitsuAcSwingVert) ? stdAc::swingv_t::kAuto : stdAc::swingv_t::kOff; result.swingh = (swing & kFujitsuAcSwingHoriz) ? stdAc::swingh_t::kAuto : @@ -545,15 +602,8 @@ String IRFujitsuAC::toString(void) { String result = ""; result.reserve(100); // Reserve some heap for the string to reduce fragging. fujitsu_ac_remote_model_t model = this->getModel(); - result += addIntToString(model, F("Model"), false); - switch (model) { - case fujitsu_ac_remote_model_t::ARRAH2E: result += F(" (ARRAH2E)"); break; - case fujitsu_ac_remote_model_t::ARDB1: result += F(" (ARDB1)"); break; - case fujitsu_ac_remote_model_t::ARREB1E: result += F(" (ARREB1E)"); break; - case fujitsu_ac_remote_model_t::ARJW2: result += F(" (ARJW2)"); break; - default: result += F(" (UNKNOWN)"); - } - result += addBoolToString(getPower(), F("Power")); + result += addModelToString(decode_type_t::FUJITSU_AC, model, false); + result += addBoolToString(getPower(), kPowerStr); result += addModeToString(getMode(), kFujitsuAcModeAuto, kFujitsuAcModeCool, kFujitsuAcModeHeat, kFujitsuAcModeDry, kFujitsuAcModeFan); @@ -562,54 +612,58 @@ String IRFujitsuAC::toString(void) { kFujitsuAcFanAuto, kFujitsuAcFanQuiet, kFujitsuAcFanMed); switch (model) { - // These models have no internal swing state. + // These models have no internal swing, clean. or filter state. case fujitsu_ac_remote_model_t::ARDB1: case fujitsu_ac_remote_model_t::ARJW2: break; default: // Assume everything else does. - result += F(", Swing: "); + result += addBoolToString(getClean(), kCleanStr); + result += addBoolToString(getFilter(), kFilterStr); + result += addIntToString(this->getSwing(), kSwingStr); + result += kSpaceLBraceStr; switch (this->getSwing()) { case kFujitsuAcSwingOff: - result += F("Off"); + result += kOffStr; break; case kFujitsuAcSwingVert: - result += F("Vert"); + result += kSwingVStr; break; case kFujitsuAcSwingHoriz: - result += F("Horiz"); + result += kSwingHStr; break; case kFujitsuAcSwingBoth: - result += F("Vert + Horiz"); + result += kSwingVStr + '+' + kSwingHStr; break; default: - result += F("UNKNOWN"); + result += kUnknownStr; } + result += ')'; } - result += F(", Command: "); + result += kCommaSpaceStr + kCommandStr + kColonSpaceStr; switch (this->getCmd()) { case kFujitsuAcCmdStepHoriz: - result += F("Step vane horizontally"); + result += kStepStr + ' ' + kSwingHStr; break; case kFujitsuAcCmdStepVert: - result += F("Step vane vertically"); + result += kStepStr + ' ' + kSwingVStr; break; case kFujitsuAcCmdToggleSwingHoriz: - result += F("Toggle horizontal swing"); + result += kToggleStr + ' ' + kSwingHStr; break; case kFujitsuAcCmdToggleSwingVert: - result += F("Toggle vertically swing"); + result += kToggleStr + ' ' + kSwingVStr; break; case kFujitsuAcCmdEcono: - result += F("Economy"); + result += kEconoStr; break; case kFujitsuAcCmdPowerful: - result += F("Powerful"); + result += kPowerfulStr; break; default: - result += F("N/A"); + result += kNAStr; } if (this->getModel() == fujitsu_ac_remote_model_t::ARREB1E) - result += addBoolToString(getOutsideQuiet(), F("Outside Quiet")); + result += addBoolToString(getOutsideQuiet(), kOutsideStr + ' ' + kQuietStr); return result; } @@ -642,10 +696,8 @@ bool IRrecv::decodeFujitsuAC(decode_results* results, uint16_t nbits, case kFujitsuAcBits: case kFujitsuAcBits - 8: case kFujitsuAcMinBits: - case kFujitsuAcMinBits + 8: - break; - default: - return false; // Must be called with the correct nr. of bits. + case kFujitsuAcMinBits + 8: break; + default: return false; // Must be called with the correct nr. of bits. } } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Fujitsu.h b/lib/IRremoteESP8266-2.7.0/src/ir_Fujitsu.h old mode 100755 new mode 100644 similarity index 88% rename from lib/IRremoteESP8266-2.6.5/src/ir_Fujitsu.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Fujitsu.h index e953f9058..eae0edb8f --- a/lib/IRremoteESP8266-2.6.5/src/ir_Fujitsu.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Fujitsu.h @@ -9,7 +9,13 @@ // Brand: Fujitsu, Model: AR-REB1E remote // Brand: Fujitsu, Model: ASYG7LMCA A/C // Brand: Fujitsu, Model: AR-RAE1E remote +// Brand: Fujitsu, Model: AGTV14LAC A/C +// Brand: Fujitsu, Model: AR-RAC1E remote +// Brand: Fujitsu, Model: ASTB09LBC A/C +// Brand: Fujitsu, Model: AR-RY4 remote // Brand: Fujitsu General, Model: AR-JW2 remote +// Brand: Fujitsu, Model: AR-DL10 remote +// Brand: Fujitsu, Model: ASU30C1 A/C #ifndef IR_FUJITSU_H_ #define IR_FUJITSU_H_ @@ -50,15 +56,21 @@ const uint8_t kFujitsuAcFanHigh = 0x01; const uint8_t kFujitsuAcFanMed = 0x02; const uint8_t kFujitsuAcFanLow = 0x03; const uint8_t kFujitsuAcFanQuiet = 0x04; +const uint8_t kFujitsuAcFanSize = 3; // Bits const uint8_t kFujitsuAcMinTemp = 16; // 16C const uint8_t kFujitsuAcMaxTemp = 30; // 30C +const uint8_t kFujitsuAcSwingSize = 2; const uint8_t kFujitsuAcSwingOff = 0x00; const uint8_t kFujitsuAcSwingVert = 0x01; const uint8_t kFujitsuAcSwingHoriz = 0x02; const uint8_t kFujitsuAcSwingBoth = 0x03; +const uint8_t kFujitsuAcOutsideQuietOffset = 7; +const uint8_t kFujitsuAcCleanOffset = 3; +const uint8_t kFujitsuAcFilterOffset = 3; + // Legacy defines. #define FUJITSU_AC_MODE_AUTO kFujitsuAcModeAuto #define FUJITSU_AC_MODE_COOL kFujitsuAcModeCool @@ -82,12 +94,6 @@ const uint8_t kFujitsuAcSwingBoth = 0x03; #define FUJITSU_AC_SWING_HORIZ kFujitsuAcSwingHoriz #define FUJITSU_AC_SWING_BOTH kFujitsuAcSwingBoth -enum fujitsu_ac_remote_model_t { - ARRAH2E = 1, // (1) AR-RAH2E, AR-RAE1E (Default) - ARDB1, // (2) AR-DB1 - ARREB1E, // (3) AR-REB1E - ARJW2, // (4) AR-JW2 (Same as ARDB1 but with horiz control) -}; class IRFujitsuAC { public: @@ -126,6 +132,10 @@ class IRFujitsuAC { void off(void); void on(void); bool getPower(void); + void setClean(const bool on); + bool getClean(const bool raw = false); + void setFilter(const bool on); + bool getFilter(const bool raw = false); void setOutsideQuiet(const bool on); bool getOutsideQuiet(const bool raw = false); @@ -153,6 +163,8 @@ class IRFujitsuAC { uint8_t _state_length; uint8_t _state_length_short; bool _outsideQuiet; + bool _clean; + bool _filter; void buildState(void); void buildFromState(const uint16_t length); }; diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_GICable.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_GICable.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_GICable.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_GICable.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_GlobalCache.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_GlobalCache.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_GlobalCache.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_GlobalCache.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Goodweather.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Goodweather.cpp old mode 100755 new mode 100644 similarity index 72% rename from lib/IRremoteESP8266-2.6.5/src/ir_Goodweather.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Goodweather.cpp index d8ac45f1b..4cf2e55cd --- a/lib/IRremoteESP8266-2.6.5/src/ir_Goodweather.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Goodweather.cpp @@ -14,6 +14,7 @@ #include "IRrecv.h" #include "IRremoteESP8266.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" using irutils::addBoolToString; @@ -22,6 +23,8 @@ using irutils::addLabeledString; using irutils::addModeToString; using irutils::addFanToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_GOODWEATHER // Send a Goodweather message. @@ -68,8 +71,7 @@ IRGoodweatherAc::IRGoodweatherAc(const uint16_t pin, const bool inverted, const bool use_modulation) : _irsend(pin, inverted, use_modulation) { stateReset(); } -void IRGoodweatherAc::stateReset(void) { -} +void IRGoodweatherAc::stateReset(void) { remote = kGoodweatherStateInit; } void IRGoodweatherAc::begin(void) { _irsend.begin(); } @@ -89,13 +91,12 @@ void IRGoodweatherAc::off(void) { this->setPower(false); } void IRGoodweatherAc::setPower(const bool on) { this->setCommand(kGoodweatherCmdPower); - if (on) - remote |= kGoodweatherPowerMask; - else - remote &= ~kGoodweatherPowerMask; + setBit(&remote, kGoodweatherBitPower, on); } -bool IRGoodweatherAc::getPower(void) { return remote & kGoodweatherPowerMask; } +bool IRGoodweatherAc::getPower(void) { + return GETBIT64(remote, kGoodweatherBitPower); +} // Set the temp. in deg C void IRGoodweatherAc::setTemp(const uint8_t temp) { @@ -103,13 +104,13 @@ void IRGoodweatherAc::setTemp(const uint8_t temp) { new_temp = std::min(kGoodweatherTempMax, new_temp); if (new_temp > this->getTemp()) this->setCommand(kGoodweatherCmdUpTemp); if (new_temp < this->getTemp()) this->setCommand(kGoodweatherCmdDownTemp); - remote &= ~kGoodweatherTempMask; - remote |= (uint64_t)(new_temp - kGoodweatherTempMin) << kGoodweatherBitTemp; + setBits(&remote, kGoodweatherBitTemp, kGoodweatherTempSize, + new_temp - kGoodweatherTempMin); } // Return the set temp. in deg C uint8_t IRGoodweatherAc::getTemp(void) { - return ((remote & kGoodweatherTempMask) >> kGoodweatherBitTemp) + + return GETBITS64(remote, kGoodweatherBitTemp, kGoodweatherTempSize) + kGoodweatherTempMin; } @@ -121,8 +122,7 @@ void IRGoodweatherAc::setFan(const uint8_t speed) { case kGoodweatherFanMed: case kGoodweatherFanHigh: this->setCommand(kGoodweatherCmdFan); - remote &= ~kGoodweatherFanMask; - remote |= ((uint64_t)speed << kGoodweatherBitFan); + setBits(&remote, kGoodweatherBitFan, kGoodweatherFanSize, speed); break; default: this->setFan(kGoodweatherFanAuto); @@ -130,7 +130,7 @@ void IRGoodweatherAc::setFan(const uint8_t speed) { } uint8_t IRGoodweatherAc::getFan() { - return (remote & kGoodweatherFanMask) >> kGoodweatherBitFan; + return GETBITS64(remote, kGoodweatherBitFan, kGoodweatherFanSize); } void IRGoodweatherAc::setMode(const uint8_t mode) { @@ -141,8 +141,7 @@ void IRGoodweatherAc::setMode(const uint8_t mode) { case kGoodweatherFan: case kGoodweatherHeat: this->setCommand(kGoodweatherCmdMode); - remote &= ~kGoodweatherModeMask; - remote |= (uint64_t)mode << kGoodweatherBitMode; + setBits(&remote, kGoodweatherBitMode, kModeBitsSize, mode); break; default: // If we get an unexpected mode, default to AUTO. @@ -151,38 +150,35 @@ void IRGoodweatherAc::setMode(const uint8_t mode) { } uint8_t IRGoodweatherAc::getMode() { - return (remote & kGoodweatherModeMask) >> kGoodweatherBitMode; + return GETBITS64(remote, kGoodweatherBitMode, kModeBitsSize); } void IRGoodweatherAc::setLight(const bool toggle) { this->setCommand(kGoodweatherCmdLight); - if (toggle) - remote |= kGoodweatherLightMask; - else - remote &= ~kGoodweatherLightMask; + setBit(&remote, kGoodweatherBitLight, toggle); } -bool IRGoodweatherAc::getLight() { return remote & kGoodweatherLightMask; } +bool IRGoodweatherAc::getLight() { + return GETBIT64(remote, kGoodweatherBitLight); +} void IRGoodweatherAc::setSleep(const bool toggle) { this->setCommand(kGoodweatherCmdSleep); - if (toggle) - remote |= kGoodweatherSleepMask; - else - remote &= ~kGoodweatherSleepMask; + setBit(&remote, kGoodweatherBitSleep, toggle); } -bool IRGoodweatherAc::getSleep() { return remote & kGoodweatherSleepMask; } +bool IRGoodweatherAc::getSleep() { + return GETBIT64(remote, kGoodweatherBitSleep); +} void IRGoodweatherAc::setTurbo(const bool toggle) { this->setCommand(kGoodweatherCmdTurbo); - if (toggle) - remote |= kGoodweatherTurboMask; - else - remote &= ~kGoodweatherTurboMask; + setBit(&remote, kGoodweatherBitTurbo, toggle); } -bool IRGoodweatherAc::getTurbo() { return remote & kGoodweatherTurboMask; } +bool IRGoodweatherAc::getTurbo() { + return GETBIT64(remote, kGoodweatherBitTurbo); +} void IRGoodweatherAc::setSwing(const uint8_t speed) { switch (speed) { @@ -190,8 +186,7 @@ void IRGoodweatherAc::setSwing(const uint8_t speed) { case kGoodweatherSwingSlow: case kGoodweatherSwingFast: this->setCommand(kGoodweatherCmdSwing); - remote &= ~kGoodweatherSwingMask; - remote |= ((uint64_t)speed << kGoodweatherBitSwing); + setBits(&remote, kGoodweatherBitSwing, kGoodweatherSwingSize, speed); break; default: this->setSwing(kGoodweatherSwingOff); @@ -199,33 +194,26 @@ void IRGoodweatherAc::setSwing(const uint8_t speed) { } uint8_t IRGoodweatherAc::getSwing() { - return (remote & kGoodweatherSwingMask) >> kGoodweatherBitSwing; + return GETBITS64(remote, kGoodweatherBitSwing, kGoodweatherSwingSize); } void IRGoodweatherAc::setCommand(const uint8_t cmd) { - if (cmd <= kGoodweatherCmdLight) { - remote &= ~kGoodweatherCommandMask; - remote |= (cmd << kGoodweatherBitCommand); - } + if (cmd <= kGoodweatherCmdLight) + setBits(&remote, kGoodweatherBitCommand, kGoodweatherCommandSize, cmd); } uint8_t IRGoodweatherAc::getCommand() { - return (remote & kGoodweatherCommandMask) >> kGoodweatherBitCommand; + return GETBITS64(remote, kGoodweatherBitCommand, kGoodweatherCommandSize); } // Convert a standard A/C mode into its native mode. uint8_t IRGoodweatherAc::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kGoodweatherCool; - case stdAc::opmode_t::kHeat: - return kGoodweatherHeat; - case stdAc::opmode_t::kDry: - return kGoodweatherDry; - case stdAc::opmode_t::kFan: - return kGoodweatherFan; - default: - return kGoodweatherAuto; + case stdAc::opmode_t::kCool: return kGoodweatherCool; + case stdAc::opmode_t::kHeat: return kGoodweatherHeat; + case stdAc::opmode_t::kDry: return kGoodweatherDry; + case stdAc::opmode_t::kFan: return kGoodweatherFan; + default: return kGoodweatherAuto; } } @@ -233,15 +221,11 @@ uint8_t IRGoodweatherAc::convertMode(const stdAc::opmode_t mode) { uint8_t IRGoodweatherAc::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kGoodweatherFanLow; - case stdAc::fanspeed_t::kMedium: - return kGoodweatherFanMed; + case stdAc::fanspeed_t::kLow: return kGoodweatherFanLow; + case stdAc::fanspeed_t::kMedium: return kGoodweatherFanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kGoodweatherFanHigh; - default: - return kGoodweatherFanAuto; + case stdAc::fanspeed_t::kMax: return kGoodweatherFanHigh; + default: return kGoodweatherFanAuto; } } @@ -250,14 +234,11 @@ uint8_t IRGoodweatherAc::convertSwingV(const stdAc::swingv_t swingv) { switch (swingv) { case stdAc::swingv_t::kHighest: case stdAc::swingv_t::kHigh: - case stdAc::swingv_t::kMiddle: - return kGoodweatherSwingFast; + case stdAc::swingv_t::kMiddle: return kGoodweatherSwingFast; case stdAc::swingv_t::kLow: case stdAc::swingv_t::kLowest: - case stdAc::swingv_t::kAuto: - return kGoodweatherSwingSlow; - default: - return kGoodweatherSwingOff; + case stdAc::swingv_t::kAuto: return kGoodweatherSwingSlow; + default: return kGoodweatherSwingOff; } } @@ -266,9 +247,9 @@ stdAc::opmode_t IRGoodweatherAc::toCommonMode(const uint8_t mode) { switch (mode) { case kGoodweatherCool: return stdAc::opmode_t::kCool; case kGoodweatherHeat: return stdAc::opmode_t::kHeat; - case kGoodweatherDry: return stdAc::opmode_t::kDry; - case kGoodweatherFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kGoodweatherDry: return stdAc::opmode_t::kDry; + case kGoodweatherFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -276,9 +257,9 @@ stdAc::opmode_t IRGoodweatherAc::toCommonMode(const uint8_t mode) { stdAc::fanspeed_t IRGoodweatherAc::toCommonFanSpeed(const uint8_t speed) { switch (speed) { case kGoodweatherFanHigh: return stdAc::fanspeed_t::kMax; - case kGoodweatherFanMed: return stdAc::fanspeed_t::kMedium; - case kGoodweatherFanLow: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kGoodweatherFanMed: return stdAc::fanspeed_t::kMedium; + case kGoodweatherFanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } @@ -309,74 +290,78 @@ stdAc::state_t IRGoodweatherAc::toCommon(void) { } // Convert the internal state into a human readable string. -String IRGoodweatherAc::toString() { +String IRGoodweatherAc::toString(void) { String result = ""; result.reserve(150); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kGoodweatherAuto, kGoodweatherCool, kGoodweatherHeat, kGoodweatherDry, kGoodweatherFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kGoodweatherFanHigh, kGoodweatherFanLow, kGoodweatherFanAuto, kGoodweatherFanAuto, kGoodweatherFanMed); - result += addLabeledString(getTurbo() ? F("Toggle") : F("-"), F("Turbo")); - result += addLabeledString(getLight() ? F("Toggle") : F("-"), F("Light")); - result += addLabeledString(getSleep() ? F("Toggle") : F("-"), F("Sleep")); - result += addIntToString(getSwing(), F("Swing")); + result += addLabeledString(getTurbo() ? kToggleStr : F("-"), kTurboStr); + result += addLabeledString(getLight() ? kToggleStr : F("-"), kLightStr); + result += addLabeledString(getSleep() ? kToggleStr : F("-"), kSleepStr); + result += addIntToString(getSwing(), kSwingStr); + result += kSpaceLBraceStr; switch (this->getSwing()) { case kGoodweatherSwingFast: - result += F(" (Fast)"); + result += kFastStr; break; case kGoodweatherSwingSlow: - result += F(" (Slow)"); + result += kSlowStr; break; case kGoodweatherSwingOff: - result += F(" (Off)"); + result += kOffStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } - result += addIntToString(getCommand(), F("Command")); + result += ')'; + result += addIntToString(getCommand(), kCommandStr); + result += kSpaceLBraceStr; switch (this->getCommand()) { case kGoodweatherCmdPower: - result += F(" (Power)"); + result += kPowerStr; break; case kGoodweatherCmdMode: - result += F(" (Mode)"); + result += kModeStr; break; case kGoodweatherCmdUpTemp: - result += F(" (Temp Up)"); + result += kTempUpStr; break; case kGoodweatherCmdDownTemp: - result += F(" (Temp Down)"); + result += kTempDownStr; break; case kGoodweatherCmdSwing: - result += F(" (Swing)"); + result += kSwingStr; break; case kGoodweatherCmdFan: - result += F(" (Fan)"); + result += kFanStr; break; case kGoodweatherCmdTimer: - result += F(" (Timer)"); + result += kTimerStr; break; case kGoodweatherCmdAirFlow: - result += F(" (Air Flow)"); + result += kAirFlowStr; break; case kGoodweatherCmdHold: - result += F(" (Hold)"); + result += kHoldStr; break; case kGoodweatherCmdSleep: - result += F(" (Sleep)"); + result += kSleepStr; break; case kGoodweatherCmdTurbo: - result += F(" (Turbo)"); + result += kTurboStr; break; case kGoodweatherCmdLight: - result += F(" (Light)"); + result += kLightStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } + result += ')'; return result; } @@ -419,7 +404,8 @@ bool IRrecv::decodeGoodweather(decode_results* results, data_result = matchData(&(results->rawbuf[offset]), 8, kGoodweatherBitMark, kGoodweatherOneSpace, kGoodweatherBitMark, kGoodweatherZeroSpace, - _tolerance, kMarkExcess, false); + _tolerance + kGoodweatherExtraTolerance, + kMarkExcess, false); if (data_result.success == false) return false; DPRINTLN("DEBUG: Normal byte read okay."); offset += data_result.used; @@ -428,7 +414,8 @@ bool IRrecv::decodeGoodweather(decode_results* results, data_result = matchData(&(results->rawbuf[offset]), 8, kGoodweatherBitMark, kGoodweatherOneSpace, kGoodweatherBitMark, kGoodweatherZeroSpace, - _tolerance, kMarkExcess, false); + _tolerance + kGoodweatherExtraTolerance, + kMarkExcess, false); if (data_result.success == false) return false; DPRINTLN("DEBUG: Inverted byte read okay."); offset += data_result.used; @@ -442,10 +429,12 @@ bool IRrecv::decodeGoodweather(decode_results* results, } // Footer. - if (!matchMark(results->rawbuf[offset++], kGoodweatherBitMark)) return false; + if (!matchMark(results->rawbuf[offset++], kGoodweatherBitMark, + _tolerance + kGoodweatherExtraTolerance)) return false; if (!matchSpace(results->rawbuf[offset++], kGoodweatherHdrSpace)) return false; - if (!matchMark(results->rawbuf[offset++], kGoodweatherBitMark)) return false; + if (!matchMark(results->rawbuf[offset++], kGoodweatherBitMark, + _tolerance + kGoodweatherExtraTolerance)) return false; if (offset <= results->rawlen && !matchAtLeast(results->rawbuf[offset], kGoodweatherHdrSpace)) return false; diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Goodweather.h b/lib/IRremoteESP8266-2.7.0/src/ir_Goodweather.h old mode 100755 new mode 100644 similarity index 81% rename from lib/IRremoteESP8266-2.6.5/src/ir_Goodweather.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Goodweather.h index 76d559779..8f1953581 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Goodweather.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Goodweather.h @@ -26,31 +26,30 @@ // Constants // Timing -const uint16_t kGoodweatherBitMark = 640; +const uint16_t kGoodweatherBitMark = 580; const uint16_t kGoodweatherOneSpace = 580; -const uint16_t kGoodweatherZeroSpace = 1600; -const uint16_t kGoodweatherHdrMark = 6800; -const uint16_t kGoodweatherHdrSpace = 6800; +const uint16_t kGoodweatherZeroSpace = 1860; +const uint16_t kGoodweatherHdrMark = 6820; +const uint16_t kGoodweatherHdrSpace = 6820; +const uint8_t kGoodweatherExtraTolerance = 12; // +12% extra // Masks const uint8_t kGoodweatherBitLight = 8; -const uint64_t kGoodweatherLightMask = 0x1ULL << kGoodweatherBitLight; const uint8_t kGoodweatherBitTurbo = kGoodweatherBitLight + 3; // 11 -const uint64_t kGoodweatherTurboMask = 0x1ULL << kGoodweatherBitTurbo; const uint8_t kGoodweatherBitCommand = kGoodweatherBitTurbo + 5; // 16 -const uint64_t kGoodweatherCommandMask = 0xFULL << kGoodweatherBitCommand; +const uint8_t kGoodweatherCommandSize = 4; // Bits const uint8_t kGoodweatherBitSleep = kGoodweatherBitCommand + 8; // 24 -const uint64_t kGoodweatherSleepMask = 0x1ULL << kGoodweatherBitSleep; const uint8_t kGoodweatherBitPower = kGoodweatherBitSleep + 1; // 25 -const uint64_t kGoodweatherPowerMask = 0x1ULL << kGoodweatherBitPower; const uint8_t kGoodweatherBitSwing = kGoodweatherBitPower + 1; // 26 -const uint64_t kGoodweatherSwingMask = 0x3ULL << kGoodweatherBitSwing; -const uint8_t kGoodweatherBitFan = kGoodweatherBitSwing + 3; // 29 -const uint64_t kGoodweatherFanMask = 0x3ULL << kGoodweatherBitFan; +const uint8_t kGoodweatherSwingSize = 2; // Bits +const uint8_t kGoodweatherBitAirFlow = kGoodweatherBitSwing + 2; // 28 +const uint8_t kGoodweatherBitFan = kGoodweatherBitAirFlow + 1; // 29 +const uint8_t kGoodweatherFanSize = 2; // Bits const uint8_t kGoodweatherBitTemp = kGoodweatherBitFan + 3; // 32 -const uint64_t kGoodweatherTempMask = 0xFULL << kGoodweatherBitTemp; +const uint8_t kGoodweatherTempSize = 4; // Bits const uint8_t kGoodweatherBitMode = kGoodweatherBitTemp + 5; // 37 -const uint64_t kGoodweatherModeMask = 0x7ULL << kGoodweatherBitMode; +const uint8_t kGoodweatherBitEOF = kGoodweatherBitMode + 3; // 40 +const uint64_t kGoodweatherEOFMask = 0xFFULL << kGoodweatherBitEOF; // Modes const uint8_t kGoodweatherAuto = 0b000; @@ -58,6 +57,7 @@ const uint8_t kGoodweatherCool = 0b001; const uint8_t kGoodweatherDry = 0b010; const uint8_t kGoodweatherFan = 0b011; const uint8_t kGoodweatherHeat = 0b100; +// Swing const uint8_t kGoodweatherSwingFast = 0b00; const uint8_t kGoodweatherSwingSlow = 0b01; const uint8_t kGoodweatherSwingOff = 0b10; @@ -82,6 +82,8 @@ const uint8_t kGoodweatherCmdHold = 0x08; const uint8_t kGoodweatherCmdSleep = 0x09; const uint8_t kGoodweatherCmdTurbo = 0x0A; const uint8_t kGoodweatherCmdLight = 0x0B; +// PAD EOF +const uint64_t kGoodweatherStateInit = 0xD50000000000; // Classes diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Gree.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Gree.cpp old mode 100755 new mode 100644 similarity index 71% rename from lib/IRremoteESP8266-2.6.5/src/ir_Gree.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Gree.cpp index a4d906424..21eb78e28 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Gree.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Gree.cpp @@ -9,12 +9,14 @@ #include "ir_Gree.h" #include +#include #ifndef ARDUINO #include #endif #include "IRrecv.h" #include "IRremoteESP8266.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" #include "ir_Kelvinator.h" @@ -33,9 +35,12 @@ using irutils::addBoolToString; using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; +using irutils::addModelToString; using irutils::addFanToString; using irutils::addTempToString; using irutils::minsToString; +using irutils::setBit; +using irutils::setBits; #if SEND_GREE // Send a Gree Heat Pump message. @@ -151,12 +156,10 @@ uint8_t* IRGreeAC::getRaw(void) { } void IRGreeAC::setRaw(const uint8_t new_code[]) { - for (uint8_t i = 0; i < kGreeStateLength; i++) { - remote_state[i] = new_code[i]; - } + memcpy(remote_state, new_code, kGreeStateLength); // We can only detect the difference between models when the power is on. if (getPower()) { - if (remote_state[2] & kGreePower2Mask) + if (GETBIT8(remote_state[2], kGreePower2Offset)) _model = gree_ac_remote_model_t::YAW1F; else _model = gree_ac_remote_model_t::YBOFB; @@ -165,8 +168,8 @@ void IRGreeAC::setRaw(const uint8_t new_code[]) { void IRGreeAC::checksum(const uint16_t length) { // Gree uses the same checksum alg. as Kelvinator's block checksum. - uint8_t sum = IRKelvinatorAC::calcBlockChecksum(remote_state, length); - remote_state[length - 1] = (sum << 4) | (remote_state[length - 1] & 0xFU); + setBits(&remote_state[length - 1], kHighNibble, kNibbleSize, + IRKelvinatorAC::calcBlockChecksum(remote_state, length)); } // Verify the checksum is valid for a given state. @@ -177,45 +180,34 @@ void IRGreeAC::checksum(const uint16_t length) { // A boolean. bool IRGreeAC::validChecksum(const uint8_t state[], const uint16_t length) { // Top 4 bits of the last byte in the state is the state's checksum. - return (state[length - 1] >> 4 == IRKelvinatorAC::calcBlockChecksum(state, - length)); + return GETBITS8(state[length - 1], kHighNibble, kNibbleSize) == + IRKelvinatorAC::calcBlockChecksum(state, length); } void IRGreeAC::setModel(const gree_ac_remote_model_t model) { switch (model) { case gree_ac_remote_model_t::YAW1F: - case gree_ac_remote_model_t::YBOFB: - _model = model; break; - default: - setModel(gree_ac_remote_model_t::YAW1F); + case gree_ac_remote_model_t::YBOFB: _model = model; break; + default: setModel(gree_ac_remote_model_t::YAW1F); } } -gree_ac_remote_model_t IRGreeAC::getModel(void) { - return _model; -} +gree_ac_remote_model_t IRGreeAC::getModel(void) { return _model; } void IRGreeAC::on(void) { setPower(true); } void IRGreeAC::off(void) { setPower(false); } void IRGreeAC::setPower(const bool on) { - if (on) { - remote_state[0] |= kGreePower1Mask; - switch (_model) { - case gree_ac_remote_model_t::YBOFB: break; - default: - remote_state[2] |= kGreePower2Mask; - } - } else { - remote_state[0] &= ~kGreePower1Mask; - remote_state[2] &= ~kGreePower2Mask; // May not be needed. See #814 - } + setBit(&remote_state[0], kGreePower1Offset, on); + // May not be needed. See #814 + setBit(&remote_state[2], kGreePower2Offset, + on && _model != gree_ac_remote_model_t::YBOFB); } bool IRGreeAC::getPower(void) { // See #814. Not checking/requiring: (remote_state[2] & kGreePower2Mask) - return remote_state[0] & kGreePower1Mask; + return GETBIT8(remote_state[0], kGreePower1Offset); } // Set the temp. in deg C @@ -223,109 +215,96 @@ void IRGreeAC::setTemp(const uint8_t temp) { uint8_t new_temp = std::max((uint8_t)kGreeMinTemp, temp); new_temp = std::min((uint8_t)kGreeMaxTemp, new_temp); if (getMode() == kGreeAuto) new_temp = 25; - remote_state[1] = (remote_state[1] & ~kGreeTempMask) | - (new_temp - kGreeMinTemp); + setBits(&remote_state[1], kLowNibble, kGreeTempSize, new_temp - kGreeMinTemp); } // Return the set temp. in deg C uint8_t IRGreeAC::getTemp(void) { - return ((remote_state[1] & kGreeTempMask) + kGreeMinTemp); + return GETBITS8(remote_state[1], kLowNibble, kGreeTempSize) + kGreeMinTemp; } // Set the speed of the fan, 0-3, 0 is auto, 1-3 is the speed void IRGreeAC::setFan(const uint8_t speed) { uint8_t fan = std::min((uint8_t)kGreeFanMax, speed); // Bounds check - if (getMode() == kGreeDry) fan = 1; // DRY mode is always locked to fan 1. // Set the basic fan values. - remote_state[0] &= ~kGreeFanMask; - remote_state[0] |= (fan << 4); + setBits(&remote_state[0], kGreeFanOffset, kGreeFanSize, fan); } -uint8_t IRGreeAC::getFan(void) { return (remote_state[0] & kGreeFanMask) >> 4; } +uint8_t IRGreeAC::getFan(void) { + return GETBITS8(remote_state[0], kGreeFanOffset, kGreeFanSize); +} void IRGreeAC::setMode(const uint8_t new_mode) { uint8_t mode = new_mode; switch (mode) { - case kGreeAuto: - // AUTO is locked to 25C - setTemp(25); - break; - case kGreeDry: - // DRY always sets the fan to 1. - setFan(1); - break; + // AUTO is locked to 25C + case kGreeAuto: setTemp(25); break; + // DRY always sets the fan to 1. + case kGreeDry: setFan(1); break; case kGreeCool: case kGreeFan: - case kGreeHeat: - break; - default: - // If we get an unexpected mode, default to AUTO. - mode = kGreeAuto; + case kGreeHeat: break; + // If we get an unexpected mode, default to AUTO. + default: mode = kGreeAuto; } - remote_state[0] &= ~kGreeModeMask; - remote_state[0] |= mode; + setBits(&remote_state[0], kLowNibble, kModeBitsSize, mode); } -uint8_t IRGreeAC::getMode(void) { return (remote_state[0] & kGreeModeMask); } +uint8_t IRGreeAC::getMode(void) { + return GETBITS8(remote_state[0], kLowNibble, kModeBitsSize); +} void IRGreeAC::setLight(const bool on) { - if (on) - remote_state[2] |= kGreeLightMask; - else - remote_state[2] &= ~kGreeLightMask; + setBit(&remote_state[2], kGreeLightOffset, on); } -bool IRGreeAC::getLight(void) { return remote_state[2] & kGreeLightMask; } +bool IRGreeAC::getLight(void) { + return GETBIT8(remote_state[2], kGreeLightOffset); +} void IRGreeAC::setIFeel(const bool on) { - if (on) - remote_state[5] |= kGreeIFeelMask; - else - remote_state[5] &= ~kGreeIFeelMask; + setBit(&remote_state[5], kGreeIFeelOffset, on); } -bool IRGreeAC::getIFeel(void) { return remote_state[5] & kGreeIFeelMask; } +bool IRGreeAC::getIFeel(void) { + return GETBIT8(remote_state[5], kGreeIFeelOffset); +} void IRGreeAC::setWiFi(const bool on) { - if (on) - remote_state[5] |= kGreeWiFiMask; - else - remote_state[5] &= ~kGreeWiFiMask; + setBit(&remote_state[5], kGreeWiFiOffset, on); } -bool IRGreeAC::getWiFi(void) { return remote_state[5] & kGreeWiFiMask; } +bool IRGreeAC::getWiFi(void) { + return GETBIT8(remote_state[5], kGreeWiFiOffset); +} void IRGreeAC::setXFan(const bool on) { - if (on) - remote_state[2] |= kGreeXfanMask; - else - remote_state[2] &= ~kGreeXfanMask; + setBit(&remote_state[2], kGreeXfanOffset, on); } -bool IRGreeAC::getXFan(void) { return remote_state[2] & kGreeXfanMask; } +bool IRGreeAC::getXFan(void) { + return GETBIT8(remote_state[2], kGreeXfanOffset); +} void IRGreeAC::setSleep(const bool on) { - if (on) - remote_state[0] |= kGreeSleepMask; - else - remote_state[0] &= ~kGreeSleepMask; + setBit(&remote_state[0], kGreeSleepOffset, on); } -bool IRGreeAC::getSleep(void) { return remote_state[0] & kGreeSleepMask; } +bool IRGreeAC::getSleep(void) { + return GETBIT8(remote_state[0], kGreeSleepOffset); +} void IRGreeAC::setTurbo(const bool on) { - if (on) - remote_state[2] |= kGreeTurboMask; - else - remote_state[2] &= ~kGreeTurboMask; + setBit(&remote_state[2], kGreeTurboOffset, on); } -bool IRGreeAC::getTurbo(void) { return remote_state[2] & kGreeTurboMask; } +bool IRGreeAC::getTurbo(void) { + return GETBIT8(remote_state[2], kGreeTurboOffset); +} void IRGreeAC::setSwingVertical(const bool automatic, const uint8_t position) { - remote_state[0] &= ~kGreeSwingAutoMask; - remote_state[0] |= (automatic << 6); + setBit(&remote_state[0], kGreeSwingAutoOffset, automatic); uint8_t new_position = position; if (!automatic) { switch (position) { @@ -349,35 +328,32 @@ void IRGreeAC::setSwingVertical(const bool automatic, const uint8_t position) { new_position = kGreeSwingAuto; } } - remote_state[4] &= ~kGreeSwingPosMask; - remote_state[4] |= new_position; + setBits(&remote_state[4], kLowNibble, kGreeSwingSize, new_position); } bool IRGreeAC::getSwingVerticalAuto(void) { - return remote_state[0] & kGreeSwingAutoMask; + return GETBIT8(remote_state[0], kGreeSwingAutoOffset); } uint8_t IRGreeAC::getSwingVerticalPosition(void) { - return remote_state[4] & kGreeSwingPosMask; + return GETBITS8(remote_state[4], kLowNibble, kGreeSwingSize); } void IRGreeAC::setTimerEnabled(const bool on) { - if (on) - remote_state[1] |= kGreeTimerEnabledBit; - else - remote_state[1] &= ~kGreeTimerEnabledBit; + setBit(&remote_state[1], kGreeTimerEnabledOffset, on); } bool IRGreeAC::getTimerEnabled(void) { - return remote_state[1] & kGreeTimerEnabledBit; + return GETBIT8(remote_state[1], kGreeTimerEnabledOffset); } // Returns the number of minutes the timer is set for. uint16_t IRGreeAC::getTimer(void) { uint16_t hrs = irutils::bcdToUint8( - (remote_state[2] & kGreeTimerHoursMask) | - ((remote_state[1] & kGreeTimerTensHrMask) >> 1)); - return hrs * 60 + ((remote_state[1] & kGreeTimerHalfHrBit) ? 30 : 0); + (GETBITS8(remote_state[1], kGreeTimerTensHrOffset, + kGreeTimerTensHrSize) << kNibbleSize) | + GETBITS8(remote_state[2], kGreeTimerHoursOffset, kGreeTimerHoursSize)); + return hrs * 60 + (GETBIT8(remote_state[1], kGreeTimerHalfHrOffset) ? 30 : 0); } // Set the A/C's timer to turn off in X many minutes. @@ -387,66 +363,51 @@ uint16_t IRGreeAC::getTimer(void) { // Args: // minutes: The number of minutes the timer should be set for. void IRGreeAC::setTimer(const uint16_t minutes) { - // Clear the previous settings. - remote_state[1] &= ~kGreeTimer1Mask; - remote_state[2] &= ~kGreeTimerHoursMask; uint16_t mins = std::min(kGreeTimerMax, minutes); // Bounds check. setTimerEnabled(mins >= 30); // Timer is enabled when >= 30 mins. uint8_t hours = mins / 60; - uint8_t halfhour = (mins % 60) < 30 ? 0 : 1; - // Set the "tens" digit of hours & the half hour. - remote_state[1] |= (((hours / 10) << 1) | halfhour) << 4; + // Set the half hour bit. + setBit(&remote_state[1], kGreeTimerHalfHrOffset, !((mins % 60) < 30)); + // Set the "tens" digit of hours. + setBits(&remote_state[1], kGreeTimerTensHrOffset, kGreeTimerTensHrSize, + hours / 10); // Set the "units" digit of hours. - remote_state[2] |= (hours % 10); + setBits(&remote_state[2], kGreeTimerHoursOffset, kGreeTimerHoursSize, + hours % 10); } // Convert a standard A/C mode into its native mode. uint8_t IRGreeAC::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kGreeCool; - case stdAc::opmode_t::kHeat: - return kGreeHeat; - case stdAc::opmode_t::kDry: - return kGreeDry; - case stdAc::opmode_t::kFan: - return kGreeFan; - default: - return kGreeAuto; + case stdAc::opmode_t::kCool: return kGreeCool; + case stdAc::opmode_t::kHeat: return kGreeHeat; + case stdAc::opmode_t::kDry: return kGreeDry; + case stdAc::opmode_t::kFan: return kGreeFan; + default: return kGreeAuto; } } // Convert a standard A/C Fan speed into its native fan speed. uint8_t IRGreeAC::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { - case stdAc::fanspeed_t::kMin: - return kGreeFanMin; + case stdAc::fanspeed_t::kMin: return kGreeFanMin; case stdAc::fanspeed_t::kLow: - case stdAc::fanspeed_t::kMedium: - return kGreeFanMax - 1; + case stdAc::fanspeed_t::kMedium: return kGreeFanMax - 1; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kGreeFanMax; - default: - return kGreeFanAuto; + case stdAc::fanspeed_t::kMax: return kGreeFanMax; + default: return kGreeFanAuto; } } // Convert a standard A/C Vertical Swing into its native version. uint8_t IRGreeAC::convertSwingV(const stdAc::swingv_t swingv) { switch (swingv) { - case stdAc::swingv_t::kHighest: - return kGreeSwingUp; - case stdAc::swingv_t::kHigh: - return kGreeSwingMiddleUp; - case stdAc::swingv_t::kMiddle: - return kGreeSwingMiddle; - case stdAc::swingv_t::kLow: - return kGreeSwingMiddleDown; - case stdAc::swingv_t::kLowest: - return kGreeSwingDown; - default: - return kGreeSwingAuto; + case stdAc::swingv_t::kHighest: return kGreeSwingUp; + case stdAc::swingv_t::kHigh: return kGreeSwingMiddleUp; + case stdAc::swingv_t::kMiddle: return kGreeSwingMiddle; + case stdAc::swingv_t::kLow: return kGreeSwingMiddleDown; + case stdAc::swingv_t::kLowest: return kGreeSwingDown; + default: return kGreeSwingAuto; } } @@ -515,40 +476,35 @@ stdAc::state_t IRGreeAC::toCommon(void) { String IRGreeAC::toString(void) { String result = ""; result.reserve(150); // Reserve some heap for the string to reduce fragging. - result += addIntToString(getModel(), F("Model"), false); - switch (getModel()) { - case gree_ac_remote_model_t::YAW1F: result += F(" (YAW1F)"); break; - case gree_ac_remote_model_t::YBOFB: result += F(" (YBOFB)"); break; - default: result += F(" (UNKNOWN)"); - } - result += addBoolToString(getPower(), F("Power")); + result += addModelToString(decode_type_t::GREE, getModel(), false); + result += addBoolToString(getPower(), kPowerStr); result += addModeToString(getMode(), kGreeAuto, kGreeCool, kGreeHeat, kGreeDry, kGreeFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kGreeFanMax, kGreeFanMin, kGreeFanAuto, kGreeFanAuto, kGreeFanMed); - result += addBoolToString(getTurbo(), F("Turbo")); - result += addBoolToString(getIFeel(), F("IFeel")); - result += addBoolToString(getWiFi(), F("WiFi")); - result += addBoolToString(getXFan(), F("XFan")); - result += addBoolToString(getLight(), F("Light")); - result += addBoolToString(getSleep(), F("Sleep")); - result += addLabeledString(getSwingVerticalAuto() ? F("Auto") : F("Manual"), - F("Swing Vertical Mode")); - result += addIntToString(getSwingVerticalPosition(), F("Swing Vertical Pos")); + result += addBoolToString(getTurbo(), kTurboStr); + result += addBoolToString(getIFeel(), kIFeelStr); + result += addBoolToString(getWiFi(), kWifiStr); + result += addBoolToString(getXFan(), kXFanStr); + result += addBoolToString(getLight(), kLightStr); + result += addBoolToString(getSleep(), kSleepStr); + result += addLabeledString(getSwingVerticalAuto() ? kAutoStr : kManualStr, + kSwingVStr + ' ' + kModeStr); + result += addIntToString(getSwingVerticalPosition(), kSwingVStr); + result += kSpaceLBraceStr; switch (getSwingVerticalPosition()) { case kGreeSwingLastPos: - result += F(" (Last Pos)"); + result += kLastStr; break; case kGreeSwingAuto: - result += F(" (Auto)"); + result += kAutoStr; break; + default: result += kUnknownStr; } - result += F(", Timer: "); - if (getTimerEnabled()) - result += minsToString(getTimer()); - else - result += F("Off"); + result += ')'; + result += addLabeledString( + getTimerEnabled() ? minsToString(getTimer()) : kOffStr, kTimerStr); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Gree.h b/lib/IRremoteESP8266-2.7.0/src/ir_Gree.h old mode 100755 new mode 100644 similarity index 72% rename from lib/IRremoteESP8266-2.6.5/src/ir_Gree.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Gree.h index a399d50d5..14cd7b84a --- a/lib/IRremoteESP8266-2.6.5/src/ir_Gree.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Gree.h @@ -24,10 +24,6 @@ #endif // Constants -enum gree_ac_remote_model_t { - YAW1F = 1, // (1) Ultimate, EKOKAI, RusClimate (Default) - YBOFB, // (2) Green, YBOFB2, YAPOF3 -}; const uint8_t kGreeAuto = 0; const uint8_t kGreeCool = 1; @@ -36,48 +32,48 @@ const uint8_t kGreeFan = 3; const uint8_t kGreeHeat = 4; // Byte 0 -const uint8_t kGreeModeMask = 0b00000111; -const uint8_t kGreePower1Mask = 0b00001000; -const uint8_t kGreeFanMask = 0b00110000; +const uint8_t kGreePower1Offset = 3; +const uint8_t kGreeFanOffset = 4; +const uint8_t kGreeFanSize = 2; // Bits const uint8_t kGreeFanAuto = 0; const uint8_t kGreeFanMin = 1; const uint8_t kGreeFanMed = 2; const uint8_t kGreeFanMax = 3; -const uint8_t kGreeSwingAutoMask = 0b01000000; -const uint8_t kGreeSleepMask = 0b10000000; +const uint8_t kGreeSwingAutoOffset = 6; +const uint8_t kGreeSleepOffset = 7; // Byte 1 -const uint8_t kGreeTempMask = 0b00001111; +const uint8_t kGreeTempSize = 4; const uint8_t kGreeMinTemp = 16; // Celsius const uint8_t kGreeMaxTemp = 30; // Celsius -const uint8_t kGreeTimerEnabledBit = 0b10000000; -const uint8_t kGreeTimerHalfHrBit = 0b00010000; -const uint8_t kGreeTimerTensHrMask = 0b01100000; -const uint8_t kGreeTimer1Mask = kGreeTimerTensHrMask | kGreeTimerHalfHrBit; +const uint8_t kGreeTimerHalfHrOffset = 4; +const uint8_t kGreeTimerTensHrOffset = 5; +const uint8_t kGreeTimerTensHrSize = 2; // Bits const uint16_t kGreeTimerMax = 24 * 60; +const uint8_t kGreeTimerEnabledOffset = 7; // Byte 2 -const uint8_t kGreeTimerHoursMask = 0b00001111; -const uint8_t kGreeTurboMask = 0b00010000; -const uint8_t kGreeLightMask = 0b00100000; +const uint8_t kGreeTimerHoursOffset = 0; +const uint8_t kGreeTimerHoursSize = 4; // Bits +const uint8_t kGreeTurboOffset = 4; +const uint8_t kGreeLightOffset = 5; // This might not be used. See #814 -const uint8_t kGreePower2Mask = 0b01000000; -const uint8_t kGreeXfanMask = 0b10000000; +const uint8_t kGreePower2Offset = 6; +const uint8_t kGreeXfanOffset = 7; // Byte 4 -const uint8_t kGreeSwingPosMask = 0b00001111; +const uint8_t kGreeSwingSize = 4; // Bits +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; // byte 5 -const uint8_t kGreeIFeelMask = 0b00000100; -const uint8_t kGreeWiFiMask = 0b01000000; - -const uint8_t kGreeSwingLastPos = 0b00000000; -const uint8_t kGreeSwingAuto = 0b00000001; -const uint8_t kGreeSwingUp = 0b00000010; -const uint8_t kGreeSwingMiddleUp = 0b00000011; -const uint8_t kGreeSwingMiddle = 0b00000100; -const uint8_t kGreeSwingMiddleDown = 0b00000101; -const uint8_t kGreeSwingDown = 0b00000110; -const uint8_t kGreeSwingDownAuto = 0b00000111; -const uint8_t kGreeSwingMiddleAuto = 0b00001001; -const uint8_t kGreeSwingUpAuto = 0b00001011; +const uint8_t kGreeIFeelOffset = 2; +const uint8_t kGreeWiFiOffset = 6; // Legacy defines. #define GREE_AUTO kGreeAuto diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Haier.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Haier.cpp old mode 100755 new mode 100644 similarity index 67% rename from lib/IRremoteESP8266-2.6.5/src/ir_Haier.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Haier.cpp index d2b947f9e..d0cbf5230 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Haier.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Haier.cpp @@ -5,10 +5,12 @@ // * YR-W02/HSU-09HMC203 by non7top. #include "ir_Haier.h" +#include #ifndef UNIT_TEST #include #endif #include "IRremoteESP8266.h" +#include "IRtext.h" #include "IRutils.h" // Supported devices: @@ -37,6 +39,8 @@ using irutils::addModeToString; using irutils::addFanToString; using irutils::addTempToString; using irutils::minsToString; +using irutils::setBit; +using irutils::setBits; #if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02) // Send a Haier A/C message. (HSU07-HEA03 remote) @@ -90,8 +94,7 @@ void IRHaierAC::begin(void) { _irsend.begin(); } #if SEND_HAIER_AC void IRHaierAC::send(const uint16_t repeat) { - checksum(); - _irsend.sendHaierAC(remote_state, kHaierACStateLength, repeat); + _irsend.sendHaierAC(getRaw(), kHaierACStateLength, repeat); } #endif // SEND_HAIER_AC @@ -123,14 +126,11 @@ uint8_t* IRHaierAC::getRaw(void) { } void IRHaierAC::setRaw(const uint8_t new_code[]) { - for (uint8_t i = 0; i < kHaierACStateLength; i++) { - remote_state[i] = new_code[i]; - } + memcpy(remote_state, new_code, kHaierACStateLength); } -void IRHaierAC::setCommand(const uint8_t state) { - remote_state[1] &= 0b11110000; - switch (state) { +void IRHaierAC::setCommand(const uint8_t command) { + switch (command) { case kHaierAcCmdOff: case kHaierAcCmdOn: case kHaierAcCmdMode: @@ -142,61 +142,51 @@ void IRHaierAC::setCommand(const uint8_t state) { case kHaierAcCmdTimerCancel: case kHaierAcCmdHealth: case kHaierAcCmdSwing: - remote_state[1] |= (state & 0b00001111); + setBits(&remote_state[1], kLowNibble, kNibbleSize, command); } } -uint8_t IRHaierAC::getCommand(void) { return remote_state[1] & (0b00001111); } +uint8_t IRHaierAC::getCommand(void) { + return GETBITS8(remote_state[1], kLowNibble, kNibbleSize); +} void IRHaierAC::setFan(const uint8_t speed) { uint8_t new_speed = kHaierAcFanAuto; switch (speed) { - case kHaierAcFanLow: - new_speed = 3; - break; - case kHaierAcFanMed: - new_speed = 1; - break; - case kHaierAcFanHigh: - new_speed = 2; - break; - default: - new_speed = kHaierAcFanAuto; // Default to auto for anything else. + case kHaierAcFanLow: new_speed = 3; break; + case kHaierAcFanMed: new_speed = 1; break; + case kHaierAcFanHigh: new_speed = 2; break; + // Default to auto for anything else. + default: new_speed = kHaierAcFanAuto; } if (speed != getFan()) setCommand(kHaierAcCmdFan); - remote_state[5] &= 0b11111100; - remote_state[5] |= new_speed; + setBits(&remote_state[5], kLowNibble, kHaierAcSwingSize, new_speed); } uint8_t IRHaierAC::getFan(void) { - switch (remote_state[5] & 0b00000011) { - case 1: - return kHaierAcFanMed; - case 2: - return kHaierAcFanHigh; - case 3: - return kHaierAcFanLow; - default: - return kHaierAcFanAuto; + switch (GETBITS8(remote_state[5], kLowNibble, kHaierAcSwingSize)) { + case 1: return kHaierAcFanMed; + case 2: return kHaierAcFanHigh; + case 3: return kHaierAcFanLow; + default: return kHaierAcFanAuto; } } void IRHaierAC::setMode(uint8_t mode) { uint8_t new_mode = mode; setCommand(kHaierAcCmdMode); - if (mode > kHaierAcFan) // If out of range, default to auto mode. - new_mode = kHaierAcAuto; - remote_state[6] &= ~kHaierAcModeMask; - remote_state[6] |= (new_mode << 5); + // If out of range, default to auto mode. + if (mode > kHaierAcFan) new_mode = kHaierAcAuto; + setBits(&remote_state[6], kHaierAcModeOffset, kModeBitsSize, new_mode); } uint8_t IRHaierAC::getMode(void) { - return (remote_state[6] & kHaierAcModeMask) >> 5; + return GETBITS8(remote_state[6], kHaierAcModeOffset, kModeBitsSize); } -void IRHaierAC::setTemp(const uint8_t celsius) { - uint8_t temp = celsius; +void IRHaierAC::setTemp(const uint8_t degrees) { + uint8_t temp = degrees; if (temp < kHaierAcMinTemp) temp = kHaierAcMinTemp; else if (temp > kHaierAcMaxTemp) @@ -208,46 +198,47 @@ void IRHaierAC::setTemp(const uint8_t celsius) { setCommand(kHaierAcCmdTempDown); else setCommand(kHaierAcCmdTempUp); - - remote_state[1] &= 0b00001111; // Clear the previous temp. - remote_state[1] |= ((temp - kHaierAcMinTemp) << 4); + setBits(&remote_state[1], kHighNibble, kNibbleSize, temp - kHaierAcMinTemp); } uint8_t IRHaierAC::getTemp(void) { - return ((remote_state[1] & 0b11110000) >> 4) + kHaierAcMinTemp; + return GETBITS8(remote_state[1], kHighNibble, kNibbleSize) + kHaierAcMinTemp; } void IRHaierAC::setHealth(const bool on) { setCommand(kHaierAcCmdHealth); - remote_state[4] &= 0b11011111; - remote_state[4] |= (on << 5); + setBit(&remote_state[4], kHaierAcHealthBitOffset, on); } -bool IRHaierAC::getHealth(void) { return remote_state[4] & (1 << 5); } +bool IRHaierAC::getHealth(void) { + return GETBIT8(remote_state[4], kHaierAcHealthBitOffset); +} void IRHaierAC::setSleep(const bool on) { setCommand(kHaierAcCmdSleep); - if (on) - remote_state[7] |= kHaierAcSleepBit; - else - remote_state[7] &= ~kHaierAcSleepBit; + setBit(&remote_state[7], kHaierAcSleepBitOffset, on); } -bool IRHaierAC::getSleep(void) { return remote_state[7] & kHaierAcSleepBit; } +bool IRHaierAC::getSleep(void) { + return GETBIT8(remote_state[7], kHaierAcSleepBitOffset); +} uint16_t IRHaierAC::getTime(const uint8_t ptr[]) { - return (ptr[0] & 0b00011111) * 60 + (ptr[1] & 0b00111111); + return GETBITS8(ptr[0], kHaierAcTimeOffset, kHaierAcHoursSize) * 60 + + GETBITS8(ptr[1], kHaierAcTimeOffset, kHaierAcMinsSize); } int16_t IRHaierAC::getOnTimer(void) { - if (remote_state[3] & 0b10000000) // Check if the timer is turned on. + // Check if the timer is turned on. + if (GETBIT8(remote_state[3], kHaierAcOnTimerOffset)) return getTime(remote_state + 6); else return -1; } int16_t IRHaierAC::getOffTimer(void) { - if (remote_state[3] & 0b01000000) // Check if the timer is turned on. + // Check if the timer is turned on. + if (GETBIT8(remote_state[3], kHaierAcOffTimerOffset)) return getTime(remote_state + 4); else return -1; @@ -258,30 +249,25 @@ uint16_t IRHaierAC::getCurrTime(void) { return getTime(remote_state + 2); } void IRHaierAC::setTime(uint8_t ptr[], const uint16_t nr_mins) { uint16_t mins = nr_mins; if (nr_mins > kHaierAcMaxTime) mins = kHaierAcMaxTime; - - // Hours - ptr[0] &= 0b11100000; - ptr[0] |= (mins / 60); - // Minutes - ptr[1] &= 0b11000000; - ptr[1] |= (mins % 60); + setBits(ptr, kHaierAcTimeOffset, kHaierAcHoursSize, mins / 60); // Hours + setBits(ptr + 1, kHaierAcTimeOffset, kHaierAcMinsSize, mins % 60); // Minutes } void IRHaierAC::setOnTimer(const uint16_t nr_mins) { setCommand(kHaierAcCmdTimerSet); - remote_state[3] |= 0b10000000; + setBit(&remote_state[3], kHaierAcOnTimerOffset); setTime(remote_state + 6, nr_mins); } void IRHaierAC::setOffTimer(const uint16_t nr_mins) { setCommand(kHaierAcCmdTimerSet); - remote_state[3] |= 0b01000000; + setBit(&remote_state[3], kHaierAcOffTimerOffset); setTime(remote_state + 4, nr_mins); } void IRHaierAC::cancelTimers(void) { setCommand(kHaierAcCmdTimerCancel); - remote_state[3] &= 0b00111111; + setBits(&remote_state[3], kHaierAcOffTimerOffset, 2, 0); } void IRHaierAC::setCurrTime(const uint16_t nr_mins) { @@ -289,19 +275,18 @@ void IRHaierAC::setCurrTime(const uint16_t nr_mins) { } uint8_t IRHaierAC::getSwing(void) { - return (remote_state[2] & 0b11000000) >> 6; + return GETBITS8(remote_state[2], kHaierAcSwingOffset, kHaierAcSwingSize); } -void IRHaierAC::setSwing(const uint8_t state) { - if (state == getSwing()) return; // Nothing to do. - setCommand(kHaierAcCmdSwing); - switch (state) { +void IRHaierAC::setSwing(const uint8_t cmd) { + if (cmd == getSwing()) return; // Nothing to do. + switch (cmd) { case kHaierAcSwingOff: case kHaierAcSwingUp: case kHaierAcSwingDown: case kHaierAcSwingChg: - remote_state[2] &= 0b00111111; - remote_state[2] |= (state << 6); + setCommand(kHaierAcCmdSwing); + setBits(&remote_state[2], kHaierAcSwingOffset, kHaierAcSwingSize, cmd); break; } } @@ -309,16 +294,11 @@ void IRHaierAC::setSwing(const uint8_t state) { // Convert a standard A/C mode into its native mode. uint8_t IRHaierAC::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kHaierAcCool; - case stdAc::opmode_t::kHeat: - return kHaierAcHeat; - case stdAc::opmode_t::kDry: - return kHaierAcDry; - case stdAc::opmode_t::kFan: - return kHaierAcFan; - default: - return kHaierAcAuto; + case stdAc::opmode_t::kCool: return kHaierAcCool; + case stdAc::opmode_t::kHeat: return kHaierAcHeat; + case stdAc::opmode_t::kDry: return kHaierAcDry; + case stdAc::opmode_t::kFan: return kHaierAcFan; + default: return kHaierAcAuto; } } @@ -326,15 +306,11 @@ uint8_t IRHaierAC::convertMode(const stdAc::opmode_t mode) { uint8_t IRHaierAC::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kHaierAcFanLow; - case stdAc::fanspeed_t::kMedium: - return kHaierAcFanMed; + case stdAc::fanspeed_t::kLow: return kHaierAcFanLow; + case stdAc::fanspeed_t::kMedium: return kHaierAcFanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kHaierAcFanHigh; - default: - return kHaierAcFanAuto; + case stdAc::fanspeed_t::kMax: return kHaierAcFanHigh; + default: return kHaierAcFanAuto; } } @@ -343,15 +319,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 kHaierAcSwingUp; 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 kHaierAcSwingDown; + case stdAc::swingv_t::kOff: return kHaierAcSwingOff; + default: return kHaierAcSwingChg; } } @@ -360,9 +332,9 @@ stdAc::opmode_t IRHaierAC::toCommonMode(const uint8_t mode) { switch (mode) { case kHaierAcCool: return stdAc::opmode_t::kCool; case kHaierAcHeat: return stdAc::opmode_t::kHeat; - case kHaierAcDry: return stdAc::opmode_t::kDry; - case kHaierAcFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kHaierAcDry: return stdAc::opmode_t::kDry; + case kHaierAcFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -370,19 +342,19 @@ stdAc::opmode_t IRHaierAC::toCommonMode(const uint8_t mode) { stdAc::fanspeed_t IRHaierAC::toCommonFanSpeed(const uint8_t speed) { switch (speed) { case kHaierAcFanHigh: return stdAc::fanspeed_t::kMax; - case kHaierAcFanMed: return stdAc::fanspeed_t::kMedium; - case kHaierAcFanLow: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kHaierAcFanMed: return stdAc::fanspeed_t::kMedium; + case kHaierAcFanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } // Convert a native vertical swing to it's common equivalent. stdAc::swingv_t IRHaierAC::toCommonSwingV(const uint8_t pos) { switch (pos) { - case kHaierAcSwingUp: return stdAc::swingv_t::kHighest; + case kHaierAcSwingUp: return stdAc::swingv_t::kHighest; case kHaierAcSwingDown: return stdAc::swingv_t::kLowest; - case kHaierAcSwingOff: return stdAc::swingv_t::kOff; - default: return stdAc::swingv_t::kAuto; + case kHaierAcSwingOff: return stdAc::swingv_t::kOff; + default: return stdAc::swingv_t::kAuto; } } @@ -417,44 +389,44 @@ String IRHaierAC::toString(void) { String result = ""; result.reserve(150); // Reserve some heap for the string to reduce fragging. uint8_t cmd = getCommand(); - result += addIntToString(cmd, F("Command"), false); - result += F(" ("); + result += addIntToString(cmd, kCommandStr, false); + result += kSpaceLBraceStr; switch (cmd) { case kHaierAcCmdOff: - result += F("Off"); + result += kOffStr; break; case kHaierAcCmdOn: - result += F("On"); + result += kOnStr; break; case kHaierAcCmdMode: - result += F("Mode"); + result += kModeStr; break; case kHaierAcCmdFan: - result += F("Fan"); + result += kFanStr; break; case kHaierAcCmdTempUp: - result += F("Temp Up"); + result += kTempUpStr; break; case kHaierAcCmdTempDown: - result += F("Temp Down"); + result += kTempDownStr; break; case kHaierAcCmdSleep: - result += F("Sleep"); + result += kSleepStr; break; case kHaierAcCmdTimerSet: - result += F("Timer Set"); + result += kTimerStr + ' ' + kSetStr; break; case kHaierAcCmdTimerCancel: - result += F("Timer Cancel"); + result += kTimerStr + ' ' + kCancelStr; break; case kHaierAcCmdHealth: - result += F("Health"); + result += kHealthStr; break; case kHaierAcCmdSwing: - result += F("Swing"); + result += kSwingStr; break; default: - result += F("Unknown"); + result += kUnknownStr; } result += ')'; result += addModeToString(getMode(), kHaierAcAuto, kHaierAcCool, kHaierAcHeat, @@ -462,33 +434,33 @@ String IRHaierAC::toString(void) { result += addTempToString(getTemp()); result += addFanToString(getFan(), kHaierAcFanHigh, kHaierAcFanLow, kHaierAcFanAuto, kHaierAcFanAuto, kHaierAcFanMed); - result += addIntToString(getSwing(), F("Swing")); - result += F(" ("); + result += addIntToString(getSwing(), kSwingStr); + result += kSpaceLBraceStr; switch (getSwing()) { case kHaierAcSwingOff: - result += F("Off"); + result += kOffStr; break; case kHaierAcSwingUp: - result += F("Up"); + result += kUpStr; break; case kHaierAcSwingDown: - result += F("Down"); + result += kDownStr; break; case kHaierAcSwingChg: - result += F("Chg"); + result += kChangeStr; break; default: - result += F("Unknown"); + result += kUnknownStr; } result += ')'; - result += addBoolToString(getSleep(), F("Sleep")); - result += addBoolToString(getHealth(), F("Health")); - result += addLabeledString(minsToString(getCurrTime()), F("Current Time")); + result += addBoolToString(getSleep(), kSleepStr); + result += addBoolToString(getHealth(), kHealthStr); + result += addLabeledString(minsToString(getCurrTime()), kClockStr); result += addLabeledString( - getOnTimer() >= 0 ? minsToString(getOnTimer()) : F("Off"), F("On Timer")); + getOnTimer() >= 0 ? minsToString(getOnTimer()) : kOffStr, kOnTimerStr); result += addLabeledString( - getOffTimer() >= 0 ? minsToString(getOffTimer()) : F("Off"), - F("Off Timer")); + getOffTimer() >= 0 ? minsToString(getOffTimer()) : kOffStr, + kOffTimerStr); return result; } // End of IRHaierAC class. @@ -502,8 +474,7 @@ void IRHaierACYRW02::begin(void) { _irsend.begin(); } #if SEND_HAIER_AC_YRW02 void IRHaierACYRW02::send(const uint16_t repeat) { - checksum(); - _irsend.sendHaierACYRW02(remote_state, kHaierACYRW02StateLength, repeat); + _irsend.sendHaierACYRW02(getRaw(), kHaierACYRW02StateLength, repeat); } #endif // SEND_HAIER_AC_YRW02 @@ -537,9 +508,7 @@ uint8_t* IRHaierACYRW02::getRaw(void) { } void IRHaierACYRW02::setRaw(const uint8_t new_code[]) { - for (uint8_t i = 0; i < kHaierACYRW02StateLength; i++) { - remote_state[i] = new_code[i]; - } + memcpy(remote_state, new_code, kHaierACYRW02StateLength); } void IRHaierACYRW02::setButton(uint8_t button) { @@ -553,13 +522,12 @@ void IRHaierACYRW02::setButton(uint8_t button) { case kHaierAcYrw02ButtonHealth: case kHaierAcYrw02ButtonTurbo: case kHaierAcYrw02ButtonSleep: - remote_state[12] &= 0b11110000; - remote_state[12] |= (button & 0b00001111); + setBits(&remote_state[12], kLowNibble, kNibbleSize, button); } } uint8_t IRHaierACYRW02::getButton(void) { - return remote_state[12] & 0b00001111; + return GETBITS8(remote_state[12], kLowNibble, kNibbleSize); } void IRHaierACYRW02::setMode(uint8_t mode) { @@ -570,16 +538,15 @@ void IRHaierACYRW02::setMode(uint8_t mode) { case kHaierAcYrw02Cool: case kHaierAcYrw02Dry: case kHaierAcYrw02Heat: - case kHaierAcYrw02Fan: - break; - default: // If unexpected, default to auto mode. - new_mode = kHaierAcYrw02Auto; + case kHaierAcYrw02Fan: break; + default: new_mode = kHaierAcYrw02Auto; // Unexpected, default to auto mode. } - remote_state[7] &= 0b0001111; - remote_state[7] |= (new_mode << 4); + setBits(&remote_state[7], kHaierAcYrw02ModeOffset, kModeBitsSize, new_mode); } -uint8_t IRHaierACYRW02::getMode(void) { return remote_state[7] >> 4; } +uint8_t IRHaierACYRW02::getMode(void) { + return GETBITS8(remote_state[7], kHaierAcYrw02ModeOffset, kModeBitsSize); +} void IRHaierACYRW02::setTemp(const uint8_t celsius) { uint8_t temp = celsius; @@ -594,33 +561,29 @@ void IRHaierACYRW02::setTemp(const uint8_t celsius) { setButton(kHaierAcYrw02ButtonTempDown); else setButton(kHaierAcYrw02ButtonTempUp); - - remote_state[1] &= 0b00001111; // Clear the previous temp. - remote_state[1] |= ((temp - kHaierAcMinTemp) << 4); + setBits(&remote_state[1], kHighNibble, kNibbleSize, temp - kHaierAcMinTemp); } uint8_t IRHaierACYRW02::getTemp(void) { - return ((remote_state[1] & 0b11110000) >> 4) + kHaierAcMinTemp; + return GETBITS8(remote_state[1], kHighNibble, kNibbleSize) + kHaierAcMinTemp; } void IRHaierACYRW02::setHealth(const bool on) { setButton(kHaierAcYrw02ButtonHealth); - remote_state[3] &= 0b11111101; - remote_state[3] |= (on << 1); + setBit(&remote_state[3], kHaierAcYrw02HealthOffset, on); } -bool IRHaierACYRW02::getHealth(void) { return remote_state[3] & 0b00000010; } +bool IRHaierACYRW02::getHealth(void) { + return GETBIT8(remote_state[3], kHaierAcYrw02HealthOffset); +} bool IRHaierACYRW02::getPower(void) { - return remote_state[4] & kHaierAcYrw02Power; + return GETBIT8(remote_state[4], kHaierAcYrw02PowerOffset); } void IRHaierACYRW02::setPower(const bool on) { setButton(kHaierAcYrw02ButtonPower); - if (on) - remote_state[4] |= kHaierAcYrw02Power; - else - remote_state[4] &= ~kHaierAcYrw02Power; + setBit(&remote_state[4], kHaierAcYrw02PowerOffset, on); } void IRHaierACYRW02::on(void) { setPower(true); } @@ -628,31 +591,34 @@ void IRHaierACYRW02::on(void) { setPower(true); } void IRHaierACYRW02::off(void) { setPower(false); } bool IRHaierACYRW02::getSleep(void) { - return remote_state[8] & kHaierAcYrw02Sleep; + return GETBIT8(remote_state[8], kHaierAcYrw02SleepOffset); } void IRHaierACYRW02::setSleep(const bool on) { setButton(kHaierAcYrw02ButtonSleep); - if (on) - remote_state[8] |= kHaierAcYrw02Sleep; - else - remote_state[8] &= ~kHaierAcYrw02Sleep; + setBit(&remote_state[8], kHaierAcYrw02SleepOffset, on); } -uint8_t IRHaierACYRW02::getTurbo(void) { return remote_state[6] >> 6; } +uint8_t IRHaierACYRW02::getTurbo(void) { + return GETBITS8(remote_state[6], kHaierAcYrw02TurboOffset, + kHaierAcYrw02TurboSize); +} void IRHaierACYRW02::setTurbo(uint8_t speed) { switch (speed) { case kHaierAcYrw02TurboOff: case kHaierAcYrw02TurboLow: case kHaierAcYrw02TurboHigh: - remote_state[6] &= 0b00111111; - remote_state[6] |= (speed << 6); + setBits(&remote_state[6], kHaierAcYrw02TurboOffset, + kHaierAcYrw02TurboSize, speed); setButton(kHaierAcYrw02ButtonTurbo); } } -uint8_t IRHaierACYRW02::getFan(void) { return remote_state[5] >> 4; } +uint8_t IRHaierACYRW02::getFan(void) { + return GETBITS8(remote_state[5], kHaierAcYrw02FanOffset, + kHaierAcYrw02FanSize); +} void IRHaierACYRW02::setFan(uint8_t speed) { switch (speed) { @@ -660,54 +626,44 @@ void IRHaierACYRW02::setFan(uint8_t speed) { case kHaierAcYrw02FanMed: case kHaierAcYrw02FanHigh: case kHaierAcYrw02FanAuto: - remote_state[5] &= 0b00001111; - remote_state[5] |= (speed << 4); + setBits(&remote_state[5], kHaierAcYrw02FanOffset, kHaierAcYrw02FanSize, + speed); setButton(kHaierAcYrw02ButtonFan); } } -uint8_t IRHaierACYRW02::getSwing(void) { return remote_state[1] & 0b00001111; } +uint8_t IRHaierACYRW02::getSwing(void) { + return GETBITS8(remote_state[1], kLowNibble, kNibbleSize); +} -void IRHaierACYRW02::setSwing(uint8_t state) { - uint8_t newstate = state; - switch (state) { +void IRHaierACYRW02::setSwing(uint8_t pos) { + uint8_t newpos = pos; + switch (pos) { case kHaierAcYrw02SwingOff: case kHaierAcYrw02SwingAuto: case kHaierAcYrw02SwingTop: case kHaierAcYrw02SwingMiddle: case kHaierAcYrw02SwingBottom: - case kHaierAcYrw02SwingDown: - setButton(kHaierAcYrw02ButtonSwing); - break; - default: - return; // Unexpected value so don't do anything. + case kHaierAcYrw02SwingDown: setButton(kHaierAcYrw02ButtonSwing); break; + default: return; // Unexpected value so don't do anything. } - // Heat mode has no MIDDLE setting, use BOTTOM instead. - if (state == kHaierAcYrw02SwingMiddle && getMode() == kHaierAcYrw02Heat) - newstate = kHaierAcYrw02SwingBottom; - + if (pos == kHaierAcYrw02SwingMiddle && getMode() == kHaierAcYrw02Heat) + newpos = kHaierAcYrw02SwingBottom; // BOTTOM is only allowed if we are in Heat mode, otherwise MIDDLE. - if (state == kHaierAcYrw02SwingBottom && getMode() != kHaierAcYrw02Heat) - newstate = kHaierAcYrw02SwingMiddle; - - remote_state[1] &= 0b11110000; - remote_state[1] |= newstate; + if (pos == kHaierAcYrw02SwingBottom && getMode() != kHaierAcYrw02Heat) + newpos = kHaierAcYrw02SwingMiddle; + setBits(&remote_state[1], kLowNibble, kNibbleSize, newpos); } // Convert a standard A/C mode into its native mode. uint8_t IRHaierACYRW02::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kHaierAcYrw02Cool; - case stdAc::opmode_t::kHeat: - return kHaierAcYrw02Heat; - case stdAc::opmode_t::kDry: - return kHaierAcYrw02Dry; - case stdAc::opmode_t::kFan: - return kHaierAcYrw02Fan; - default: - return kHaierAcYrw02Auto; + case stdAc::opmode_t::kCool: return kHaierAcYrw02Cool; + case stdAc::opmode_t::kHeat: return kHaierAcYrw02Heat; + case stdAc::opmode_t::kDry: return kHaierAcYrw02Dry; + case stdAc::opmode_t::kFan: return kHaierAcYrw02Fan; + default: return kHaierAcYrw02Auto; } } @@ -715,15 +671,11 @@ uint8_t IRHaierACYRW02::convertMode(const stdAc::opmode_t mode) { uint8_t IRHaierACYRW02::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kHaierAcYrw02FanLow; - case stdAc::fanspeed_t::kMedium: - return kHaierAcYrw02FanMed; + case stdAc::fanspeed_t::kLow: return kHaierAcYrw02FanLow; + case stdAc::fanspeed_t::kMedium: return kHaierAcYrw02FanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kHaierAcYrw02FanHigh; - default: - return kHaierAcYrw02FanAuto; + case stdAc::fanspeed_t::kMax: return kHaierAcYrw02FanHigh; + default: return kHaierAcYrw02FanAuto; } } @@ -731,18 +683,12 @@ uint8_t IRHaierACYRW02::convertFan(const stdAc::fanspeed_t speed) { uint8_t IRHaierACYRW02::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 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; } } @@ -751,9 +697,9 @@ stdAc::opmode_t IRHaierACYRW02::toCommonMode(const uint8_t mode) { switch (mode) { case kHaierAcYrw02Cool: return stdAc::opmode_t::kCool; case kHaierAcYrw02Heat: return stdAc::opmode_t::kHeat; - case kHaierAcYrw02Dry: return stdAc::opmode_t::kDry; - case kHaierAcYrw02Fan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kHaierAcYrw02Dry: return stdAc::opmode_t::kDry; + case kHaierAcYrw02Fan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -761,21 +707,21 @@ stdAc::opmode_t IRHaierACYRW02::toCommonMode(const uint8_t mode) { stdAc::fanspeed_t IRHaierACYRW02::toCommonFanSpeed(const uint8_t speed) { switch (speed) { case kHaierAcYrw02FanHigh: return stdAc::fanspeed_t::kMax; - case kHaierAcYrw02FanMed: return stdAc::fanspeed_t::kMedium; - case kHaierAcYrw02FanLow: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kHaierAcYrw02FanMed: return stdAc::fanspeed_t::kMedium; + case kHaierAcYrw02FanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } // Convert a native vertical swing to it's common equivalent. stdAc::swingv_t IRHaierACYRW02::toCommonSwingV(const uint8_t pos) { switch (pos) { - case kHaierAcYrw02SwingTop: return stdAc::swingv_t::kHighest; + case kHaierAcYrw02SwingTop: return stdAc::swingv_t::kHighest; case kHaierAcYrw02SwingMiddle: return stdAc::swingv_t::kMiddle; - case kHaierAcYrw02SwingDown: return stdAc::swingv_t::kLow; + case kHaierAcYrw02SwingDown: return stdAc::swingv_t::kLow; case kHaierAcYrw02SwingBottom: return stdAc::swingv_t::kLowest; - case kHaierAcYrw02SwingOff: return stdAc::swingv_t::kOff; - default: return stdAc::swingv_t::kAuto; + case kHaierAcYrw02SwingOff: return stdAc::swingv_t::kOff; + default: return stdAc::swingv_t::kAuto; } } @@ -808,40 +754,40 @@ stdAc::state_t IRHaierACYRW02::toCommon(void) { String IRHaierACYRW02::toString(void) { String result = ""; result.reserve(130); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); uint8_t cmd = getButton(); - result += addIntToString(cmd, F("Button")); - result += F(" ("); + result += addIntToString(cmd, kButtonStr); + result += kSpaceLBraceStr; switch (cmd) { case kHaierAcYrw02ButtonPower: - result += F("Power"); + result += kPowerStr; break; case kHaierAcYrw02ButtonMode: - result += F("Mode"); + result += kModeStr; break; case kHaierAcYrw02ButtonFan: - result += F("Fan"); + result += kFanStr; break; case kHaierAcYrw02ButtonTempUp: - result += F("Temp Up"); + result += kTempUpStr; break; case kHaierAcYrw02ButtonTempDown: - result += F("Temp Down"); + result += kTempDownStr; break; case kHaierAcYrw02ButtonSleep: - result += F("Sleep"); + result += kSleepStr; break; case kHaierAcYrw02ButtonHealth: - result += "Health"; + result += kHealthStr; break; case kHaierAcYrw02ButtonSwing: - result += F("Swing"); + result += kSwingStr; break; case kHaierAcYrw02ButtonTurbo: - result += F("Turbo"); + result += kTurboStr; break; default: - result += F("Unknown"); + result += kUnknownStr; } result += ')'; result += addModeToString(getMode(), kHaierAcYrw02Auto, kHaierAcYrw02Cool, @@ -851,49 +797,49 @@ String IRHaierACYRW02::toString(void) { result += addFanToString(getFan(), kHaierAcYrw02FanHigh, kHaierAcYrw02FanLow, kHaierAcYrw02FanAuto, kHaierAcYrw02FanAuto, kHaierAcYrw02FanMed); - result += addIntToString(getTurbo(), F("Turbo")); - result += F(" ("); + result += addIntToString(getTurbo(), kTurboStr); + result += kSpaceLBraceStr; switch (getTurbo()) { case kHaierAcYrw02TurboOff: - result += F("Off"); + result += kOffStr; break; case kHaierAcYrw02TurboLow: - result += F("Low"); + result += kLowStr; break; case kHaierAcYrw02TurboHigh: - result += F("High"); + result += kHighStr; break; default: - result += F("Unknown"); + result += kUnknownStr; } result += ')'; - result += addIntToString(getSwing(), F("Swing")); - result += F(" ("); + result += addIntToString(getSwing(), kSwingStr); + result += kSpaceLBraceStr; switch (getSwing()) { case kHaierAcYrw02SwingOff: - result += F("Off"); + result += kOffStr; break; case kHaierAcYrw02SwingAuto: - result += F("Auto"); + result += kAutoStr; break; case kHaierAcYrw02SwingBottom: - result += F("Bottom"); + result += kLowestStr; break; case kHaierAcYrw02SwingDown: - result += F("Down"); + result += kLowStr; break; case kHaierAcYrw02SwingTop: - result += F("Top"); + result += kHighestStr; break; case kHaierAcYrw02SwingMiddle: - result += F("Middle"); + result += kMiddleStr; break; default: - result += F("Unknown"); + result += kUnknownStr; } result += ')'; - result += addBoolToString(getSleep(), F("Sleep")); - result += addBoolToString(getHealth(), F("Health")); + result += addBoolToString(getSleep(), kSleepStr); + result += addBoolToString(getHealth(), kHealthStr); return result; } // End of IRHaierACYRW02 class. diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Haier.h b/lib/IRremoteESP8266-2.7.0/src/ir_Haier.h old mode 100755 new mode 100644 similarity index 80% rename from lib/IRremoteESP8266-2.6.5/src/ir_Haier.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Haier.h index ea5f67ab3..587c4c560 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Haier.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Haier.h @@ -34,26 +34,37 @@ const uint8_t kHaierAcPrefix = 0b10100101; const uint8_t kHaierAcMinTemp = 16; const uint8_t kHaierAcDefTemp = 25; const uint8_t kHaierAcMaxTemp = 30; -const uint8_t kHaierAcCmdOff = 0b00000000; -const uint8_t kHaierAcCmdOn = 0b00000001; -const uint8_t kHaierAcCmdMode = 0b00000010; -const uint8_t kHaierAcCmdFan = 0b00000011; -const uint8_t kHaierAcCmdTempUp = 0b00000110; -const uint8_t kHaierAcCmdTempDown = 0b00000111; -const uint8_t kHaierAcCmdSleep = 0b00001000; -const uint8_t kHaierAcCmdTimerSet = 0b00001001; -const uint8_t kHaierAcCmdTimerCancel = 0b00001010; -const uint8_t kHaierAcCmdHealth = 0b00001100; -const uint8_t kHaierAcCmdSwing = 0b00001101; +const uint8_t kHaierAcCmdOff = 0b0000; +const uint8_t kHaierAcCmdOn = 0b0001; +const uint8_t kHaierAcCmdMode = 0b0010; +const uint8_t kHaierAcCmdFan = 0b0011; +const uint8_t kHaierAcCmdTempUp = 0b0110; +const uint8_t kHaierAcCmdTempDown = 0b0111; +const uint8_t kHaierAcCmdSleep = 0b1000; +const uint8_t kHaierAcCmdTimerSet = 0b1001; +const uint8_t kHaierAcCmdTimerCancel = 0b1010; +const uint8_t kHaierAcCmdHealth = 0b1100; +const uint8_t kHaierAcCmdSwing = 0b1101; -// Byte 2 -const uint8_t kHaierAcSwingOff = 0b00000000; -const uint8_t kHaierAcSwingUp = 0b00000001; -const uint8_t kHaierAcSwingDown = 0b00000010; -const uint8_t kHaierAcSwingChg = 0b00000011; +// Byte 2 (Clock Hours) -// Byte 6 -const uint8_t kHaierAcModeMask = 0b11100000; +// Byte 3 (Timer Flags & Clock Minutes) +const uint8_t kHaierAcOffTimerOffset = 6; +const uint8_t kHaierAcOnTimerOffset = 7; + +// Byte 4 (Health & Off Time Hours) +const uint8_t kHaierAcHealthBitOffset = 5; + +// Byte 5 (Swing & Off Time Mins) +const uint8_t kHaierAcSwingOffset = 6; +const uint8_t kHaierAcSwingSize = 2; // Bits +const uint8_t kHaierAcSwingOff = 0b00; +const uint8_t kHaierAcSwingUp = 0b01; +const uint8_t kHaierAcSwingDown = 0b10; +const uint8_t kHaierAcSwingChg = 0b11; + +// Byte 6 (Mode & On Time Hours) +const uint8_t kHaierAcModeOffset = 5; const uint8_t kHaierAcAuto = 0; const uint8_t kHaierAcCool = 1; const uint8_t kHaierAcDry = 2; @@ -65,9 +76,17 @@ const uint8_t kHaierAcFanLow = 1; const uint8_t kHaierAcFanMed = 2; const uint8_t kHaierAcFanHigh = 3; +// Byte 7 (On Time Minutes) + +// Time +const uint8_t kHaierAcTimeOffset = 0; // Bits +const uint8_t kHaierAcHoursSize = 5; // Bits +const uint8_t kHaierAcMinsSize = 6; // Bits + const uint16_t kHaierAcMaxTime = (23 * 60) + 59; // Byte 7 +const uint8_t kHaierAcSleepBitOffset = 6; const uint8_t kHaierAcSleepBit = 0b01000000; // Legacy Haier AC defines. @@ -104,9 +123,9 @@ const uint8_t kHaierAcSleepBit = 0b01000000; const uint8_t kHaierAcYrw02Prefix = 0xA6; // Byte 1 -// Bits 0-3 +// High Nibble - Temperature // 0x0 = 16DegC, ... 0xE = 30DegC -// Bits 4-7 - Swing +// Low Nibble - Swing const uint8_t kHaierAcYrw02SwingOff = 0x0; const uint8_t kHaierAcYrw02SwingTop = 0x1; const uint8_t kHaierAcYrw02SwingMiddle = 0x2; // Not available in heat mode. @@ -115,33 +134,39 @@ const uint8_t kHaierAcYrw02SwingDown = 0xA; const uint8_t kHaierAcYrw02SwingAuto = 0xC; // Airflow // Byte 3 -// Bit 7 - Health mode +const uint8_t kHaierAcYrw02HealthOffset = 1; // Byte 4 +const uint8_t kHaierAcYrw02PowerOffset = 6; const uint8_t kHaierAcYrw02Power = 0b01000000; // Byte 5 // Bits 0-3 -const uint8_t kHaierAcYrw02FanHigh = 0x2; -const uint8_t kHaierAcYrw02FanMed = 0x4; -const uint8_t kHaierAcYrw02FanLow = 0x6; -const uint8_t kHaierAcYrw02FanAuto = 0xA; +const uint8_t kHaierAcYrw02FanOffset = 5; +const uint8_t kHaierAcYrw02FanSize = 3; +const uint8_t kHaierAcYrw02FanHigh = 0b001; +const uint8_t kHaierAcYrw02FanMed = 0b010; +const uint8_t kHaierAcYrw02FanLow = 0b011; +const uint8_t kHaierAcYrw02FanAuto = 0b101; // Byte 6 -// Bits 0-1 +const uint8_t kHaierAcYrw02TurboOffset = 6; +const uint8_t kHaierAcYrw02TurboSize = 2; const uint8_t kHaierAcYrw02TurboOff = 0x0; const uint8_t kHaierAcYrw02TurboHigh = 0x1; const uint8_t kHaierAcYrw02TurboLow = 0x2; // Byte 7 -// Bits 0-3 -const uint8_t kHaierAcYrw02Auto = 0x0; -const uint8_t kHaierAcYrw02Cool = 0x2; -const uint8_t kHaierAcYrw02Dry = 0x4; -const uint8_t kHaierAcYrw02Heat = 0x8; -const uint8_t kHaierAcYrw02Fan = 0xC; +// Mode mask 0b11100000 +const uint8_t kHaierAcYrw02ModeOffset = 5; +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 // Byte 8 +const uint8_t kHaierAcYrw02SleepOffset = 7; const uint8_t kHaierAcYrw02Sleep = 0b10000000; // Byte 12 diff --git a/lib/IRremoteESP8266-2.7.0/src/ir_Hitachi.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Hitachi.cpp new file mode 100644 index 000000000..6fe776362 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Hitachi.cpp @@ -0,0 +1,753 @@ +// Copyright 2018-2019 David Conran +// +// Code to emulate Hitachi protocol compatible devices. +// Should be compatible with: +// * Hitachi RAS-35THA6 remote +// + +#include "ir_Hitachi.h" +#include +#include +#ifndef ARDUINO +#include +#endif +#include "IRrecv.h" +#include "IRremoteESP8266.h" +#include "IRsend.h" +#include "IRtext.h" +#include "IRutils.h" + +// Constants +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/417 +const uint16_t kHitachiAcHdrMark = 3300; +const uint16_t kHitachiAcHdrSpace = 1700; +const uint16_t kHitachiAc1HdrMark = 3400; +const uint16_t kHitachiAc1HdrSpace = 3400; +const uint16_t kHitachiAcBitMark = 400; +const uint16_t kHitachiAcOneSpace = 1250; +const uint16_t kHitachiAcZeroSpace = 500; +const uint32_t kHitachiAcMinGap = kDefaultMessageGap; // Just a guess. +// Support for HitachiAc424 protocol +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/973 +const uint16_t kHitachiAc424LdrMark = 29784; // Leader +const uint16_t kHitachiAc424LdrSpace = 49290; // Leader +const uint16_t kHitachiAc424HdrMark = 3416; // Header +const uint16_t kHitachiAc424HdrSpace = 1604; // Header +const uint16_t kHitachiAc424BitMark = 463; +const uint16_t kHitachiAc424OneSpace = 1208; +const uint16_t kHitachiAc424ZeroSpace = 372; + +using irutils::addBoolToString; +using irutils::addIntToString; +using irutils::addLabeledString; +using irutils::addModeToString; +using irutils::addFanToString; +using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; + +#if (SEND_HITACHI_AC || SEND_HITACHI_AC2) +// Send a Hitachi A/C message. +// +// Args: +// data: An array of bytes containing the IR command. +// nbytes: Nr. of bytes of data in the array. (>=kHitachiAcStateLength) +// repeat: Nr. of times the message is to be repeated. (Default = 0). +// +// Status: ALPHA / Untested. +// +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/417 +void IRsend::sendHitachiAC(const unsigned char data[], const uint16_t nbytes, + const uint16_t repeat) { + if (nbytes < kHitachiAcStateLength) + return; // Not enough bytes to send a proper message. + sendGeneric(kHitachiAcHdrMark, kHitachiAcHdrSpace, kHitachiAcBitMark, + kHitachiAcOneSpace, kHitachiAcBitMark, kHitachiAcZeroSpace, + kHitachiAcBitMark, kHitachiAcMinGap, data, nbytes, 38, true, + repeat, 50); +} +#endif // (SEND_HITACHI_AC || SEND_HITACHI_AC2) + +#if SEND_HITACHI_AC1 +// Send a Hitachi A/C 13-byte message. +// +// For devices: +// Hitachi A/C Series VI (Circa 2007) / Remote: LT0541-HTA +// +// Args: +// data: An array of bytes containing the IR command. +// nbytes: Nr. of bytes of data in the array. (>=kHitachiAc1StateLength) +// repeat: Nr. of times the message is to be repeated. (Default = 0). +// +// Status: BETA / Appears to work. +// +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/453 +// Basically the same as sendHitatchiAC() except different size and header. +void IRsend::sendHitachiAC1(const unsigned char data[], const uint16_t nbytes, + const uint16_t repeat) { + if (nbytes < kHitachiAc1StateLength) + return; // Not enough bytes to send a proper message. + sendGeneric(kHitachiAc1HdrMark, kHitachiAc1HdrSpace, kHitachiAcBitMark, + kHitachiAcOneSpace, kHitachiAcBitMark, kHitachiAcZeroSpace, + kHitachiAcBitMark, kHitachiAcMinGap, data, nbytes, kHitachiAcFreq, + true, repeat, kDutyDefault); +} +#endif // SEND_HITACHI_AC1 + +#if SEND_HITACHI_AC2 +// Send a Hitachi A/C 53-byte message. +// +// For devices: +// Hitachi A/C Series VI (Circa 2007) / Remote: LT0541-HTA +// +// Args: +// data: An array of bytes containing the IR command. +// nbytes: Nr. of bytes of data in the array. (>=kHitachiAc2StateLength) +// repeat: Nr. of times the message is to be repeated. (Default = 0). +// +// Status: BETA / Appears to work. +// +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/417 +// Basically the same as sendHitatchiAC() except different size. +void IRsend::sendHitachiAC2(const unsigned char data[], const uint16_t nbytes, + const uint16_t repeat) { + if (nbytes < kHitachiAc2StateLength) + return; // Not enough bytes to send a proper message. + sendHitachiAC(data, nbytes, repeat); +} +#endif // SEND_HITACHI_AC2 + +// Class for handling the remote control on a Hitachi 28 byte A/C message. +// Inspired by: +// https://github.com/ToniA/arduino-heatpumpir/blob/master/HitachiHeatpumpIR.cpp + +IRHitachiAc::IRHitachiAc(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { stateReset(); } + +void IRHitachiAc::stateReset(void) { + remote_state[0] = 0x80; + remote_state[1] = 0x08; + remote_state[2] = 0x0C; + remote_state[3] = 0x02; + remote_state[4] = 0xFD; + remote_state[5] = 0x80; + remote_state[6] = 0x7F; + remote_state[7] = 0x88; + remote_state[8] = 0x48; + remote_state[9] = 0x10; + for (uint8_t i = 10; i < kHitachiAcStateLength; i++) remote_state[i] = 0x00; + remote_state[14] = 0x60; + remote_state[15] = 0x60; + remote_state[24] = 0x80; + setTemp(23); +} + +void IRHitachiAc::begin(void) { _irsend.begin(); } + +uint8_t IRHitachiAc::calcChecksum(const uint8_t state[], + const uint16_t length) { + uint8_t sum = 62; + for (uint16_t i = 0; i < length - 1; i++) sum -= reverseBits(state[i], 8); + return reverseBits(sum, 8); +} + +void IRHitachiAc::checksum(const uint16_t length) { + remote_state[length - 1] = calcChecksum(remote_state, length); +} + +bool IRHitachiAc::validChecksum(const uint8_t state[], const uint16_t length) { + if (length < 2) return true; // Assume true for lengths that are too short. + return (state[length - 1] == calcChecksum(state, length)); +} + +uint8_t *IRHitachiAc::getRaw(void) { + checksum(); + return remote_state; +} + +void IRHitachiAc::setRaw(const uint8_t new_code[], const uint16_t length) { + memcpy(remote_state, new_code, std::min(length, kHitachiAcStateLength)); +} + +#if SEND_HITACHI_AC +void IRHitachiAc::send(const uint16_t repeat) { + _irsend.sendHitachiAC(getRaw(), kHitachiAcStateLength, repeat); +} +#endif // SEND_HITACHI_AC + +bool IRHitachiAc::getPower(void) { + return GETBIT8(remote_state[17], kHitachiAcPowerOffset); +} + +void IRHitachiAc::setPower(const bool on) { + setBit(&remote_state[17], kHitachiAcPowerOffset, on); +} + +void IRHitachiAc::on(void) { setPower(true); } + +void IRHitachiAc::off(void) { setPower(false); } + +uint8_t IRHitachiAc::getMode(void) { return reverseBits(remote_state[10], 8); } + +void IRHitachiAc::setMode(const uint8_t mode) { + uint8_t newmode = mode; + switch (mode) { + // Fan mode sets a special temp. + case kHitachiAcFan: setTemp(64); break; + case kHitachiAcAuto: + case kHitachiAcHeat: + case kHitachiAcCool: + case kHitachiAcDry: break; + default: newmode = kHitachiAcAuto; + } + remote_state[10] = reverseBits(newmode, 8); + if (mode != kHitachiAcFan) setTemp(_previoustemp); + setFan(getFan()); // Reset the fan speed after the mode change. +} + +uint8_t IRHitachiAc::getTemp(void) { + return reverseBits(remote_state[11], 8) >> 1; +} + +void IRHitachiAc::setTemp(const uint8_t celsius) { + uint8_t temp; + if (celsius != 64) _previoustemp = celsius; + switch (celsius) { + case 64: + temp = celsius; + break; + default: + temp = std::min(celsius, kHitachiAcMaxTemp); + temp = std::max(temp, kHitachiAcMinTemp); + } + remote_state[11] = reverseBits(temp << 1, 8); + if (temp == kHitachiAcMinTemp) + remote_state[9] = 0x90; + else + remote_state[9] = 0x10; +} + +uint8_t IRHitachiAc::getFan(void) { return reverseBits(remote_state[13], 8); } + +void IRHitachiAc::setFan(const uint8_t speed) { + uint8_t fanmin = kHitachiAcFanAuto; + uint8_t fanmax = kHitachiAcFanHigh; + switch (getMode()) { + case kHitachiAcDry: // Only 2 x low speeds in Dry mode. + fanmin = kHitachiAcFanLow; + fanmax = kHitachiAcFanLow + 1; + break; + case kHitachiAcFan: + fanmin = kHitachiAcFanLow; // No Auto in Fan mode. + break; + } + uint8_t newspeed = std::max(speed, fanmin); + newspeed = std::min(newspeed, fanmax); + remote_state[13] = reverseBits(newspeed, 8); +} + +bool IRHitachiAc::getSwingVertical(void) { + return GETBIT8(remote_state[14], kHitachiAcSwingOffset); +} + +void IRHitachiAc::setSwingVertical(const bool on) { + setBit(&remote_state[14], kHitachiAcSwingOffset, on); +} + +bool IRHitachiAc::getSwingHorizontal(void) { + return GETBIT8(remote_state[15], kHitachiAcSwingOffset); +} + +void IRHitachiAc::setSwingHorizontal(const bool on) { + setBit(&remote_state[15], kHitachiAcSwingOffset, on); +} + +// Convert a standard A/C mode into its native mode. +uint8_t IRHitachiAc::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: return kHitachiAcCool; + case stdAc::opmode_t::kHeat: return kHitachiAcHeat; + case stdAc::opmode_t::kDry: return kHitachiAcDry; + case stdAc::opmode_t::kFan: return kHitachiAcFan; + default: return kHitachiAcAuto; + } +} + +// Convert a standard A/C Fan speed into its native fan speed. +uint8_t IRHitachiAc::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: + case stdAc::fanspeed_t::kLow: return kHitachiAcFanLow; + case stdAc::fanspeed_t::kMedium: return kHitachiAcFanLow + 1; + case stdAc::fanspeed_t::kHigh: return kHitachiAcFanHigh - 1; + case stdAc::fanspeed_t::kMax: return kHitachiAcFanHigh; + default: return kHitachiAcFanAuto; + } +} + +// Convert a native mode to it's common equivalent. +stdAc::opmode_t IRHitachiAc::toCommonMode(const uint8_t mode) { + switch (mode) { + case kHitachiAcCool: return stdAc::opmode_t::kCool; + case kHitachiAcHeat: return stdAc::opmode_t::kHeat; + case kHitachiAcDry: return stdAc::opmode_t::kDry; + case kHitachiAcFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; + } +} + +// Convert a native fan speed to it's common equivalent. +stdAc::fanspeed_t IRHitachiAc::toCommonFanSpeed(const uint8_t speed) { + switch (speed) { + case kHitachiAcFanHigh: return stdAc::fanspeed_t::kMax; + case kHitachiAcFanHigh - 1: return stdAc::fanspeed_t::kHigh; + case kHitachiAcFanLow + 1: return stdAc::fanspeed_t::kMedium; + case kHitachiAcFanLow: return stdAc::fanspeed_t::kLow; + default: return stdAc::fanspeed_t::kAuto; + } +} + +// Convert the A/C state to it's common equivalent. +stdAc::state_t IRHitachiAc::toCommon(void) { + stdAc::state_t result; + result.protocol = decode_type_t::HITACHI_AC; + result.model = -1; // No models used. + result.power = this->getPower(); + result.mode = this->toCommonMode(this->getMode()); + result.celsius = true; + result.degrees = this->getTemp(); + result.fanspeed = this->toCommonFanSpeed(this->getFan()); + result.swingv = this->getSwingVertical() ? stdAc::swingv_t::kAuto : + stdAc::swingv_t::kOff; + result.swingh = this->getSwingHorizontal() ? stdAc::swingh_t::kAuto : + stdAc::swingh_t::kOff; + // Not supported. + result.quiet = false; + result.turbo = false; + result.clean = false; + result.econo = false; + result.filter = false; + result.light = false; + result.beep = false; + result.sleep = -1; + result.clock = -1; + return result; +} + +// Convert the internal state into a human readable string. +String IRHitachiAc::toString(void) { + String result = ""; + result.reserve(110); // Reserve some heap for the string to reduce fragging. + result += addBoolToString(getPower(), kPowerStr, false); + result += addModeToString(getMode(), kHitachiAcAuto, kHitachiAcCool, + kHitachiAcHeat, kHitachiAcDry, kHitachiAcFan); + result += addTempToString(getTemp()); + result += addFanToString(getFan(), kHitachiAcFanHigh, kHitachiAcFanLow, + kHitachiAcFanAuto, kHitachiAcFanAuto, + kHitachiAcFanMed); + result += addBoolToString(getSwingVertical(), kSwingVStr); + result += addBoolToString(getSwingHorizontal(), kSwingHStr); + return result; +} + +#if (DECODE_HITACHI_AC || DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2) +// Decode the supplied Hitachi A/C message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: The number of data bits to expect. +// Typically kHitachiAcBits, kHitachiAc1Bits, kHitachiAc2Bits +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: ALPHA / Untested. +// +// Supported devices: +// Hitachi A/C Series VI (Circa 2007) / Remote: LT0541-HTA +// +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/417 +// https://github.com/crankyoldgit/IRremoteESP8266/issues/453 +bool IRrecv::decodeHitachiAC(decode_results *results, const uint16_t nbits, + const bool strict) { + const uint8_t k_tolerance = _tolerance + 5; + if (results->rawlen < 2 * nbits + kHeader + kFooter - 1) + return false; // Can't possibly be a valid HitachiAC message. + if (strict) { + switch (nbits) { + case kHitachiAcBits: + case kHitachiAc1Bits: + case kHitachiAc2Bits: + break; // Okay to continue. + default: + return false; // Not strictly a Hitachi message. + } + } + uint16_t offset = kStartOffset; + uint16_t hmark; + uint32_t hspace; + if (nbits == kHitachiAc1Bits) { + hmark = kHitachiAc1HdrMark; + hspace = kHitachiAc1HdrSpace; + } else { + hmark = kHitachiAcHdrMark; + hspace = kHitachiAcHdrSpace; + } + // Match Header + Data + Footer + if (!matchGeneric(results->rawbuf + offset, results->state, + results->rawlen - offset, nbits, + hmark, hspace, + kHitachiAcBitMark, kHitachiAcOneSpace, + kHitachiAcBitMark, kHitachiAcZeroSpace, + kHitachiAcBitMark, kHitachiAcMinGap, true, + k_tolerance)) return false; + + // Compliance + if (strict) { + if (nbits / 8 == kHitachiAcStateLength && + !IRHitachiAc::validChecksum(results->state, kHitachiAcStateLength)) + return false; + } + + // Success + switch (nbits) { + case kHitachiAc1Bits: + results->decode_type = HITACHI_AC1; + break; + case kHitachiAc2Bits: + results->decode_type = HITACHI_AC2; + break; + case kHitachiAcBits: + default: + results->decode_type = HITACHI_AC; + } + 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_HITACHI_AC || DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2) + +#if SEND_HITACHI_AC424 +// Send HITACHI_AC424 messages +// +// Note: This protocol is almost exactly the same as HitachiAC2 except this +// variant has a leader section as well, and subtle timing differences. +// It is also in LSBF order (per byte), rather than MSBF order. +// +// Args: +// data: An array of bytes containing the IR command. +// It is assumed to be in LSBF order for this code. +// nbytes: Nr. of bytes of data in the array. (>=kHitachiAc424StateLength) +// repeat: Nr. of times the message is to be repeated. +// +// Status: STABLE / Reported as working. +void IRsend::sendHitachiAc424(const uint8_t data[], const uint16_t nbytes, + const uint16_t repeat) { + enableIROut(kHitachiAcFreq); + for (uint16_t r = 0; r <= repeat; r++) { + // Leader + mark(kHitachiAc424LdrMark); + space(kHitachiAc424LdrSpace); + // Header + Data + Footer + sendGeneric(kHitachiAc424HdrMark, kHitachiAc424HdrSpace, + kHitachiAc424BitMark, kHitachiAc424OneSpace, + kHitachiAc424BitMark, kHitachiAc424ZeroSpace, + kHitachiAc424BitMark, kHitachiAcMinGap, + data, nbytes, // Bytes + kHitachiAcFreq, false, kNoRepeat, kDutyDefault); + } +} +#endif // SEND_HITACHI_AC424 + +#if DECODE_HITACHI_AC424 +// Decode the supplied Hitachi 424 bit A/C message. +// +// Note: This protocol is almost exactly the same as HitachiAC2 except this +// variant has a leader section as well, and subtle timing differences. +// It is also in LSBF order (per byte), rather than MSBF order. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: The number of data bits to expect. Typically kHitachiAc424Bits. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: STABLE / Reported as working. +// +// Supported devices: +// Hitachi Shirokumakun / AC Model: RAS-AJ25H / AC Remote Model: RAR-8P2 +// Manual (Japanese): +// https://kadenfan.hitachi.co.jp/support/raj/item/docs/ras_aj22h_a_tori.pdf +// +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/973 +bool IRrecv::decodeHitachiAc424(decode_results *results, const uint16_t nbits, + const bool strict) { + if (results->rawlen < 2 * nbits + kHeader + kHeader + kFooter - 1) + return false; // Too short a message to match. + if (strict && nbits != kHitachiAc424Bits) + return false; + + uint16_t offset = kStartOffset; + uint16_t used; + + // Leader + if (!matchMark(results->rawbuf[offset++], kHitachiAc424LdrMark)) + return false; + if (!matchSpace(results->rawbuf[offset++], kHitachiAc424LdrSpace)) + return false; + + // Header + Data + Footer + used = matchGeneric(results->rawbuf + offset, results->state, + results->rawlen - offset, nbits, + kHitachiAc424HdrMark, kHitachiAc424HdrSpace, + kHitachiAc424BitMark, kHitachiAc424OneSpace, + kHitachiAc424BitMark, kHitachiAc424ZeroSpace, + kHitachiAc424BitMark, kHitachiAcMinGap, true, + kUseDefTol, 0, false); + if (used == 0) return false; // We failed to find any data. + + // Success + results->decode_type = decode_type_t::HITACHI_AC424; + results->bits = nbits; + return true; +} +#endif // DECODE_HITACHI_AC424 + +// Class for handling the remote control on a Hitachi_AC424 53 byte A/C message +IRHitachiAc424::IRHitachiAc424(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { stateReset(); } + +// Reset to auto fan, cooling, 23° Celcius +void IRHitachiAc424::stateReset(void) { + for (uint8_t i = 0; i < kHitachiAc424StateLength; i++) + remote_state[i] = 0x00; + + remote_state[0] = 0x01; + remote_state[1] = 0x10; + remote_state[3] = 0x40; + remote_state[5] = 0xFF; + remote_state[7] = 0xCC; + remote_state[11] = 0x13; // Button Action + remote_state[33] = 0x80; + remote_state[35] = 0x03; + remote_state[37] = 0x01; + remote_state[39] = 0x88; + remote_state[45] = 0xFF; + remote_state[47] = 0xFF; + remote_state[49] = 0xFF; + remote_state[51] = 0xFF; + + setTemp(23); + setPower(true); + setMode(kHitachiAc424Cool); + setFan(kHitachiAc424FanAuto); +} + +void IRHitachiAc424::setInvertedStates(void) { + for (uint8_t i = 3; i < kHitachiAc424StateLength - 1; i += 2) + remote_state[i + 1] = ~remote_state[i]; +} + +void IRHitachiAc424::begin(void) { _irsend.begin(); } + +uint8_t *IRHitachiAc424::getRaw(void) { + setInvertedStates(); + return remote_state; +} + +void IRHitachiAc424::setRaw(const uint8_t new_code[], const uint16_t length) { + memcpy(remote_state, new_code, std::min(length, kHitachiAc424StateLength)); +} + +#if SEND_HITACHI_AC424 +void IRHitachiAc424::send(const uint16_t repeat) { + _irsend.sendHitachiAc424(getRaw(), kHitachiAc424StateLength, repeat); +} +#endif // SEND_HITACHI_AC424 + +bool IRHitachiAc424::getPower(void) { + return GETBIT8(remote_state[kHitachiAc424PowerByte], + kHitachiAc424PowerOffset); +} + +void IRHitachiAc424::setPower(const bool on) { + setBit(&remote_state[kHitachiAc424PowerByte], kHitachiAc424PowerOffset, on); +} + +void IRHitachiAc424::on(void) { setPower(true); } + +void IRHitachiAc424::off(void) { setPower(false); } + +uint8_t IRHitachiAc424::getMode(void) { + return GETBITS8(remote_state[kHitachiAc424ModeByte], kLowNibble, kNibbleSize); +} + +void IRHitachiAc424::setMode(const uint8_t mode) { + uint8_t newMode = mode; + switch (mode) { + // Fan mode sets a special temp. + case kHitachiAc424Fan: setTemp(kHitachiAc424FanTemp, false); break; + case kHitachiAc424Heat: + case kHitachiAc424Cool: + case kHitachiAc424Dry: break; + default: newMode = kHitachiAc424Cool; + } + setBits(&remote_state[kHitachiAc424ModeByte], kLowNibble, kNibbleSize, + newMode); + if (newMode != kHitachiAc424Fan) setTemp(_previoustemp); + setFan(getFan()); // Reset the fan speed after the mode change. +} + +uint8_t IRHitachiAc424::getTemp(void) { + return GETBITS8(remote_state[kHitachiAc424TempByte], kHitachiAc424TempOffset, + kHitachiAc424TempSize); +} + +void IRHitachiAc424::setTemp(const uint8_t celsius, bool setPrevious) { + uint8_t temp; + if (setPrevious) _previoustemp = celsius; + temp = std::min(celsius, kHitachiAc424MaxTemp); + temp = std::max(temp, kHitachiAc424MinTemp); + setBits(&remote_state[kHitachiAc424TempByte], kHitachiAc424TempOffset, + kHitachiAc424TempSize, temp); +} + +uint8_t IRHitachiAc424::getFan(void) { + return GETBITS8(remote_state[kHitachiAc424FanByte], kHighNibble, kNibbleSize); +} + +void IRHitachiAc424::setFan(const uint8_t speed) { + uint8_t newSpeed = std::max(speed, kHitachiAc424FanMin); + uint8_t fanMax = kHitachiAc424FanMax; + + // Only 2 x low speeds in Dry mode or Auto + if (getMode() == kHitachiAc424Dry && speed == kHitachiAc424FanAuto) { + fanMax = kHitachiAc424FanAuto; + } else if (getMode() == kHitachiAc424Dry) { + fanMax = kHitachiAc424FanMaxDry; + } else if (getMode() == kHitachiAc424Fan && speed == kHitachiAc424FanAuto) { + // Fan Mode does not have auto. Set to safe low + newSpeed = kHitachiAc424FanMin; + } + + newSpeed = std::min(newSpeed, fanMax); + setBits(&remote_state[kHitachiAc424FanByte], kHighNibble, kNibbleSize, + newSpeed); + remote_state[9] = 0x92; + remote_state[29] = 0x00; + + // When fan is at min/max, additional bytes seem to be set + if (newSpeed == kHitachiAc424FanMin) remote_state[9] = 0x98; + if (newSpeed == kHitachiAc424FanMax) { + remote_state[9] = 0xA9; + remote_state[29] = 0x30; + } +} + +// Convert a standard A/C mode into its native mode. +uint8_t IRHitachiAc424::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: return kHitachiAc424Cool; + case stdAc::opmode_t::kHeat: return kHitachiAc424Heat; + case stdAc::opmode_t::kDry: return kHitachiAc424Dry; + case stdAc::opmode_t::kFan: return kHitachiAc424Fan; + default: return kHitachiAc424Cool; + } +} + +// Convert a standard A/C Fan speed into its native fan speed. +uint8_t IRHitachiAc424::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: return kHitachiAc424FanMin; + case stdAc::fanspeed_t::kLow: return kHitachiAc424FanLow; + case stdAc::fanspeed_t::kMedium: return kHitachiAc424FanMedium; + case stdAc::fanspeed_t::kHigh: return kHitachiAc424FanHigh; + case stdAc::fanspeed_t::kMax: return kHitachiAc424FanMax; + default: return kHitachiAc424FanAuto; + } +} + +// Convert a native mode to it's common equivalent. +stdAc::opmode_t IRHitachiAc424::toCommonMode(const uint8_t mode) { + switch (mode) { + case kHitachiAc424Cool: return stdAc::opmode_t::kCool; + case kHitachiAc424Heat: return stdAc::opmode_t::kHeat; + case kHitachiAc424Dry: return stdAc::opmode_t::kDry; + case kHitachiAc424Fan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kCool; + } +} + +// Convert a native fan speed to it's common equivalent. +stdAc::fanspeed_t IRHitachiAc424::toCommonFanSpeed(const uint8_t speed) { + switch (speed) { + case kHitachiAc424FanMax: return stdAc::fanspeed_t::kMax; + case kHitachiAc424FanHigh: return stdAc::fanspeed_t::kHigh; + case kHitachiAc424FanMedium: return stdAc::fanspeed_t::kMedium; + case kHitachiAc424FanLow: return stdAc::fanspeed_t::kLow; + case kHitachiAc424FanMin: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; + } +} + +// Convert the A/C state to it's common equivalent. +stdAc::state_t IRHitachiAc424::toCommon(void) { + stdAc::state_t result; + result.protocol = decode_type_t::HITACHI_AC424; + result.model = -1; // No models used. + result.power = this->getPower(); + result.mode = this->toCommonMode(this->getMode()); + result.celsius = true; + result.degrees = this->getTemp(); + result.fanspeed = this->toCommonFanSpeed(this->getFan()); + + // TODO(jamsinclair): Add support. + result.swingv = stdAc::swingv_t::kOff; + + // Not supported. + result.swingh = stdAc::swingh_t::kOff; + result.quiet = false; + result.turbo = false; + result.clean = false; + result.econo = false; + result.filter = false; + result.light = false; + result.beep = false; + result.sleep = -1; + result.clock = -1; + return result; +} + +// Convert the internal state into a human readable string. +String IRHitachiAc424::toString(void) { + String result = ""; + result.reserve(60); // Reserve some heap for the string to reduce fragging. + result += addBoolToString(getPower(), kPowerStr, false); + result += addModeToString(getMode(), 0, kHitachiAc424Cool, + kHitachiAc424Heat, kHitachiAc424Dry, + kHitachiAc424Fan); + result += addTempToString(getTemp()); + result += addIntToString(getFan(), kFanStr); + result += kSpaceLBraceStr; + switch (getFan()) { + case kHitachiAc424FanAuto: result += kAutoStr; break; + case kHitachiAc424FanMax: result += kMaxStr; break; + case kHitachiAc424FanHigh: result += kHighStr; break; + case kHitachiAc424FanMedium: result += kMedStr; break; + case kHitachiAc424FanLow: result += kLowStr; break; + case kHitachiAc424FanMin: result += kMinStr; break; + default: result += kUnknownStr; + } + result += ')'; + return result; +} diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Hitachi.h b/lib/IRremoteESP8266-2.7.0/src/ir_Hitachi.h old mode 100755 new mode 100644 similarity index 51% rename from lib/IRremoteESP8266-2.6.5/src/ir_Hitachi.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Hitachi.h index b9bfd391c..4b02b3a4c --- a/lib/IRremoteESP8266-2.6.5/src/ir_Hitachi.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Hitachi.h @@ -1,11 +1,13 @@ // Hitachi A/C // -// Copyright 2018 David Conran +// Copyright 2018-2019 David Conran // Supports: // Brand: Hitachi, Model: RAS-35THA6 remote // Brand: Hitachi, Model: LT0541-HTA remote // Brand: Hitachi, Model: Series VI A/C (Circa 2007) +// Brand: Hitachi, Model: RAR-8P2 remote +// Brand: Hitachi, Model: RAS-AJ25H A/C #ifndef IR_HITACHI_H_ #define IR_HITACHI_H_ @@ -22,6 +24,7 @@ #endif // Constants +const uint16_t kHitachiAcFreq = 38000; // Hz. const uint8_t kHitachiAcAuto = 2; const uint8_t kHitachiAcHeat = 3; const uint8_t kHitachiAcCool = 4; @@ -34,6 +37,35 @@ const uint8_t kHitachiAcFanHigh = 5; const uint8_t kHitachiAcMinTemp = 16; // 16C const uint8_t kHitachiAcMaxTemp = 32; // 32C const uint8_t kHitachiAcAutoTemp = 23; // 23C +const uint8_t kHitachiAcPowerOffset = 0; +const uint8_t kHitachiAcSwingOffset = 7; + +// HitachiAc424 +// Byte[13] +const uint8_t kHitachiAc424TempByte = 13; +const uint8_t kHitachiAc424TempOffset = 2; +const uint8_t kHitachiAc424TempSize = 6; +const uint8_t kHitachiAc424MinTemp = 16; // 16C +const uint8_t kHitachiAc424MaxTemp = 32; // 32C +const uint8_t kHitachiAc424FanTemp = 27; // 27C + +// Byte[25] +const uint8_t kHitachiAc424ModeByte = 25; +const uint8_t kHitachiAc424Fan = 1; +const uint8_t kHitachiAc424Cool = 3; +const uint8_t kHitachiAc424Dry = 5; +const uint8_t kHitachiAc424Heat = 6; +const uint8_t kHitachiAc424FanByte = kHitachiAc424ModeByte; +const uint8_t kHitachiAc424FanMin = 1; +const uint8_t kHitachiAc424FanLow = 2; +const uint8_t kHitachiAc424FanMedium = 3; +const uint8_t kHitachiAc424FanHigh = 4; +const uint8_t kHitachiAc424FanAuto = 5; +const uint8_t kHitachiAc424FanMax = 6; +const uint8_t kHitachiAc424FanMaxDry = 2; +// Byte[27] +const uint8_t kHitachiAc424PowerByte = 27; +const uint8_t kHitachiAc424PowerOffset = 4; // Classes class IRHitachiAc { @@ -87,4 +119,47 @@ class IRHitachiAc { uint8_t _previoustemp; }; +class IRHitachiAc424 { + public: + explicit IRHitachiAc424(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + + void stateReset(void); +#if SEND_HITACHI_AC424 + void send(const uint16_t repeat = kHitachiAcDefaultRepeat); + uint8_t calibrate(void) { return _irsend.calibrate(); } +#endif // SEND_HITACHI_AC424 + void begin(void); + void on(void); + void off(void); + void setPower(const bool on); + bool getPower(void); + void setTemp(const uint8_t temp, bool setPrevious = true); + uint8_t getTemp(void); + void setFan(const uint8_t speed); + uint8_t getFan(void); + void setMode(const uint8_t mode); + uint8_t getMode(void); + uint8_t* getRaw(void); + void setRaw(const uint8_t new_code[], + const uint16_t length = kHitachiAc424StateLength); + uint8_t convertMode(const stdAc::opmode_t mode); + 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); + String toString(void); +#ifndef UNIT_TEST + + private: + IRsend _irsend; +#else + IRsendTest _irsend; +#endif + // The state of the IR remote in IR code form. + uint8_t remote_state[kHitachiAc424StateLength]; + void setInvertedStates(void); + uint8_t _previoustemp; +}; + #endif // IR_HITACHI_H_ diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Inax.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Inax.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Inax.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Inax.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_JVC.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_JVC.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_JVC.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_JVC.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Kelvinator.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Kelvinator.cpp old mode 100755 new mode 100644 similarity index 77% rename from lib/IRremoteESP8266-2.6.5/src/ir_Kelvinator.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Kelvinator.cpp index 0af521b15..320458b30 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Kelvinator.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Kelvinator.cpp @@ -16,12 +16,14 @@ #include "ir_Kelvinator.h" #include +#include #ifndef ARDUINO #include #endif #include "IRac.h" #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // Constants @@ -44,27 +46,20 @@ const uint16_t kKelvinatorGapSpace = kKelvinatorGapSpaceTicks * kKelvinatorTick; const uint8_t kKelvinatorCmdFooter = 2; const uint8_t kKelvinatorCmdFooterBits = 3; -const uint8_t kKelvinatorPower = 8; -const uint8_t kKelvinatorModeMask = 0xF8; -const uint8_t kKelvinatorFanOffset = 4; -const uint8_t kKelvinatorBasicFanMask = 0xFF ^ (3U << kKelvinatorFanOffset); -const uint8_t kKelvinatorFanMask = 0xFF ^ (7U << kKelvinatorFanOffset); +const uint8_t kKelvinatorModeOffset = 0; // Mask 0b111 +const uint8_t kKelvinatorPowerOffset = 3; +const uint8_t kKelvinatorFanOffset = 4; // Mask 0b111 +const uint8_t kKelvinatorFanSize = 3; // Bits +const uint8_t kKelvinatorBasicFanSize = 2; // Bits, Mask 0b011 const uint8_t kKelvinatorChecksumStart = 10; const uint8_t kKelvinatorVentSwingOffset = 6; -const uint8_t kKelvinatorVentSwing = 1 << kKelvinatorVentSwingOffset; -const uint8_t kKelvinatorVentSwingV = 1; -const uint8_t kKelvinatorVentSwingH = 1 << 4; -const uint8_t kKelvinatorSleep1And3 = 1 << 7; +const uint8_t kKelvinatorVentSwingVOffset = 0; +const uint8_t kKelvinatorVentSwingHOffset = 4; const uint8_t kKelvinatorQuietOffset = 7; -const uint8_t kKelvinatorQuiet = 1 << kKelvinatorQuietOffset; const uint8_t kKelvinatorIonFilterOffset = 6; -const uint8_t kKelvinatorIonFilter = 1 << kKelvinatorIonFilterOffset; const uint8_t kKelvinatorLightOffset = 5; -const uint8_t kKelvinatorLight = 1 << kKelvinatorLightOffset; const uint8_t kKelvinatorXfanOffset = 7; -const uint8_t kKelvinatorXfan = 1 << kKelvinatorXfanOffset; const uint8_t kKelvinatorTurboOffset = 4; -const uint8_t kKelvinatorTurbo = 1 << kKelvinatorTurboOffset; using irutils::addBoolToString; using irutils::addIntToString; @@ -72,6 +67,8 @@ using irutils::addLabeledString; using irutils::addModeToString; using irutils::addFanToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_KELVINATOR // Send a Kelvinator A/C message. @@ -157,9 +154,7 @@ uint8_t *IRKelvinatorAC::getRaw(void) { } void IRKelvinatorAC::setRaw(const uint8_t new_code[]) { - for (uint8_t i = 0; i < kKelvinatorStateLength; i++) { - remote_state[i] = new_code[i]; - } + memcpy(remote_state, new_code, kKelvinatorStateLength); } uint8_t IRKelvinatorAC::calcBlockChecksum(const uint8_t *block, @@ -167,19 +162,19 @@ uint8_t IRKelvinatorAC::calcBlockChecksum(const uint8_t *block, uint8_t sum = kKelvinatorChecksumStart; // Sum the lower half of the first 4 bytes of this block. for (uint8_t i = 0; i < 4 && i < length - 1; i++, block++) - sum += (*block & 0x0FU); + sum += (*block & 0b1111); // then sum the upper half of the next 3 bytes. for (uint8_t i = 4; i < length - 1; i++, block++) sum += (*block >> 4); // Trim it down to fit into the 4 bits allowed. i.e. Mod 16. - return sum & 0x0FU; + return sum & 0b1111; } // Many Bothans died to bring us this information. void IRKelvinatorAC::checksum(const uint16_t length) { // For each command + options block. for (uint16_t offset = 0; offset + 7 < length; offset += 8) { - uint8_t sum = calcBlockChecksum(remote_state + offset); - remote_state[7 + offset] = (sum << 4) | (remote_state[7 + offset] & 0xFU); + setBits(&remote_state[7 + offset], kHighNibble, kNibbleSize, + calcBlockChecksum(remote_state + offset)); } } @@ -193,44 +188,38 @@ bool IRKelvinatorAC::validChecksum(const uint8_t state[], const uint16_t length) { for (uint16_t offset = 0; offset + 7 < length; offset += 8) { // Top 4 bits of the last byte in the block is the block's checksum. - if (state[offset + 7] >> 4 != calcBlockChecksum(state + offset)) + if (GETBITS8(state[offset + 7], kHighNibble, kNibbleSize) != + calcBlockChecksum(state + offset)) return false; } return true; } -void IRKelvinatorAC::on(void) { - remote_state[0] |= kKelvinatorPower; - remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. -} +void IRKelvinatorAC::on(void) { setPower(true); } -void IRKelvinatorAC::off(void) { - remote_state[0] &= ~kKelvinatorPower; - remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. -} +void IRKelvinatorAC::off(void) {setPower(false); } void IRKelvinatorAC::setPower(const bool on) { - if (on) - this->on(); - else - this->off(); + setBit(&remote_state[0], kKelvinatorPowerOffset, on); + remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getPower(void) { - return remote_state[0] & kKelvinatorPower; + return GETBIT8(remote_state[0], kKelvinatorPowerOffset); } // Set the temp. in deg C void IRKelvinatorAC::setTemp(const uint8_t degrees) { uint8_t temp = std::max(kKelvinatorMinTemp, degrees); temp = std::min(kKelvinatorMaxTemp, temp); - remote_state[1] = (remote_state[1] & 0xF0U) | (temp - kKelvinatorMinTemp); + setBits(&remote_state[1], kLowNibble, kNibbleSize, temp - kKelvinatorMinTemp); remote_state[9] = remote_state[1]; // Duplicate to the 2nd command chunk. } // Return the set temp. in deg C uint8_t IRKelvinatorAC::getTemp(void) { - return ((remote_state[1] & 0xFU) + kKelvinatorMinTemp); + return GETBITS8(remote_state[1], kLowNibble, kNibbleSize) + + kKelvinatorMinTemp; } // Set the speed of the fan, 0-5, 0 is auto, 1-5 is the speed @@ -240,24 +229,22 @@ void IRKelvinatorAC::setFan(const uint8_t speed) { // Only change things if we need to. if (fan != this->getFan()) { // Set the basic fan values. - uint8_t fan_basic = std::min(kKelvinatorBasicFanMax, fan); - remote_state[0] = (remote_state[0] & kKelvinatorBasicFanMask) | - (fan_basic << kKelvinatorFanOffset); + setBits(&remote_state[0], kKelvinatorFanOffset, kKelvinatorBasicFanSize, + std::min(kKelvinatorBasicFanMax, fan)); remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. // Set the advanced(?) fan value. - remote_state[14] = - (remote_state[14] & kKelvinatorFanMask) | (fan << kKelvinatorFanOffset); + setBits(&remote_state[14], kKelvinatorFanOffset, kKelvinatorFanSize, fan); // Turbo mode is turned off if we change the fan settings. this->setTurbo(false); } } uint8_t IRKelvinatorAC::getFan(void) { - return ((remote_state[14] & ~kKelvinatorFanMask) >> kKelvinatorFanOffset); + return GETBITS8(remote_state[14], kKelvinatorFanOffset, kKelvinatorFanSize); } uint8_t IRKelvinatorAC::getMode(void) { - return (remote_state[0] & ~kKelvinatorModeMask); + return GETBITS8(remote_state[0], kKelvinatorModeOffset, kModeBitsSize); } void IRKelvinatorAC::setMode(const uint8_t mode) { @@ -271,7 +258,7 @@ void IRKelvinatorAC::setMode(const uint8_t mode) { case kKelvinatorHeat: case kKelvinatorCool: case kKelvinatorFan: - remote_state[0] = (remote_state[0] & kKelvinatorModeMask) | mode; + setBits(&remote_state[0], kKelvinatorModeOffset, kModeBitsSize, mode); remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. break; default: // If we get an unexpected mode, default to AUTO. @@ -280,99 +267,81 @@ void IRKelvinatorAC::setMode(const uint8_t mode) { } void IRKelvinatorAC::setSwingVertical(const bool on) { - if (on) { - remote_state[0] |= kKelvinatorVentSwing; - remote_state[4] |= kKelvinatorVentSwingV; - } else { - remote_state[4] &= ~kKelvinatorVentSwingV; - if (!this->getSwingHorizontal()) remote_state[0] &= ~kKelvinatorVentSwing; - } + setBit(&remote_state[4], kKelvinatorVentSwingVOffset, on); + setBit(&remote_state[0], kKelvinatorVentSwingOffset, + on || getSwingHorizontal()); remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getSwingVertical(void) { - return remote_state[4] & kKelvinatorVentSwingV; + return GETBIT8(remote_state[4], kKelvinatorVentSwingVOffset); } void IRKelvinatorAC::setSwingHorizontal(const bool on) { - if (on) { - remote_state[0] |= kKelvinatorVentSwing; - remote_state[4] |= kKelvinatorVentSwingH; - } else { - remote_state[4] &= ~kKelvinatorVentSwingH; - if (!this->getSwingVertical()) remote_state[0] &= ~kKelvinatorVentSwing; - } + setBit(&remote_state[4], kKelvinatorVentSwingHOffset, on); + setBit(&remote_state[0], kKelvinatorVentSwingOffset, + on || getSwingVertical()); remote_state[8] = remote_state[0]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getSwingHorizontal(void) { - return remote_state[4] & kKelvinatorVentSwingH; + return GETBIT8(remote_state[4], kKelvinatorVentSwingHOffset); } void IRKelvinatorAC::setQuiet(const bool on) { - remote_state[12] &= ~kKelvinatorQuiet; - remote_state[12] |= (on << kKelvinatorQuietOffset); + setBit(&remote_state[12], kKelvinatorQuietOffset, on); } bool IRKelvinatorAC::getQuiet(void) { - return remote_state[12] & kKelvinatorQuiet; + return GETBIT8(remote_state[12], kKelvinatorQuietOffset); } void IRKelvinatorAC::setIonFilter(const bool on) { - remote_state[2] &= ~kKelvinatorIonFilter; - remote_state[2] |= (on << kKelvinatorIonFilterOffset); + setBit(&remote_state[2], kKelvinatorIonFilterOffset, on); remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getIonFilter(void) { - return remote_state[2] & kKelvinatorIonFilter; + return GETBIT8(remote_state[2], kKelvinatorIonFilterOffset); } void IRKelvinatorAC::setLight(const bool on) { - remote_state[2] &= ~kKelvinatorLight; - remote_state[2] |= (on << kKelvinatorLightOffset); + setBit(&remote_state[2], kKelvinatorLightOffset, on); remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getLight(void) { - return remote_state[2] & kKelvinatorLight; + return GETBIT8(remote_state[2], kKelvinatorLightOffset); } // Note: XFan mode is only valid in Cool or Dry mode. void IRKelvinatorAC::setXFan(const bool on) { - remote_state[2] &= ~kKelvinatorXfan; - remote_state[2] |= (on << kKelvinatorXfanOffset); + setBit(&remote_state[2], kKelvinatorXfanOffset, on); remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getXFan(void) { - return remote_state[2] & kKelvinatorXfan; + return GETBIT8(remote_state[2], kKelvinatorXfanOffset); } // Note: Turbo mode is turned off if the fan speed is changed. void IRKelvinatorAC::setTurbo(const bool on) { - remote_state[2] &= ~kKelvinatorTurbo; - remote_state[2] |= (on << kKelvinatorTurboOffset); + setBit(&remote_state[2], kKelvinatorTurboOffset, on); remote_state[10] = remote_state[2]; // Duplicate to the 2nd command chunk. } bool IRKelvinatorAC::getTurbo(void) { - return remote_state[2] & kKelvinatorTurbo; + return GETBIT8(remote_state[2], kKelvinatorTurboOffset); } // Convert a standard A/C mode into its native mode. uint8_t IRKelvinatorAC::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kKelvinatorCool; - case stdAc::opmode_t::kHeat: - return kKelvinatorHeat; - case stdAc::opmode_t::kDry: - return kKelvinatorDry; - case stdAc::opmode_t::kFan: - return kKelvinatorFan; - default: - return kKelvinatorAuto; + case stdAc::opmode_t::kCool: return kKelvinatorCool; + case stdAc::opmode_t::kHeat: return kKelvinatorHeat; + case stdAc::opmode_t::kDry: return kKelvinatorDry; + case stdAc::opmode_t::kFan: return kKelvinatorFan; + default: return kKelvinatorAuto; } } @@ -381,9 +350,9 @@ stdAc::opmode_t IRKelvinatorAC::toCommonMode(const uint8_t mode) { switch (mode) { case kKelvinatorCool: return stdAc::opmode_t::kCool; case kKelvinatorHeat: return stdAc::opmode_t::kHeat; - case kKelvinatorDry: return stdAc::opmode_t::kDry; - case kKelvinatorFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kKelvinatorDry: return stdAc::opmode_t::kDry; + case kKelvinatorFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -423,20 +392,20 @@ stdAc::state_t IRKelvinatorAC::toCommon(void) { String IRKelvinatorAC::toString(void) { String result = ""; result.reserve(160); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kKelvinatorAuto, kKelvinatorCool, kKelvinatorHeat, kKelvinatorDry, kKelvinatorFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kKelvinatorFanMax, kKelvinatorFanMin, kKelvinatorFanAuto, kKelvinatorFanAuto, kKelvinatorBasicFanMax); - result += addBoolToString(getTurbo(), F("Turbo")); - result += addBoolToString(getQuiet(), F("Quiet")); - result += addBoolToString(getXFan(), F("XFan")); - result += addBoolToString(getIonFilter(), F("IonFilter")); - result += addBoolToString(getLight(), F("Light")); - result += addBoolToString(getSwingHorizontal(), F("Swing (Horizontal)")); - result += addBoolToString(getSwingVertical(), F("Swing (Vertical)")); + result += addBoolToString(getTurbo(), kTurboStr); + result += addBoolToString(getQuiet(), kQuietStr); + result += addBoolToString(getXFan(), kXFanStr); + result += addBoolToString(getIonFilter(), kIonStr); + result += addBoolToString(getLight(), kLightStr); + result += addBoolToString(getSwingHorizontal(), kSwingHStr); + result += addBoolToString(getSwingVertical(), kSwingVStr); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Kelvinator.h b/lib/IRremoteESP8266-2.7.0/src/ir_Kelvinator.h old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Kelvinator.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Kelvinator.h diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_LG.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_LG.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_LG.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_LG.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_LG.h b/lib/IRremoteESP8266-2.7.0/src/ir_LG.h old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_LG.h rename to lib/IRremoteESP8266-2.7.0/src/ir_LG.h diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Lasertag.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Lasertag.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Lasertag.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Lasertag.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Lego.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Lego.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Lego.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Lego.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Lutron.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Lutron.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Lutron.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Lutron.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_MWM.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_MWM.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_MWM.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_MWM.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Magiquest.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Magiquest.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Magiquest.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Magiquest.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Magiquest.h b/lib/IRremoteESP8266-2.7.0/src/ir_Magiquest.h old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Magiquest.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Magiquest.h diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Midea.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Midea.cpp old mode 100755 new mode 100644 similarity index 82% rename from lib/IRremoteESP8266-2.6.5/src/ir_Midea.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Midea.cpp index 80744c9cb..3160fc291 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Midea.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Midea.cpp @@ -8,6 +8,7 @@ #endif #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // Midea A/C added by (send) bwze/crankyoldgit & (decode) crankyoldgit @@ -43,6 +44,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_MIDEA // Send a Midea message @@ -123,46 +126,38 @@ void IRMideaAC::send(const uint16_t repeat) { // Return a pointer to the internal state date of the remote. uint64_t IRMideaAC::getRaw(void) { this->checksum(); - return remote_state & kMideaACStateMask; + return GETBITS64(remote_state, 0, kMideaBits); } // Override the internal state with the new state. -void IRMideaAC::setRaw(const uint64_t newState) { - remote_state = newState & kMideaACStateMask; -} +void IRMideaAC::setRaw(const uint64_t newState) { remote_state = newState; } + +// Set the requested power state of the A/C to on. +void IRMideaAC::on(void) { setPower(true); } // Set the requested power state of the A/C to off. -void IRMideaAC::on(void) { remote_state |= kMideaACPower; } - -// Set the requested power state of the A/C to off. -void IRMideaAC::off(void) { - remote_state &= (kMideaACStateMask ^ kMideaACPower); -} +void IRMideaAC::off(void) { setPower(false); } // Set the requested power state of the A/C. void IRMideaAC::setPower(const bool on) { - if (on) - this->on(); - else - this->off(); + setBit(&remote_state, kMideaACPowerOffset, on); } // Return the requested power state of the A/C. -bool IRMideaAC::getPower(void) { return (remote_state & kMideaACPower); } +bool IRMideaAC::getPower(void) { + return GETBIT64(remote_state, kMideaACPowerOffset); +} // Returns true if we want the A/C unit to work natively in Celsius. bool IRMideaAC::getUseCelsius(void) { - return !(remote_state & kMideaACCelsiusBit); + return !GETBIT64(remote_state, kMideaACCelsiusOffset); } // Set the A/C unit to use Celsius natively. void IRMideaAC::setUseCelsius(const bool on) { if (on != getUseCelsius()) { // We need to change. uint8_t native_temp = getTemp(!on); // Get the old native temp. - if (on) - remote_state &= ~kMideaACCelsiusBit; // Clear the bit - else - remote_state |= kMideaACCelsiusBit; // Set the bit + setBit(&remote_state, kMideaACCelsiusOffset, !on); // Cleared is on. setTemp(native_temp, !on); // Reset temp using the old native temp. } } @@ -186,8 +181,7 @@ void IRMideaAC::setTemp(const uint8_t temp, const bool useCelsius) { else // Native and desired are the same units. new_temp -= min_temp; // Set the actual data. - remote_state &= kMideaACTempMask; - remote_state |= ((uint64_t)new_temp << 24); + setBits(&remote_state, kMideaACTempOffset, kMideaACTempSize, new_temp); } // Return the set temp. @@ -196,7 +190,7 @@ void IRMideaAC::setTemp(const uint8_t temp, const bool useCelsius) { // Returns: // A uint8_t containing the temperature. uint8_t IRMideaAC::getTemp(const bool celsius) { - uint8_t temp = ((remote_state >> 24) & 0x1F); + uint8_t temp = GETBITS64(remote_state, kMideaACTempOffset, kMideaACTempSize); if (getUseCelsius()) temp += kMideaACMinTempC; else @@ -209,27 +203,21 @@ uint8_t IRMideaAC::getTemp(const bool celsius) { // Set the speed of the fan, // 1-3 set the speed, 0 or anything else set it to auto. void IRMideaAC::setFan(const uint8_t fan) { - uint64_t new_fan; - switch (fan) { - case kMideaACFanLow: - case kMideaACFanMed: - case kMideaACFanHigh: - new_fan = fan; - break; - default: - new_fan = kMideaACFanAuto; - } - remote_state &= kMideaACFanMask; - remote_state |= (new_fan << 35); + setBits(&remote_state, kMideaACFanOffset, kMideaACFanSize, + (fan > kMideaACFanHigh) ? kMideaACFanAuto : fan); } // Return the requested state of the unit's fan. -uint8_t IRMideaAC::getFan(void) { return (remote_state >> 35) & 0b111; } +uint8_t IRMideaAC::getFan(void) { + return GETBITS64(remote_state, kMideaACFanOffset, kMideaACFanSize); +} // Get the requested climate operation mode of the a/c unit. // Returns: // A uint8_t containing the A/C mode. -uint8_t IRMideaAC::getMode(void) { return ((remote_state >> 32) & 0b111); } +uint8_t IRMideaAC::getMode(void) { + return GETBITS64(remote_state, kMideaACModeOffset, kModeBitsSize); +} // Set the requested climate operation mode of the a/c unit. void IRMideaAC::setMode(const uint8_t mode) { @@ -239,9 +227,8 @@ void IRMideaAC::setMode(const uint8_t mode) { case kMideaACHeat: case kMideaACDry: case kMideaACFan: - remote_state &= kMideaACModeMask; - remote_state |= ((uint64_t)mode << 32); - return; + setBits(&remote_state, kMideaACModeOffset, kModeBitsSize, mode); + break; default: this->setMode(kMideaACAuto); } @@ -249,24 +236,22 @@ void IRMideaAC::setMode(const uint8_t mode) { // Set the Sleep state of the A/C. void IRMideaAC::setSleep(const bool on) { - if (on) - remote_state |= kMideaACSleep; - else - remote_state &= (kMideaACStateMask ^ kMideaACSleep); + setBit(&remote_state, kMideaACSleepOffset, on); } // Return the Sleep state of the A/C. -bool IRMideaAC::getSleep(void) { return (remote_state & kMideaACSleep); } +bool IRMideaAC::getSleep(void) { + return GETBIT64(remote_state, kMideaACSleepOffset); +} // Set the A/C to toggle the vertical swing toggle for the next send. -void IRMideaAC::setSwingVToggle(const bool on) { - _SwingVToggle = on; -} +void IRMideaAC::setSwingVToggle(const bool on) { _SwingVToggle = on; } // Return if the message/state is just a Swing V toggle message/command. bool IRMideaAC::isSwingVToggle(void) { return remote_state == kMideaACToggleSwingV; } + // Return the Swing V toggle state of the A/C. bool IRMideaAC::getSwingVToggle(void) { _SwingVToggle |= isSwingVToggle(); @@ -296,30 +281,24 @@ uint8_t IRMideaAC::calcChecksum(const uint64_t state) { // Returns: // A boolean. bool IRMideaAC::validChecksum(const uint64_t state) { - return ((state & 0xFF) == calcChecksum(state)); + return GETBITS64(state, 0, 8) == calcChecksum(state); } // Calculate & set the checksum for the current internal state of the remote. void IRMideaAC::checksum(void) { // Stored the checksum value in the last byte. - remote_state &= kMideaACChecksumMask; - remote_state |= calcChecksum(remote_state); + setBits(&remote_state, 0, 8, calcChecksum(remote_state)); } // Convert a standard A/C mode into its native mode. uint8_t IRMideaAC::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kMideaACCool; - case stdAc::opmode_t::kHeat: - return kMideaACHeat; - case stdAc::opmode_t::kDry: - return kMideaACDry; - case stdAc::opmode_t::kFan: - return kMideaACFan; - default: - return kMideaACAuto; + case stdAc::opmode_t::kCool: return kMideaACCool; + case stdAc::opmode_t::kHeat: return kMideaACHeat; + case stdAc::opmode_t::kDry: return kMideaACDry; + case stdAc::opmode_t::kFan: return kMideaACFan; + default: return kMideaACAuto; } } @@ -327,15 +306,11 @@ uint8_t IRMideaAC::convertMode(const stdAc::opmode_t mode) { uint8_t IRMideaAC::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kMideaACFanLow; - case stdAc::fanspeed_t::kMedium: - return kMideaACFanMed; + case stdAc::fanspeed_t::kLow: return kMideaACFanLow; + case stdAc::fanspeed_t::kMedium: return kMideaACFanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kMideaACFanHigh; - default: - return kMideaACFanAuto; + case stdAc::fanspeed_t::kMax: return kMideaACFanHigh; + default: return kMideaACFanAuto; } } @@ -344,9 +319,9 @@ stdAc::opmode_t IRMideaAC::toCommonMode(const uint8_t mode) { switch (mode) { case kMideaACCool: return stdAc::opmode_t::kCool; case kMideaACHeat: return stdAc::opmode_t::kHeat; - case kMideaACDry: return stdAc::opmode_t::kDry; - case kMideaACFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kMideaACDry: return stdAc::opmode_t::kDry; + case kMideaACFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -354,9 +329,9 @@ stdAc::opmode_t IRMideaAC::toCommonMode(const uint8_t mode) { stdAc::fanspeed_t IRMideaAC::toCommonFanSpeed(const uint8_t speed) { switch (speed) { case kMideaACFanHigh: return stdAc::fanspeed_t::kMax; - case kMideaACFanMed: return stdAc::fanspeed_t::kMedium; - case kMideaACFanLow: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kMideaACFanMed: return stdAc::fanspeed_t::kMedium; + case kMideaACFanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } @@ -400,19 +375,19 @@ String IRMideaAC::toString(void) { String result = ""; result.reserve(100); // Reserve some heap for the string to reduce fragging. if (!isSwingVToggle()) { - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kMideaACAuto, kMideaACCool, kMideaACHeat, kMideaACDry, kMideaACFan); - result += addBoolToString(getUseCelsius(), F("Celsius")); + result += addBoolToString(getUseCelsius(), kCelsiusStr); result += addTempToString(getTemp(true)); result += '/'; result += uint64ToString(getTemp(false)); result += 'F'; result += addFanToString(getFan(), kMideaACFanHigh, kMideaACFanLow, kMideaACFanAuto, kMideaACFanAuto, kMideaACFanMed); - result += addBoolToString(getSleep(), F("Sleep")); + result += addBoolToString(getSleep(), kSleepStr); } - result += addBoolToString(getSwingVToggle(), F("Swing(V) Toggle"), + result += addBoolToString(getSwingVToggle(), kSwingVStr + ' ' + kToggleStr, !isSwingVToggle()); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Midea.h b/lib/IRremoteESP8266-2.7.0/src/ir_Midea.h old mode 100755 new mode 100644 similarity index 84% rename from lib/IRremoteESP8266-2.6.5/src/ir_Midea.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Midea.h index 289821778..af005d729 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Midea.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Midea.h @@ -26,27 +26,27 @@ // https://docs.google.com/spreadsheets/d/1TZh4jWrx4h9zzpYUI9aYXMl1fYOiqu-xVuOOMqagxrs/edit?usp=sharing // Constants +const uint8_t kMideaACTempOffset = 24; +const uint8_t kMideaACTempSize = 5; // Bits +const uint8_t kMideaACMinTempF = 62; // Fahrenheit +const uint8_t kMideaACMaxTempF = 86; // Fahrenheit +const uint8_t kMideaACMinTempC = 17; // Celsius +const uint8_t kMideaACMaxTempC = 30; // Celsius +const uint8_t kMideaACCelsiusOffset = 29; +const uint8_t kMideaACModeOffset = 32; const uint8_t kMideaACCool = 0; // 0b000 const uint8_t kMideaACDry = 1; // 0b001 const uint8_t kMideaACAuto = 2; // 0b010 const uint8_t kMideaACHeat = 3; // 0b011 const uint8_t kMideaACFan = 4; // 0b100 -const uint8_t kMideaACFanAuto = 0; // 0b000 -const uint8_t kMideaACFanLow = 1; // 0b001 -const uint8_t kMideaACFanMed = 2; // 0b010 -const uint8_t kMideaACFanHigh = 3; // 0b011 -const uint64_t kMideaACPower = 1ULL << 39; -const uint64_t kMideaACSleep = 1ULL << 38; -const uint8_t kMideaACMinTempF = 62; // Fahrenheit -const uint8_t kMideaACMaxTempF = 86; // Fahrenheit -const uint8_t kMideaACMinTempC = 17; // Celsius -const uint8_t kMideaACMaxTempC = 30; // Celsius -const uint64_t kMideaACStateMask = 0x0000FFFFFFFFFFFF; -const uint64_t kMideaACCelsiusBit = 0x0000000020000000; -const uint64_t kMideaACTempMask = 0x0000FFFFE0FFFFFF; -const uint64_t kMideaACFanMask = 0x0000FFC7FFFFFFFF; -const uint64_t kMideaACModeMask = 0x0000FFF8FFFFFFFF; -const uint64_t kMideaACChecksumMask = 0x0000FFFFFFFFFF00; +const uint8_t kMideaACFanOffset = 35; +const uint8_t kMideaACFanSize = 2; // Bits +const uint8_t kMideaACFanAuto = 0; // 0b00 +const uint8_t kMideaACFanLow = 1; // 0b01 +const uint8_t kMideaACFanMed = 2; // 0b10 +const uint8_t kMideaACFanHigh = 3; // 0b11 +const uint8_t kMideaACSleepOffset = 38; +const uint8_t kMideaACPowerOffset = 39; const uint64_t kMideaACToggleSwingV = 0x0000A201FFFFFF7C; // Legacy defines. (Deprecated) diff --git a/lib/IRremoteESP8266-2.7.0/src/ir_Mitsubishi.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Mitsubishi.cpp new file mode 100644 index 000000000..7e28fd332 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Mitsubishi.cpp @@ -0,0 +1,1594 @@ +// Copyright 2009 Ken Shirriff +// Copyright 2017-2019 David Conran +// Copyright 2019 Mark Kuchel +// Copyright 2018 Denes Varga + +// Mitsubishi + +#include "ir_Mitsubishi.h" +#include +#include +#ifndef ARDUINO +#include +#endif +#include "IRrecv.h" +#include "IRsend.h" +#include "IRtext.h" +#include "IRutils.h" +#include "ir_Tcl.h" + +// Mitsubishi (TV) decoding added from https://github.com/z3t0/Arduino-IRremote +// Mitsubishi (TV) sending & Mitsubishi A/C support added by David Conran + +// Constants +// Mitsubishi TV +// period time is 1/33000Hz = 30.303 uSeconds (T) +// Ref: +// GlobalCache's Control Tower's Mitsubishi TV data. +// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Mitsubishi.cpp +const uint16_t kMitsubishiTick = 30; +const uint16_t kMitsubishiBitMarkTicks = 10; +const uint16_t kMitsubishiBitMark = kMitsubishiBitMarkTicks * kMitsubishiTick; +const uint16_t kMitsubishiOneSpaceTicks = 70; +const uint16_t kMitsubishiOneSpace = kMitsubishiOneSpaceTicks * kMitsubishiTick; +const uint16_t kMitsubishiZeroSpaceTicks = 30; +const uint16_t kMitsubishiZeroSpace = + kMitsubishiZeroSpaceTicks * kMitsubishiTick; +const uint16_t kMitsubishiMinCommandLengthTicks = 1786; +const uint16_t kMitsubishiMinCommandLength = + kMitsubishiMinCommandLengthTicks * kMitsubishiTick; +const uint16_t kMitsubishiMinGapTicks = 936; +const uint16_t kMitsubishiMinGap = kMitsubishiMinGapTicks * kMitsubishiTick; + +// Mitsubishi Projector (HC3000) +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/441 + +const uint16_t kMitsubishi2HdrMark = 8400; +const uint16_t kMitsubishi2HdrSpace = kMitsubishi2HdrMark / 2; +const uint16_t kMitsubishi2BitMark = 560; +const uint16_t kMitsubishi2ZeroSpace = 520; +const uint16_t kMitsubishi2OneSpace = kMitsubishi2ZeroSpace * 3; +const uint16_t kMitsubishi2MinGap = 28500; + +// Mitsubishi A/C +// Ref: +// https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266.ino#L84 + +const uint16_t kMitsubishiAcHdrMark = 3400; +const uint16_t kMitsubishiAcHdrSpace = 1750; +const uint16_t kMitsubishiAcBitMark = 450; +const uint16_t kMitsubishiAcOneSpace = 1300; +const uint16_t kMitsubishiAcZeroSpace = 420; +const uint16_t kMitsubishiAcRptMark = 440; +const uint16_t kMitsubishiAcRptSpace = 17100; +const uint8_t kMitsubishiAcExtraTolerance = 5; + +// Mitsubishi 136 bit A/C +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/888 + +const uint16_t kMitsubishi136HdrMark = 3324; +const uint16_t kMitsubishi136HdrSpace = 1474; +const uint16_t kMitsubishi136BitMark = 467; +const uint16_t kMitsubishi136OneSpace = 1137; +const uint16_t kMitsubishi136ZeroSpace = 351; +const uint32_t kMitsubishi136Gap = kDefaultMessageGap; + +// Mitsubishi 112 bit A/C +// Ref: +// https://github.com/kuchel77 + +const uint16_t kMitsubishi112HdrMark = 3450; +const uint16_t kMitsubishi112HdrSpace = 1696; +const uint16_t kMitsubishi112BitMark = 450; +const uint16_t kMitsubishi112OneSpace = 1250; +const uint16_t kMitsubishi112ZeroSpace = 385; +const uint32_t kMitsubishi112Gap = kDefaultMessageGap; +// Total tolerance percentage to use for matching the header mark. +const uint8_t kMitsubishi112HdrMarkTolerance = 5; + + +using irutils::addBoolToString; +using irutils::addFanToString; +using irutils::addIntToString; +using irutils::addLabeledString; +using irutils::addModeToString; +using irutils::addTempToString; +using irutils::minsToString; +using irutils::setBit; +using irutils::setBits; + +#if SEND_MITSUBISHI +// Send a Mitsubishi message +// +// Args: +// data: Contents of the message to be sent. +// nbits: Nr. of bits of data to be sent. Typically kMitsubishiBits. +// repeat: Nr. of additional times the message is to be sent. +// +// Status: ALPHA / untested. +// +// Notes: +// This protocol appears to have no header. +// Ref: +// https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Mitsubishi.cpp +// GlobalCache's Control Tower's Mitsubishi TV data. +void IRsend::sendMitsubishi(uint64_t data, uint16_t nbits, uint16_t repeat) { + sendGeneric(0, 0, // No Header + kMitsubishiBitMark, kMitsubishiOneSpace, kMitsubishiBitMark, + kMitsubishiZeroSpace, kMitsubishiBitMark, kMitsubishiMinGap, + kMitsubishiMinCommandLength, data, nbits, 33, true, repeat, 50); +} +#endif // SEND_MITSUBISHI + +#if DECODE_MITSUBISHI +// Decode the supplied Mitsubishi message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: Nr. of data bits to expect. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: BETA / previously working. +// +// Notes: +// This protocol appears to have no header. +// +// Ref: +// GlobalCache's Control Tower's Mitsubishi TV data. +bool IRrecv::decodeMitsubishi(decode_results *results, uint16_t nbits, + bool strict) { + if (strict && nbits != kMitsubishiBits) + return false; // Request is out of spec. + + uint16_t offset = kStartOffset; + uint64_t data = 0; + + // Match Data + Footer + if (!matchGeneric(results->rawbuf + offset, &data, + results->rawlen - offset, nbits, + 0, 0, // No header + kMitsubishiBitMark, kMitsubishiOneSpace, + kMitsubishiBitMark, kMitsubishiZeroSpace, + kMitsubishiBitMark, kMitsubishiMinGap, + true, 30)) return false; + // Success + results->decode_type = MITSUBISHI; + results->bits = nbits; + results->value = data; + results->address = 0; + results->command = 0; + return true; +} +#endif // DECODE_MITSUBISHI + +#if SEND_MITSUBISHI2 +// Send a Mitsubishi2 message +// +// Args: +// data: Contents of the message to be sent. +// nbits: Nr. of bits of data to be sent. Typically kMitsubishiBits. +// repeat: Nr. of additional times the message is to be sent. +// +// Status: ALPHA / untested. +// +// Notes: +// Based on a Mitsubishi HC3000 projector's remote. +// This protocol appears to have a manditory in-protocol repeat. +// That is in *addition* to the entire message needing to be sent twice +// for the device to accept the command. That is separate from the repeat. +// i.e. Allegedly, the real remote requires the "Off" button pressed twice. +// You will need to add a suitable gap yourself. +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/441 +void IRsend::sendMitsubishi2(uint64_t data, uint16_t nbits, uint16_t repeat) { + for (uint16_t i = 0; i <= repeat; i++) { + // First half of the data. + sendGeneric(kMitsubishi2HdrMark, kMitsubishi2HdrSpace, kMitsubishi2BitMark, + kMitsubishi2OneSpace, kMitsubishi2BitMark, + kMitsubishi2ZeroSpace, kMitsubishi2BitMark, + kMitsubishi2HdrSpace, data >> (nbits / 2), nbits / 2, 33, true, + 0, 50); + // Second half of the data. + sendGeneric(0, 0, // No header for the second data block + kMitsubishi2BitMark, kMitsubishi2OneSpace, kMitsubishi2BitMark, + kMitsubishi2ZeroSpace, kMitsubishi2BitMark, kMitsubishi2MinGap, + data & ((1 << (nbits / 2)) - 1), nbits / 2, 33, true, 0, 50); + } +} +#endif // SEND_MITSUBISHI2 + +#if DECODE_MITSUBISHI2 +// Decode the supplied Mitsubishi2 message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: Nr. of data bits to expect. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: BETA / Works with simulated data. +// +// Notes: +// Hardware supported: +// * Mitsubishi HC3000 projector's remote. +// +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/441 +bool IRrecv::decodeMitsubishi2(decode_results *results, uint16_t nbits, + bool strict) { + if (results->rawlen < 2 * nbits + kHeader + (kFooter * 2) - 1) + return false; // Shorter than shortest possibly expected. + if (strict && nbits != kMitsubishiBits) + return false; // Request is out of spec. + + uint16_t offset = kStartOffset; + results->value = 0; + + // Header + if (!matchMark(results->rawbuf[offset++], kMitsubishi2HdrMark)) return false; + if (!matchSpace(results->rawbuf[offset++], kMitsubishi2HdrSpace)) + return false; + for (uint8_t i = 0; i < 2; i++) { + // Match Data + Footer + uint16_t used; + uint64_t data = 0; + used = matchGeneric(results->rawbuf + offset, &data, + results->rawlen - offset, nbits / 2, + 0, 0, // No header + kMitsubishi2BitMark, kMitsubishi2OneSpace, + kMitsubishi2BitMark, kMitsubishi2ZeroSpace, + kMitsubishi2BitMark, kMitsubishi2HdrSpace, + i % 2); + if (!used) return false; + offset += used; + results->value <<= (nbits / 2); + results->value |= data; + } + + // Success + results->decode_type = MITSUBISHI2; + results->bits = nbits; + results->address = GETBITS64(results->value, nbits / 2, nbits / 2); + results->command = GETBITS64(results->value, 0, nbits / 2); + return true; +} +#endif // DECODE_MITSUBISHI2 + +#if SEND_MITSUBISHI_AC +// Send a Mitsubishi A/C message. +// +// Args: +// data: An array of bytes containing the IR command. +// nbytes: Nr. of bytes of data in the array. (>=kMitsubishiACStateLength) +// repeat: Nr. of times the message is to be repeated. +// (Default = kMitsubishiACMinRepeat). +// +// Status: BETA / Appears to be working. +// +void IRsend::sendMitsubishiAC(const unsigned char data[], const uint16_t nbytes, + const uint16_t repeat) { + if (nbytes < kMitsubishiACStateLength) + return; // Not enough bytes to send a proper message. + + sendGeneric(kMitsubishiAcHdrMark, kMitsubishiAcHdrSpace, kMitsubishiAcBitMark, + kMitsubishiAcOneSpace, kMitsubishiAcBitMark, + kMitsubishiAcZeroSpace, kMitsubishiAcRptMark, + kMitsubishiAcRptSpace, data, nbytes, 38, false, repeat, 50); +} +#endif // SEND_MITSUBISHI_AC + +#if DECODE_MITSUBISHI_AC +// Decode the supplied Mitsubishi message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: Nr. of data bits to expect. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: ALPHA / Under development +// +// Ref: +// https://www.analysir.com/blog/2015/01/06/reverse-engineering-mitsubishi-ac-infrared-protocol/ +bool IRrecv::decodeMitsubishiAC(decode_results *results, uint16_t nbits, + bool strict) { + if (results->rawlen < ((kMitsubishiACBits * 2) + 2)) { + DPRINTLN("Shorter than shortest possibly expected."); + return false; // Shorter than shortest possibly expected. + } + if (strict && nbits != kMitsubishiACBits) { + DPRINTLN("Request is out of spec."); + return false; // Request is out of spec. + } + uint16_t offset = kStartOffset; + for (uint8_t i = 0; i < kMitsubishiACStateLength; i++) { + results->state[i] = 0; + } + bool failure = false; + uint8_t rep = 0; + do { + failure = false; + // Header: + // Sometime happens that junk signals arrives before the real message + bool headerFound = false; + while (!headerFound && + offset < (results->rawlen - (kMitsubishiACBits * 2 + 2))) { + headerFound = + matchMark(results->rawbuf[offset], kMitsubishiAcHdrMark) && + matchSpace(results->rawbuf[offset + 1], kMitsubishiAcHdrSpace); + offset += 2; + } + if (!headerFound) { + DPRINTLN("Header mark not found."); + return false; + } + DPRINT("Header mark found at #"); + DPRINTLN(offset - 2); + // Decode byte-by-byte: + match_result_t data_result; + for (uint8_t i = 0; i < kMitsubishiACStateLength && !failure; i++) { + results->state[i] = 0; + data_result = + matchData(&(results->rawbuf[offset]), 8, kMitsubishiAcBitMark, + kMitsubishiAcOneSpace, kMitsubishiAcBitMark, + kMitsubishiAcZeroSpace, + _tolerance + kMitsubishiAcExtraTolerance, 0, false); + if (data_result.success == false) { + failure = true; + DPRINT("Byte decode failed at #"); + DPRINTLN((uint16_t)i); + } else { + results->state[i] = data_result.data; + offset += data_result.used; + DPRINT((uint16_t)results->state[i]); + DPRINT(","); + } + DPRINTLN(""); + } + // HEADER validation: + if (failure || results->state[0] != 0x23 || results->state[1] != 0xCB || + results->state[2] != 0x26 || results->state[3] != 0x01 || + results->state[4] != 0x00) { + DPRINTLN("Header mismatch."); + failure = true; + } else { + // DATA part: + + // FOOTER checksum: + if (!IRMitsubishiAC::validChecksum(results->state)) { + DPRINTLN("Checksum error."); + failure = true; + } + } + if (rep != kMitsubishiACMinRepeat && failure) { + bool repeatMarkFound = false; + while (!repeatMarkFound && + offset < (results->rawlen - (kMitsubishiACBits * 2 + 4))) { + repeatMarkFound = + matchMark(results->rawbuf[offset], kMitsubishiAcRptMark) && + matchSpace(results->rawbuf[offset + 1], kMitsubishiAcRptSpace); + offset += 2; + } + if (!repeatMarkFound) { + DPRINTLN("First attempt failure and repeat mark not found."); + return false; + } + } + rep++; + // Check if the repeat is correct if we need strict decode: + if (strict && !failure) { + DPRINTLN("Strict repeat check enabled."); + // Repeat mark and space: + if (!matchMark(results->rawbuf[offset++], kMitsubishiAcRptMark) || + !matchSpace(results->rawbuf[offset++], kMitsubishiAcRptSpace)) { + DPRINTLN("Repeat mark error."); + return false; + } + // Header mark and space: + if (!matchMark(results->rawbuf[offset++], kMitsubishiAcHdrMark) || + !matchSpace(results->rawbuf[offset++], kMitsubishiAcHdrSpace)) { + DPRINTLN("Repeat header error."); + return false; + } + // Payload: + for (uint8_t i = 0; i < kMitsubishiACStateLength; i++) { + data_result = + matchData(&(results->rawbuf[offset]), 8, kMitsubishiAcBitMark, + kMitsubishiAcOneSpace, kMitsubishiAcBitMark, + kMitsubishiAcZeroSpace, + _tolerance + kMitsubishiAcExtraTolerance, 0, false); + if (data_result.success == false || + data_result.data != results->state[i]) { + DPRINTLN("Repeat payload error."); + return false; + } + offset += data_result.used; + } + } // strict repeat check + } while (failure && rep <= kMitsubishiACMinRepeat); + results->decode_type = MITSUBISHI_AC; + results->bits = nbits; + return !failure; +} +#endif // DECODE_MITSUBISHI_AC + +// Code to emulate Mitsubishi A/C IR remote control unit. +// 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. +// +// Equipment it seems compatible with: +// * +// Initialise the object. +IRMitsubishiAC::IRMitsubishiAC(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { this->stateReset(); } + +// Reset the state of the remote to a known good state/sequence. +void IRMitsubishiAC::stateReset(void) { + // The state of the IR remote in IR code form. + // Known good state obtained from: + // https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266.ino#L108 + static const uint8_t kReset[kMitsubishiACStateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x08, 0x06, 0x30, 0x45, 0x67}; + setRaw(kReset); +} + +// Configure the pin for output. +void IRMitsubishiAC::begin(void) { _irsend.begin(); } + +#if SEND_MITSUBISHI_AC +// Send the current desired state to the IR LED. +void IRMitsubishiAC::send(const uint16_t repeat) { + _irsend.sendMitsubishiAC(getRaw(), kMitsubishiACStateLength, repeat); +} +#endif // SEND_MITSUBISHI_AC + +// Return a pointer to the internal state date of the remote. +uint8_t *IRMitsubishiAC::getRaw(void) { + this->checksum(); + return remote_state; +} + +void IRMitsubishiAC::setRaw(const uint8_t *data) { + memcpy(remote_state, data, kMitsubishiACStateLength); +} + +// Calculate the checksum for the current internal state of the remote. +void IRMitsubishiAC::checksum(void) { + remote_state[kMitsubishiACStateLength - 1] = calculateChecksum(remote_state); +} + +bool IRMitsubishiAC::validChecksum(const uint8_t *data) { + return calculateChecksum(data) == data[kMitsubishiACStateLength - 1]; +} + +uint8_t IRMitsubishiAC::calculateChecksum(const uint8_t *data) { + return sumBytes(data, kMitsubishiACStateLength - 1); +} + +// Set the requested power state of the A/C to on. +void IRMitsubishiAC::on(void) { setPower(true); } + +// Set the requested power state of the A/C to off. +void IRMitsubishiAC::off(void) { setPower(false); } + +// Set the requested power state of the A/C. +void IRMitsubishiAC::setPower(bool on) { + setBit(&remote_state[5], kMitsubishiAcPowerOffset, on); +} + +// Return the requested power state of the A/C. +bool IRMitsubishiAC::getPower(void) { + return GETBIT8(remote_state[5], kMitsubishiAcPowerOffset); +} + +// Set the temp. in deg C +void IRMitsubishiAC::setTemp(const uint8_t degrees) { + uint8_t temp = std::max((uint8_t)kMitsubishiAcMinTemp, degrees); + temp = std::min((uint8_t)kMitsubishiAcMaxTemp, temp); + remote_state[7] = temp - kMitsubishiAcMinTemp; +} + +// Return the set temp. in deg C +uint8_t IRMitsubishiAC::getTemp(void) { + return (remote_state[7] + kMitsubishiAcMinTemp); +} + +// Set the speed of the fan, 0-6. +// 0 is auto, 1-5 is the speed, 6 is silent. +void IRMitsubishiAC::setFan(const uint8_t speed) { + uint8_t fan = speed; + // Bounds check + if (fan > kMitsubishiAcFanSilent) + fan = kMitsubishiAcFanMax; // Set the fan to maximum if out of range. + // Auto has a special bit. + setBit(&remote_state[9], kMitsubishiAcFanAutoOffset, + fan == kMitsubishiAcFanAuto); + if (fan >= kMitsubishiAcFanMax) + fan--; // There is no spoon^H^H^Heed 5 (max), pretend it doesn't exist. + setBits(&remote_state[9], kMitsubishiAcFanOffset, kMitsubishiAcFanSize, fan); +} + +// Return the requested state of the unit's fan. +uint8_t IRMitsubishiAC::getFan(void) { + uint8_t fan = GETBITS8(remote_state[9], kMitsubishiAcFanOffset, + kMitsubishiAcFanSize); + if (fan == kMitsubishiAcFanMax) return kMitsubishiAcFanSilent; + return fan; +} + +// Return the requested climate operation mode of the a/c unit. +uint8_t IRMitsubishiAC::getMode(void) { + return GETBITS8(remote_state[6], kMitsubishiAcModeOffset, kModeBitsSize); +} + +// Set the requested climate operation mode of the a/c unit. +void IRMitsubishiAC::setMode(const uint8_t mode) { + // If we get an unexpected mode, default to AUTO. + switch (mode) { + case kMitsubishiAcAuto: remote_state[8] = 0b00110000; break; + case kMitsubishiAcCool: remote_state[8] = 0b00110110; break; + case kMitsubishiAcDry: remote_state[8] = 0b00110010; break; + case kMitsubishiAcHeat: remote_state[8] = 0b00110000; break; + default: + this->setMode(kMitsubishiAcAuto); + return; + } + setBits(&remote_state[6], kMitsubishiAcModeOffset, kModeBitsSize, mode); +} + +// Set the requested vane operation mode of the a/c unit. +void IRMitsubishiAC::setVane(const uint8_t position) { + uint8_t pos = std::min(position, kMitsubishiAcVaneAutoMove); // bounds check + setBit(&remote_state[9], kMitsubishiAcVaneBitOffset); + setBits(&remote_state[9], kMitsubishiAcVaneOffset, kMitsubishiAcVaneSize, + pos); +} + +// Set the requested wide-vane operation mode of the a/c unit. +void IRMitsubishiAC::setWideVane(const uint8_t position) { + setBits(&remote_state[8], kHighNibble, kNibbleSize, + std::min(position, kMitsubishiAcWideVaneAuto)); +} + +// Return the requested vane operation mode of the a/c unit. +uint8_t IRMitsubishiAC::getVane(void) { + return GETBITS8(remote_state[9], kMitsubishiAcVaneOffset, + kMitsubishiAcVaneSize); +} + +// Return the requested wide vane operation mode of the a/c unit. +uint8_t IRMitsubishiAC::getWideVane(void) { + return GETBITS8(remote_state[8], kHighNibble, kNibbleSize); +} + +// Return the clock setting of the message. 1=1/6 hour. e.g. 4pm = 48 +uint8_t IRMitsubishiAC::getClock(void) { return remote_state[10]; } + +// Set the current time. 1 = 1/6 hour. e.g. 6am = 36. +void IRMitsubishiAC::setClock(const uint8_t clock) { + remote_state[10] = clock; +} + +// Return the desired start time. 1 = 1/6 hour. e.g. 1am = 6 +uint8_t IRMitsubishiAC::getStartClock(void) { return remote_state[12]; } + +// Set the desired start time of the AC. 1 = 1/6 hour. e.g. 8pm = 120 +void IRMitsubishiAC::setStartClock(const uint8_t clock) { + remote_state[12] = clock; +} + +// Return the desired stop time of the AC. 1 = 1/6 hour. e.g 10pm = 132 +uint8_t IRMitsubishiAC::getStopClock(void) { return remote_state[11]; } + +// Set the desired stop time of the AC. 1 = 1/6 hour. e.g 10pm = 132 +void IRMitsubishiAC::setStopClock(const uint8_t clock) { + remote_state[11] = clock; +} + +// Return the timer setting. Possible values: kMitsubishiAcNoTimer, +// kMitsubishiAcStartTimer, kMitsubishiAcStopTimer, +// kMitsubishiAcStartStopTimer +uint8_t IRMitsubishiAC::getTimer(void) { + return GETBITS8(remote_state[13], 0, 3); +} + +// Set the timer setting. Possible values: kMitsubishiAcNoTimer, +// kMitsubishiAcStartTimer, kMitsubishiAcStopTimer, +// kMitsubishiAcStartStopTimer +void IRMitsubishiAC::setTimer(uint8_t timer) { + setBits(&remote_state[13], 0, 3, timer); +} + +// Convert a standard A/C mode into its native mode. +uint8_t IRMitsubishiAC::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: return kMitsubishiAcCool; + case stdAc::opmode_t::kHeat: return kMitsubishiAcHeat; + case stdAc::opmode_t::kDry: return kMitsubishiAcDry; + default: return kMitsubishiAcAuto; + } +} + +// Convert a standard A/C Fan speed into its native fan speed. +uint8_t IRMitsubishiAC::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: return kMitsubishiAcFanSilent; + case stdAc::fanspeed_t::kLow: return kMitsubishiAcFanRealMax - 3; + case stdAc::fanspeed_t::kMedium: return kMitsubishiAcFanRealMax - 2; + case stdAc::fanspeed_t::kHigh: return kMitsubishiAcFanRealMax - 1; + case stdAc::fanspeed_t::kMax: return kMitsubishiAcFanRealMax; + default: return kMitsubishiAcFanAuto; + } +} + +// Convert a standard A/C vertical swing into its native setting. +uint8_t IRMitsubishiAC::convertSwingV(const stdAc::swingv_t position) { + switch (position) { + case stdAc::swingv_t::kHighest: return kMitsubishiAcVaneAutoMove - 6; + case stdAc::swingv_t::kHigh: return kMitsubishiAcVaneAutoMove - 5; + case stdAc::swingv_t::kMiddle: return kMitsubishiAcVaneAutoMove - 4; + case stdAc::swingv_t::kLow: return kMitsubishiAcVaneAutoMove - 3; + case stdAc::swingv_t::kLowest: return kMitsubishiAcVaneAutoMove - 2; + case stdAc::swingv_t::kAuto: return kMitsubishiAcVaneAutoMove; + default: return kMitsubishiAcVaneAuto; + } +} + +// Convert a standard A/C wide wane swing into its native setting. +uint8_t IRMitsubishiAC::convertSwingH(const stdAc::swingh_t position) { + switch (position) { + case stdAc::swingh_t::kLeftMax: return kMitsubishiAcWideVaneAuto - 7; + case stdAc::swingh_t::kLeft: return kMitsubishiAcWideVaneAuto - 6; + case stdAc::swingh_t::kMiddle: return kMitsubishiAcWideVaneAuto - 5; + case stdAc::swingh_t::kRight: return kMitsubishiAcWideVaneAuto - 4; + case stdAc::swingh_t::kRightMax: return kMitsubishiAcWideVaneAuto - 3; + case stdAc::swingh_t::kWide: return kMitsubishiAcWideVaneAuto - 2; + case stdAc::swingh_t::kAuto: return kMitsubishiAcWideVaneAuto; + default: return kMitsubishiAcWideVaneAuto - 5; + } +} + +// Convert a native mode to it's common equivalent. +stdAc::opmode_t IRMitsubishiAC::toCommonMode(const uint8_t mode) { + switch (mode) { + case kMitsubishiAcCool: return stdAc::opmode_t::kCool; + case kMitsubishiAcHeat: return stdAc::opmode_t::kHeat; + case kMitsubishiAcDry: return stdAc::opmode_t::kDry; + default: return stdAc::opmode_t::kAuto; + } +} + +// Convert a native fan speed to it's common equivalent. +stdAc::fanspeed_t IRMitsubishiAC::toCommonFanSpeed(const uint8_t speed) { + switch (speed) { + case kMitsubishiAcFanRealMax: return stdAc::fanspeed_t::kMax; + case kMitsubishiAcFanRealMax - 1: return stdAc::fanspeed_t::kHigh; + case kMitsubishiAcFanRealMax - 2: return stdAc::fanspeed_t::kMedium; + case kMitsubishiAcFanRealMax - 3: return stdAc::fanspeed_t::kLow; + case kMitsubishiAcFanSilent: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; + } +} + +// Convert a native vertical swing to it's common equivalent. +stdAc::swingv_t IRMitsubishiAC::toCommonSwingV(const uint8_t pos) { + switch (pos) { + case 1: return stdAc::swingv_t::kHighest; + case 2: return stdAc::swingv_t::kHigh; + case 3: return stdAc::swingv_t::kMiddle; + case 4: return stdAc::swingv_t::kLow; + case 5: return stdAc::swingv_t::kLowest; + default: return stdAc::swingv_t::kAuto; + } +} + +// Convert a native horizontal swing to it's common equivalent. +stdAc::swingh_t IRMitsubishiAC::toCommonSwingH(const uint8_t pos) { + switch (pos) { + case 1: return stdAc::swingh_t::kLeftMax; + case 2: return stdAc::swingh_t::kLeft; + case 3: return stdAc::swingh_t::kMiddle; + case 4: return stdAc::swingh_t::kRight; + case 5: return stdAc::swingh_t::kRightMax; + case 6: return stdAc::swingh_t::kWide; + default: return stdAc::swingh_t::kAuto; + } +} + +// Convert the A/C state to it's common equivalent. +stdAc::state_t IRMitsubishiAC::toCommon(void) { + stdAc::state_t result; + result.protocol = decode_type_t::MITSUBISHI_AC; + result.model = -1; // No models used. + result.power = this->getPower(); + result.mode = this->toCommonMode(this->getMode()); + result.celsius = true; + result.degrees = this->getTemp(); + result.fanspeed = this->toCommonFanSpeed(this->getFan()); + result.swingv = this->toCommonSwingV(this->getVane()); + result.swingh = this->toCommonSwingH(this->getWideVane()); + result.quiet = this->getFan() == kMitsubishiAcFanSilent; + // Not supported. + result.turbo = false; + result.clean = false; + result.econo = false; + result.filter = false; + result.light = false; + result.beep = false; + result.sleep = -1; + result.clock = -1; + return result; +} + +// Convert the internal state into a human readable string. +String IRMitsubishiAC::toString(void) { + String result = ""; + result.reserve(110); // Reserve some heap for the string to reduce fragging. + result += addBoolToString(getPower(), kPowerStr, false); + result += addModeToString(getMode(), kMitsubishiAcAuto, kMitsubishiAcCool, + kMitsubishiAcHeat, kMitsubishiAcDry, + kMitsubishiAcAuto); + result += addTempToString(getTemp()); + result += addFanToString(getFan(), kMitsubishiAcFanRealMax, + kMitsubishiAcFanRealMax - 3, + kMitsubishiAcFanAuto, kMitsubishiAcFanQuiet, + kMitsubishiAcFanRealMax - 2); + result += addIntToString(this->getVane(), kSwingVStr); + result += kSpaceLBraceStr; + switch (this->getVane()) { + case kMitsubishiAcVaneAuto: result += kAutoStr; break; + case kMitsubishiAcVaneAutoMove: result += kAutoStr + ' ' + kMoveStr; break; + default: result += kUnknownStr; + } + result += ')'; + result += addIntToString(this->getWideVane(), kSwingHStr); + result += kSpaceLBraceStr; + switch (this->getWideVane()) { + case kMitsubishiAcWideVaneAuto: result += kAutoStr; break; + default: result += kUnknownStr; + } + result += ')'; + result += addLabeledString(minsToString(getClock() * 10), kClockStr); + result += addLabeledString(minsToString(getStartClock() * 10), kOnTimerStr); + result += addLabeledString(minsToString(getStopClock() * 10), kOffTimerStr); + result += kCommaSpaceStr + kTimerStr + kColonSpaceStr; + switch (this->getTimer()) { + case kMitsubishiAcNoTimer: + result += '-'; + break; + case kMitsubishiAcStartTimer: + result += kStartStr; + break; + case kMitsubishiAcStopTimer: + result += kStopStr; + break; + case kMitsubishiAcStartStopTimer: + result += kStartStr + '+' + kStopStr; + break; + default: + result += F("? ("); + result += this->getTimer(); + result += ')'; + } + return result; +} + +#if SEND_MITSUBISHI136 +// Send a Mitsubishi136 A/C message. +// +// Args: +// data: An array of bytes containing the IR command. +// nbytes: Nr. of bytes of data in the array. (>=kMitsubishi136StateLength) +// repeat: Nr. of times the message is to be repeated. +// (Default = kMitsubishi136MinRepeat). +// +// Status: ALPHA / Probably working. Needs to be tested against a real device. +// +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/888 +void IRsend::sendMitsubishi136(const unsigned char data[], + const uint16_t nbytes, + const uint16_t repeat) { + if (nbytes < kMitsubishi136StateLength) + return; // Not enough bytes to send a proper message. + + sendGeneric(kMitsubishi136HdrMark, kMitsubishi136HdrSpace, + kMitsubishi136BitMark, kMitsubishi136OneSpace, + kMitsubishi136BitMark, kMitsubishi136ZeroSpace, + kMitsubishi136BitMark, kMitsubishi136Gap, + data, nbytes, 38, false, repeat, 50); +} +#endif // SEND_MITSUBISHI136 + +#if DECODE_MITSUBISHI136 +// Decode the supplied Mitsubishi136 message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: Nr. of data bits to expect. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: STABLE / Reported as working. +// +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/888 +bool IRrecv::decodeMitsubishi136(decode_results *results, const uint16_t nbits, + const bool strict) { + // Too short to match? + if (results->rawlen < (2 * nbits) + kHeader + kFooter - 1) return false; + if (nbits % 8 != 0) return false; // Not a multiple of an 8 bit byte. + if (strict) { // Do checks to see if it matches the spec. + if (nbits != kMitsubishi136Bits) return false; + } + uint16_t used = matchGeneric(results->rawbuf + kStartOffset, results->state, + results->rawlen - kStartOffset, nbits, + kMitsubishi136HdrMark, kMitsubishi136HdrSpace, + kMitsubishi136BitMark, kMitsubishi136OneSpace, + kMitsubishi136BitMark, kMitsubishi136ZeroSpace, + kMitsubishi136BitMark, kMitsubishi136Gap, + true, _tolerance, 0, false); + if (!used) return false; + if (strict) { + // Header validation: Codes start with 0x23CB26 + if (results->state[0] != 0x23 || results->state[1] != 0xCB || + results->state[2] != 0x26) return false; + if (!IRMitsubishi136::validChecksum(results->state, nbits / 8)) + return false; + } + results->decode_type = MITSUBISHI136; + results->bits = nbits; + return true; +} +#endif // DECODE_MITSUBISHI136 + +// Code to emulate Mitsubishi 136bit A/C IR remote control unit. +// +// Equipment it seems compatible with: +// Brand: Mitsubishi Electric, Model: PEAD-RP71JAA Ducted A/C +// Brand: Mitsubishi Electric, Model: 001CP T7WE10714 remote + +// Initialise the object. +IRMitsubishi136::IRMitsubishi136(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { this->stateReset(); } + +// Reset the state of the remote to a known good state/sequence. +void IRMitsubishi136::stateReset(void) { + // The state of the IR remote in IR code form. + // Known good state obtained from: + // https://docs.google.com/spreadsheets/d/1f8EGfIbBUo2B-CzUFdrgKQprWakoYNKM80IKZN4KXQE/edit#gid=312397579&range=A10 + static const uint8_t kReset[kMitsubishi136StateLength] = { + 0x23, 0xCB, 0x26, 0x21, 0x00, 0x40, 0xC2, 0xC7, 0x04}; + memcpy(remote_state, kReset, kMitsubishi136StateLength); +} + +// Calculate the checksum for the current internal state of the remote. +void IRMitsubishi136::checksum(void) { + for (uint8_t i = 0; i < 6; i++) + remote_state[kMitsubishi136PowerByte + 6 + i] = + ~remote_state[kMitsubishi136PowerByte + i]; +} + +bool IRMitsubishi136::validChecksum(const uint8_t *data, const uint16_t len) { + if (len < kMitsubishi136StateLength) return false; + const uint16_t half = (len - kMitsubishi136PowerByte) / 2; + for (uint8_t i = 0; i < half; i++) { + // This variable is needed to avoid the warning: (known compiler issue) + // warning: comparison of promoted ~unsigned with unsigned [-Wsign-compare] + const uint8_t inverted = ~data[kMitsubishi136PowerByte + half + i]; + if (data[kMitsubishi136PowerByte + i] != inverted) return false; + } + return true; +} + +// Configure the pin for output. +void IRMitsubishi136::begin(void) { _irsend.begin(); } + +#if SEND_MITSUBISHI136 +// Send the current desired state to the IR LED. +void IRMitsubishi136::send(const uint16_t repeat) { + _irsend.sendMitsubishi136(getRaw(), kMitsubishi136StateLength, repeat); +} +#endif // SEND_MITSUBISHI136 + +// Return a pointer to the internal state date of the remote. +uint8_t *IRMitsubishi136::getRaw(void) { + checksum(); + return remote_state; +} + +void IRMitsubishi136::setRaw(const uint8_t *data) { + memcpy(remote_state, data, kMitsubishi136StateLength); +} + +// Set the requested power state of the A/C to off. +void IRMitsubishi136::on(void) { setPower(true); } + +// Set the requested power state of the A/C to off. +void IRMitsubishi136::off(void) { setPower(false); } + +// Set the requested power state of the A/C. +void IRMitsubishi136::setPower(bool on) { + setBit(&remote_state[kMitsubishi136PowerByte], kMitsubishi136PowerOffset, on); +} + +// Return the requested power state of the A/C. +bool IRMitsubishi136::getPower(void) { + return GETBIT8(remote_state[kMitsubishi136PowerByte], + kMitsubishi136PowerOffset); +} + +// Set the temp. in deg C +void IRMitsubishi136::setTemp(const uint8_t degrees) { + uint8_t temp = std::max((uint8_t)kMitsubishi136MinTemp, degrees); + temp = std::min((uint8_t)kMitsubishi136MaxTemp, temp); + setBits(&remote_state[kMitsubishi136TempByte], kHighNibble, kNibbleSize, + temp - kMitsubishiAcMinTemp); +} + +// Return the set temp. in deg C +uint8_t IRMitsubishi136::getTemp(void) { + return GETBITS8(remote_state[kMitsubishi136TempByte], kHighNibble, + kNibbleSize) + kMitsubishiAcMinTemp; +} + +void IRMitsubishi136::setFan(const uint8_t speed) { + setBits(&remote_state[kMitsubishi136FanByte], kMitsubishi136FanOffset, + kMitsubishi136FanSize, std::min(speed, kMitsubishi136FanMax)); +} + +// Return the requested state of the unit's fan. +uint8_t IRMitsubishi136::getFan(void) { + return GETBITS8(remote_state[kMitsubishi136FanByte], kMitsubishi136FanOffset, + kMitsubishi136FanSize); +} + +// Return the requested climate operation mode of the a/c unit. +uint8_t IRMitsubishi136::getMode(void) { + return GETBITS8(remote_state[kMitsubishi136ModeByte], + kMitsubishi136ModeOffset, kModeBitsSize); +} + +// Set the requested climate operation mode of the a/c unit. +void IRMitsubishi136::setMode(const uint8_t mode) { + // If we get an unexpected mode, default to AUTO. + switch (mode) { + case kMitsubishi136Fan: + case kMitsubishi136Cool: + case kMitsubishi136Heat: + case kMitsubishi136Auto: + case kMitsubishi136Dry: + setBits(&remote_state[kMitsubishi136ModeByte], kMitsubishi136ModeOffset, + kModeBitsSize, mode); + break; + default: + setMode(kMitsubishi136Auto); + } +} + +// Set the requested vane operation mode of the a/c unit. +void IRMitsubishi136::setSwingV(const uint8_t position) { + // If we get an unexpected mode, default to auto. + switch (position) { + case kMitsubishi136SwingVLowest: + case kMitsubishi136SwingVLow: + case kMitsubishi136SwingVHigh: + case kMitsubishi136SwingVHighest: + case kMitsubishi136SwingVAuto: + setBits(&remote_state[kMitsubishi136SwingVByte], kHighNibble, kNibbleSize, + position); + break; + default: + setMode(kMitsubishi136SwingVAuto); + } +} + +// Return the requested vane operation mode of the a/c unit. +uint8_t IRMitsubishi136::getSwingV(void) { + return GETBITS8(remote_state[kMitsubishi136SwingVByte], kHighNibble, + kNibbleSize); +} + +// Emulate a quiet setting. There is no true quiet setting on this a/c +void IRMitsubishi136::setQuiet(bool on) { + if (on) setFan(kMitsubishi136FanQuiet); + else if (getQuiet()) setFan(kMitsubishi136FanLow); +} + +// Return the requested power state of the A/C. +bool IRMitsubishi136::getQuiet(void) { + return getFan() == kMitsubishi136FanQuiet; +} + +// Convert a standard A/C mode into its native mode. +uint8_t IRMitsubishi136::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: return kMitsubishi136Cool; + case stdAc::opmode_t::kHeat: return kMitsubishi136Heat; + case stdAc::opmode_t::kDry: return kMitsubishi136Dry; + case stdAc::opmode_t::kFan: return kMitsubishi136Fan; + default: return kMitsubishi136Auto; + } +} + +// Convert a standard A/C Fan speed into its native fan speed. +uint8_t IRMitsubishi136::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: return kMitsubishi136FanMin; + case stdAc::fanspeed_t::kLow: return kMitsubishi136FanLow; + case stdAc::fanspeed_t::kHigh: + case stdAc::fanspeed_t::kMax: return kMitsubishi136FanMax; + default: return kMitsubishi136FanMed; + } +} + +// Convert a standard A/C vertical swing into its native setting. +uint8_t IRMitsubishi136::convertSwingV(const stdAc::swingv_t position) { + switch (position) { + case stdAc::swingv_t::kHighest: return kMitsubishi136SwingVHighest; + case stdAc::swingv_t::kHigh: + case stdAc::swingv_t::kMiddle: return kMitsubishi136SwingVHigh; + case stdAc::swingv_t::kLow: return kMitsubishi136SwingVLow; + case stdAc::swingv_t::kLowest: return kMitsubishi136SwingVLowest; + default: return kMitsubishi136SwingVAuto; + } +} + +// Convert a native mode to it's common equivalent. +stdAc::opmode_t IRMitsubishi136::toCommonMode(const uint8_t mode) { + switch (mode) { + case kMitsubishi136Cool: return stdAc::opmode_t::kCool; + case kMitsubishi136Heat: return stdAc::opmode_t::kHeat; + case kMitsubishi136Dry: return stdAc::opmode_t::kDry; + case kMitsubishi136Fan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; + } +} + +// Convert a native fan speed to it's common equivalent. +stdAc::fanspeed_t IRMitsubishi136::toCommonFanSpeed(const uint8_t speed) { + switch (speed) { + case kMitsubishi136FanMax: return stdAc::fanspeed_t::kMax; + case kMitsubishi136FanMed: return stdAc::fanspeed_t::kMedium; + case kMitsubishi136FanLow: return stdAc::fanspeed_t::kLow; + case kMitsubishi136FanMin: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kMedium; + } +} + +// Convert a native vertical swing to it's common equivalent. +stdAc::swingv_t IRMitsubishi136::toCommonSwingV(const uint8_t pos) { + switch (pos) { + case kMitsubishi136SwingVHighest: return stdAc::swingv_t::kHighest; + case kMitsubishi136SwingVHigh: return stdAc::swingv_t::kHigh; + case kMitsubishi136SwingVLow: return stdAc::swingv_t::kLow; + case kMitsubishi136SwingVLowest: return stdAc::swingv_t::kLowest; + default: return stdAc::swingv_t::kAuto; + } +} + +// Convert the A/C state to it's common equivalent. +stdAc::state_t IRMitsubishi136::toCommon(void) { + stdAc::state_t result; + result.protocol = decode_type_t::MITSUBISHI136; + result.model = -1; // No models used. + result.power = this->getPower(); + result.mode = this->toCommonMode(this->getMode()); + result.celsius = true; + result.degrees = this->getTemp(); + result.fanspeed = this->toCommonFanSpeed(this->getFan()); + result.swingv = this->toCommonSwingV(this->getSwingV()); + result.quiet = this->getQuiet(); + // Not supported. + result.swingh = stdAc::swingh_t::kOff; + result.turbo = false; + result.clean = false; + result.econo = false; + result.filter = false; + result.light = false; + result.beep = false; + result.sleep = -1; + result.clock = -1; + return result; +} + +// Convert the internal state into a human readable string. +String IRMitsubishi136::toString(void) { + String result = ""; + result.reserve(80); // Reserve some heap for the string to reduce fragging. + result += addBoolToString(getPower(), kPowerStr, false); + result += addModeToString(getMode(), kMitsubishi136Auto, kMitsubishi136Cool, + kMitsubishi136Heat, kMitsubishi136Dry, + kMitsubishi136Fan); + result += addTempToString(getTemp()); + result += addFanToString(getFan(), kMitsubishi136FanMax, + kMitsubishi136FanLow, kMitsubishi136FanMax, + kMitsubishi136FanQuiet, kMitsubishi136FanMed); + result += addIntToString(getSwingV(), kSwingVStr); + result += kSpaceLBraceStr; + switch (getSwingV()) { + case kMitsubishi136SwingVHighest: result += kHighestStr; break; + case kMitsubishi136SwingVHigh: result += kHighStr; break; + case kMitsubishi136SwingVLow: result += kLowStr; break; + case kMitsubishi136SwingVLowest: result += kLowestStr; break; + case kMitsubishi136SwingVAuto: result += kAutoStr; break; + default: result += kUnknownStr; + } + result += ')'; + result += addBoolToString(getQuiet(), kQuietStr); + return result; +} + + +#if SEND_MITSUBISHI112 +// Send a Mitsubishi112 A/C message. +// +// Args: +// data: An array of bytes containing the IR command. +// nbytes: Nr. of bytes of data in the array. (>=kMitsubishi112StateLength) +// repeat: Nr. of times the message is to be repeated. +// (Default = kMitsubishi112MinRepeat). +// +// Status: Stable / Reported as working. +// +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/947 +void IRsend::sendMitsubishi112(const unsigned char data[], + const uint16_t nbytes, + const uint16_t repeat) { + if (nbytes < kMitsubishi112StateLength) + return; // Not enough bytes to send a proper message. + + sendGeneric(kMitsubishi112HdrMark, kMitsubishi112HdrSpace, + kMitsubishi112BitMark, kMitsubishi112OneSpace, + kMitsubishi112BitMark, kMitsubishi112ZeroSpace, + kMitsubishi112BitMark, kMitsubishi112Gap, + data, nbytes, 38, false, repeat, 50); +} +#endif // SEND_MITSUBISHI112 + +#if DECODE_MITSUBISHI112 || DECODE_TCL112AC +// Decode the supplied Mitsubishi112 / Tcl112Ac message. +// +// Args: +// results: Ptr to the data to decode and where to store the decode result. +// nbits: Nr. of data bits to expect. +// strict: Flag indicating if we should perform strict matching. +// Returns: +// boolean: True if it can decode it, false if it can't. +// +// Status: STABLE / Reported as working. +// +// Note: Mitsubishi112 & Tcl112Ac are basically the same protocol. +// The only significant difference I can see is Mitsubishi112 has a +// slightly longer header mark. We will use that to determine which +// varient it should be. The other differences require full decoding and +// only only with certain settings. +// There are some other timing differences too, but the tolerances will +// overlap. +// Ref: +// https://github.com/crankyoldgit/IRremoteESP8266/issues/619 +// https://github.com/crankyoldgit/IRremoteESP8266/issues/947 +bool IRrecv::decodeMitsubishi112(decode_results *results, const uint16_t nbits, + const bool strict) { + if (results->rawlen < ((2 * nbits) + kHeader + kFooter - 1)) return false; + if (nbits % 8 != 0) return false; // Not a multiple of an 8 bit byte. + if (strict) { // Do checks to see if it matches the spec. + if (nbits != kMitsubishi112Bits && nbits != kTcl112AcBits) return false; + } + uint16_t offset = kStartOffset; + decode_type_t typeguess = decode_type_t::UNKNOWN; + uint16_t hdrspace; + uint16_t bitmark; + uint16_t onespace; + uint16_t zerospace; + uint32_t gap; + uint8_t tolerance = _tolerance; + + // Header +#if DECODE_MITSUBISHI112 + if (matchMark(results->rawbuf[offset], kMitsubishi112HdrMark, + kMitsubishi112HdrMarkTolerance, 0)) { + typeguess = decode_type_t::MITSUBISHI112; + hdrspace = kMitsubishi112HdrSpace; + bitmark = kMitsubishi112BitMark; + onespace = kMitsubishi112OneSpace; + zerospace = kMitsubishi112ZeroSpace; + gap = kMitsubishi112Gap; + } +#endif // DECODE_MITSUBISHI112 +#if DECODE_TCL112AC + if (typeguess == decode_type_t::UNKNOWN && // We didn't match Mitsubishi112 + matchMark(results->rawbuf[offset], kTcl112AcHdrMark, + kTcl112AcHdrMarkTolerance, 0)) { + typeguess = decode_type_t::TCL112AC; + hdrspace = kTcl112AcHdrSpace; + bitmark = kTcl112AcBitMark; + onespace = kTcl112AcOneSpace; + zerospace = kTcl112AcZeroSpace; + gap = kTcl112AcGap; + tolerance += kTcl112AcTolerance; + } +#endif // DECODE_TCL112AC + if (typeguess == decode_type_t::UNKNOWN) return false; // No header matched. + offset++; + + uint16_t used = matchGeneric(results->rawbuf + offset, results->state, + results->rawlen - offset, nbits, + 0, // Skip the header as we matched it earlier. + hdrspace, bitmark, onespace, bitmark, zerospace, + bitmark, gap, + true, tolerance, 0, false); + if (!used) return false; + if (strict) { + // Header validation: Codes start with 0x23CB26 + if (results->state[0] != 0x23 || results->state[1] != 0xCB || + results->state[2] != 0x26) return false; + // TCL112 and MITSUBISHI112 share the exact same checksum. + if (!IRTcl112Ac::validChecksum(results->state, nbits / 8)) return false; + } + // Success + results->decode_type = typeguess; + 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_MITSUBISHI112 || DECODE_TCL112AC + +// Code to emulate Mitsubishi 112bit A/C IR remote control unit. +// +// Equipment it seems compatible with: +// Brand: Mitsubishi Electric, Model: MSH-A24WV / MUH-A24WV A/C +// Brand: Mitsubishi Electric, Model: KPOA remote + +// Initialise the object. +IRMitsubishi112::IRMitsubishi112(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { this->stateReset(); } + +// Reset the state of the remote to a known good state/sequence. +void IRMitsubishi112::stateReset(void) { + const uint8_t kReset[kMitsubishi112StateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03, 0x0B, 0x10, + 0x00, 0x00, 0x00, 0x30}; + setRaw(kReset); +} + +// Calculate the checksum for the current internal state of the remote. +void IRMitsubishi112::checksum(void) { + remote_state[kMitsubishi112StateLength - 1] = IRTcl112Ac::calcChecksum( + remote_state, kMitsubishi112StateLength); +} + +// Configure the pin for output. +void IRMitsubishi112::begin(void) { _irsend.begin(); } + +#if SEND_MITSUBISHI112 +// Send the current desired state to the IR LED. +void IRMitsubishi112::send(const uint16_t repeat) { + _irsend.sendMitsubishi112(getRaw(), kMitsubishi112StateLength, repeat); +} +#endif // SEND_MITSUBISHI112 + +// Return a pointer to the internal state date of the remote. +uint8_t *IRMitsubishi112::getRaw(void) { + checksum(); + return remote_state; +} + +void IRMitsubishi112::setRaw(const uint8_t *data) { + memcpy(remote_state, data, kMitsubishi112StateLength); +} + +// Set the requested power state of the A/C to off. +void IRMitsubishi112::on(void) { setPower(true); } + +// Set the requested power state of the A/C to off. +void IRMitsubishi112::off(void) { setPower(false); } + +// Set the requested power state of the A/C. +void IRMitsubishi112::setPower(bool on) { + setBit(&remote_state[kMitsubishi112PowerByte], kMitsubishi112PowerOffset, on); +} + +// Return the requested power state of the A/C. +bool IRMitsubishi112::getPower(void) { + return GETBIT8(remote_state[kMitsubishi112PowerByte], + kMitsubishi112PowerOffset); +} + +// Set the temp. in deg C +void IRMitsubishi112::setTemp(const uint8_t degrees) { + uint8_t temp = std::max((uint8_t)kMitsubishi112MinTemp, degrees); + temp = std::min((uint8_t)kMitsubishi112MaxTemp, temp); + setBits(&remote_state[kMitsubishi112TempByte], kLowNibble, + kMitsubishi112TempSize, kMitsubishiAcMaxTemp - temp); +} + +// Return the set temp. in deg C +uint8_t IRMitsubishi112::getTemp(void) { + return kMitsubishiAcMaxTemp - GETBITS8(remote_state[kMitsubishi112TempByte], + kLowNibble, kMitsubishi112TempSize); +} + +void IRMitsubishi112::setFan(const uint8_t speed) { + switch (speed) { + case kMitsubishi112FanMin: + case kMitsubishi112FanLow: + case kMitsubishi112FanMed: + case kMitsubishi112FanMax: + setBits(&remote_state[kMitsubishi112FanByte], kMitsubishi112FanOffset, + kMitsubishi112FanSize, speed); + break; + default: + setFan(kMitsubishi112FanMax); + } +} + +// Return the requested state of the unit's fan. +uint8_t IRMitsubishi112::getFan(void) { + return GETBITS8(remote_state[kMitsubishi112FanByte], kMitsubishi112FanOffset, + kMitsubishi112FanSize); +} + +// Return the requested climate operation mode of the a/c unit. +uint8_t IRMitsubishi112::getMode(void) { + return GETBITS8(remote_state[kMitsubishi112ModeByte], + kMitsubishi112ModeOffset, kModeBitsSize); +} + +// Set the requested climate operation mode of the a/c unit. +void IRMitsubishi112::setMode(const uint8_t mode) { + // If we get an unexpected mode, default to AUTO. + switch (mode) { + // Note: No Fan Only mode. + case kMitsubishi112Cool: + case kMitsubishi112Heat: + case kMitsubishi112Auto: + case kMitsubishi112Dry: + setBits(&remote_state[kMitsubishi112ModeByte], kMitsubishi112ModeOffset, + kModeBitsSize, mode); + break; + default: + setMode(kMitsubishi112Auto); + } +} + +// Set the requested vane operation mode of the a/c unit. +void IRMitsubishi112::setSwingV(const uint8_t position) { + // If we get an unexpected mode, default to auto. + switch (position) { + case kMitsubishi112SwingVLowest: + case kMitsubishi112SwingVLow: + case kMitsubishi112SwingVMiddle: + case kMitsubishi112SwingVHigh: + case kMitsubishi112SwingVHighest: + case kMitsubishi112SwingVAuto: + setBits(&remote_state[kMitsubishi112SwingVByte], + kMitsubishi112SwingVOffset, kMitsubishi112SwingVSize, position); + break; + default: + setMode(kMitsubishi112SwingVAuto); + } +} + +// Return the requested vane operation mode of the a/c unit. +uint8_t IRMitsubishi112::getSwingV(void) { + return GETBITS8(remote_state[kMitsubishi112SwingVByte], + kMitsubishi112SwingVOffset, kMitsubishi112SwingVSize); +} + +// Set the requested vane operation mode of the a/c unit. +void IRMitsubishi112::setSwingH(const uint8_t position) { + // If we get an unexpected mode, default to auto. + switch (position) { + case kMitsubishi112SwingHLeftMax: + case kMitsubishi112SwingHLeft: + case kMitsubishi112SwingHMiddle: + case kMitsubishi112SwingHRight: + case kMitsubishi112SwingHRightMax: + case kMitsubishi112SwingHWide: + case kMitsubishi112SwingHAuto: + setBits(&remote_state[kMitsubishi112SwingHByte], + kMitsubishi112SwingHOffset, kMitsubishi112SwingHSize, position); + break; + default: + setSwingH(kMitsubishi112SwingHAuto); + } +} + +// Return the requested vane operation mode of the a/c unit. +uint8_t IRMitsubishi112::getSwingH(void) { + return GETBITS8(remote_state[kMitsubishi112SwingHByte], + kMitsubishi112SwingHOffset, kMitsubishi112SwingHSize); +} + +// Emulate a quiet setting. There is no true quiet setting on this a/c +void IRMitsubishi112::setQuiet(bool on) { + if (on) + setFan(kMitsubishi112FanQuiet); + else if (getQuiet()) setFan(kMitsubishi112FanLow); +} + +// Return the requested power state of the A/C. +bool IRMitsubishi112::getQuiet(void) { + return getFan() == kMitsubishi112FanQuiet; +} + + +// Convert a standard A/C mode into its native mode. +uint8_t IRMitsubishi112::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: return kMitsubishi112Cool; + case stdAc::opmode_t::kHeat: return kMitsubishi112Heat; + case stdAc::opmode_t::kDry: return kMitsubishi112Dry; + // Note: No Fan Only mode. + default: return kMitsubishi112Auto; + } +} + +// Convert a standard A/C Fan speed into its native fan speed. +uint8_t IRMitsubishi112::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: return kMitsubishi112FanMin; + case stdAc::fanspeed_t::kLow: return kMitsubishi112FanLow; + case stdAc::fanspeed_t::kMedium: return kMitsubishi112FanMed; + case stdAc::fanspeed_t::kHigh: + case stdAc::fanspeed_t::kMax: return kMitsubishi112FanMax; + default: return kMitsubishi112FanMed; + } +} + +// Convert a standard A/C vertical swing into its native setting. +uint8_t IRMitsubishi112::convertSwingV(const stdAc::swingv_t position) { + switch (position) { + case stdAc::swingv_t::kHighest: return kMitsubishi112SwingVHighest; + case stdAc::swingv_t::kHigh: return kMitsubishi112SwingVHigh; + case stdAc::swingv_t::kMiddle: return kMitsubishi112SwingVMiddle; + case stdAc::swingv_t::kLow: return kMitsubishi112SwingVLow; + case stdAc::swingv_t::kLowest: return kMitsubishi112SwingVLowest; + default: return kMitsubishi112SwingVAuto; + } +} + +// Convert a standard A/C vertical swing into its native setting. +uint8_t IRMitsubishi112::convertSwingH(const stdAc::swingh_t position) { + switch (position) { + case stdAc::swingh_t::kLeftMax: return kMitsubishi112SwingHLeftMax; + case stdAc::swingh_t::kLeft: return kMitsubishi112SwingHLeft; + case stdAc::swingh_t::kMiddle: return kMitsubishi112SwingHMiddle; + case stdAc::swingh_t::kRight: return kMitsubishi112SwingHRight; + case stdAc::swingh_t::kRightMax: return kMitsubishi112SwingHRightMax; + case stdAc::swingh_t::kWide: return kMitsubishi112SwingHWide; + case stdAc::swingh_t::kAuto: return kMitsubishi112SwingHAuto; + default: return kMitsubishi112SwingHAuto; + } +} + +// Convert a native mode to it's common equivalent. +stdAc::opmode_t IRMitsubishi112::toCommonMode(const uint8_t mode) { + switch (mode) { + case kMitsubishi112Cool: return stdAc::opmode_t::kCool; + case kMitsubishi112Heat: return stdAc::opmode_t::kHeat; + case kMitsubishi112Dry: return stdAc::opmode_t::kDry; + default: return stdAc::opmode_t::kAuto; + } +} + +// Convert a native fan speed to it's common equivalent. +stdAc::fanspeed_t IRMitsubishi112::toCommonFanSpeed(const uint8_t speed) { + switch (speed) { + case kMitsubishi112FanMax: return stdAc::fanspeed_t::kMax; + case kMitsubishi112FanMed: return stdAc::fanspeed_t::kMedium; + case kMitsubishi112FanLow: return stdAc::fanspeed_t::kLow; + case kMitsubishi112FanMin: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kMedium; + } +} + +// Convert a native vertical swing to it's common equivalent. +stdAc::swingv_t IRMitsubishi112::toCommonSwingV(const uint8_t pos) { + switch (pos) { + case kMitsubishi112SwingVHighest: return stdAc::swingv_t::kHighest; + case kMitsubishi112SwingVHigh: return stdAc::swingv_t::kHigh; + case kMitsubishi112SwingVMiddle: return stdAc::swingv_t::kMiddle; + case kMitsubishi112SwingVLow: return stdAc::swingv_t::kLow; + case kMitsubishi112SwingVLowest: return stdAc::swingv_t::kLowest; + default: return stdAc::swingv_t::kAuto; + } +} + +// Convert a native vertical swing to it's common equivalent. +stdAc::swingh_t IRMitsubishi112::toCommonSwingH(const uint8_t pos) { + switch (pos) { + case kMitsubishi112SwingHLeftMax: return stdAc::swingh_t::kLeftMax; + case kMitsubishi112SwingHLeft: return stdAc::swingh_t::kLeft; + case kMitsubishi112SwingHMiddle: return stdAc::swingh_t::kMiddle; + case kMitsubishi112SwingHRight: return stdAc::swingh_t::kRight; + case kMitsubishi112SwingHRightMax: return stdAc::swingh_t::kRightMax; + case kMitsubishi112SwingHWide: return stdAc::swingh_t::kWide; + default: return stdAc::swingh_t::kAuto; + } +} + + +// Convert the A/C state to it's common equivalent. +stdAc::state_t IRMitsubishi112::toCommon(void) { + stdAc::state_t result; + result.protocol = decode_type_t::MITSUBISHI112; + result.model = -1; // No models used. + result.power = this->getPower(); + result.mode = this->toCommonMode(this->getMode()); + result.celsius = true; + result.degrees = this->getTemp(); + result.fanspeed = this->toCommonFanSpeed(this->getFan()); + result.swingv = this->toCommonSwingV(this->getSwingV()); + result.swingh = this->toCommonSwingH(this->getSwingH());; + result.quiet = this->getQuiet(); + // Not supported. + result.econo = false; // Need to figure this part from stdAc + result.clock = -1; + result.sleep = -1; + result.turbo = false; + result.clean = false; + result.filter = false; + result.light = false; + result.beep = false; + + + return result; +} + +// Convert the internal state into a human readable string. +String IRMitsubishi112::toString(void) { + String result = ""; + result.reserve(80); // Reserve some heap for the string to reduce fragging. + result += addBoolToString(getPower(), kPowerStr, false); + result += addModeToString(getMode(), kMitsubishi112Auto, kMitsubishi112Cool, + kMitsubishi112Heat, kMitsubishi112Dry, + kMitsubishi112Auto); + result += addTempToString(getTemp()); + result += addFanToString(getFan(), kMitsubishi112FanMax, + kMitsubishi112FanLow, kMitsubishi112FanMax, + kMitsubishi112FanQuiet, kMitsubishi112FanMed); + result += addIntToString(getSwingV(), kSwingVStr); + result += kSpaceLBraceStr; + switch (getSwingV()) { + case kMitsubishi112SwingVHighest: result += kHighestStr; break; + case kMitsubishi112SwingVHigh: result += kHighStr; break; + case kMitsubishi112SwingVMiddle: result += kMiddleStr; break; + case kMitsubishi112SwingVLow: result += kLowStr; break; + case kMitsubishi112SwingVLowest: result += kLowestStr; break; + case kMitsubishi112SwingVAuto: result += kAutoStr; break; + default: result += kUnknownStr; + } + result += ')'; + result += addIntToString(getSwingH(), kSwingHStr); + result += kSpaceLBraceStr; + switch (getSwingH()) { + case kMitsubishi112SwingHLeftMax: result += kLeftMaxStr; break; + case kMitsubishi112SwingHLeft: result += kLeftStr; break; + case kMitsubishi112SwingHMiddle: result += kMiddleStr; break; + case kMitsubishi112SwingHRight: result += kRightStr; break; + case kMitsubishi112SwingHRightMax: result += kRightMaxStr; break; + case kMitsubishi112SwingHWide: result += kWideStr; break; + case kMitsubishi112SwingHAuto: result += kAutoStr; break; + default: result += kUnknownStr; + } + result += ')'; + result += addBoolToString(getQuiet(), kQuietStr); + return result; +} diff --git a/lib/IRremoteESP8266-2.7.0/src/ir_Mitsubishi.h b/lib/IRremoteESP8266-2.7.0/src/ir_Mitsubishi.h new file mode 100644 index 000000000..31021514f --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Mitsubishi.h @@ -0,0 +1,312 @@ +// Copyright 2009 Ken Shirriff +// Copyright 2017-2019 David Conran +// Copyright 2019 Mark Kuchel + +// Mitsubishi + +// Supports: +// Brand: Mitsubishi, Model: TV +// Brand: Mitsubishi, Model: HC3000 Projector +// Brand: Mitsubishi, Model: MS-GK24VA A/C +// Brand: Mitsubishi, Model: KM14A 0179213 remote +// Brand: Mitsubishi Electric, Model: PEAD-RP71JAA Ducted A/C +// Brand: Mitsubishi Electric, Model: 001CP T7WE10714 remote +// Brand: Mitsubishi Electric, Model: MSH-A24WV / MUH-A24WV A/C +// Brand: Mitsubishi Electric, Model: KPOA remote + +#ifndef IR_MITSUBISHI_H_ +#define IR_MITSUBISHI_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifndef UNIT_TEST +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" +#ifdef UNIT_TEST +#include "IRsend_test.h" +#endif + +// Mitsubishi (TV) decoding added from https://github.com/z3t0/Arduino-IRremote +// Mitsubishi (TV) sending & Mitsubishi A/C support added by David Conran + +// Constants +const uint8_t kMitsubishiAcModeOffset = 3; +const uint8_t kMitsubishiAcAuto = 0b100; +const uint8_t kMitsubishiAcCool = 0b011; +const uint8_t kMitsubishiAcDry = 0b010; +const uint8_t kMitsubishiAcHeat = 0b001; +const uint8_t kMitsubishiAcPowerOffset = 5; +const uint8_t kMitsubishiAcPower = 1 << kMitsubishiAcPowerOffset; // 0x20 +const uint8_t kMitsubishiAcFanOffset = 0; +const uint8_t kMitsubishiAcFanSize = 3; // Mask 0b111 +const uint8_t kMitsubishiAcFanAuto = 0; +const uint8_t kMitsubishiAcFanAutoOffset = 7; +const uint8_t kMitsubishiAcFanMax = 5; +const uint8_t kMitsubishiAcFanRealMax = 4; +const uint8_t kMitsubishiAcFanSilent = 6; +const uint8_t kMitsubishiAcFanQuiet = kMitsubishiAcFanSilent; +const uint8_t kMitsubishiAcMinTemp = 16; // 16C +const uint8_t kMitsubishiAcMaxTemp = 31; // 31C +const uint8_t kMitsubishiAcVaneBitOffset = 6; +const uint8_t kMitsubishiAcVaneOffset = 3; +const uint8_t kMitsubishiAcVaneSize = 3; +const uint8_t kMitsubishiAcVaneAuto = 0; +const uint8_t kMitsubishiAcVaneAutoMove = 7; +const uint8_t kMitsubishiAcNoTimer = 0; +const uint8_t kMitsubishiAcStartTimer = 5; +const uint8_t kMitsubishiAcStopTimer = 3; +const uint8_t kMitsubishiAcStartStopTimer = 7; +const uint8_t kMitsubishiAcWideVaneAuto = 8; + +const uint8_t kMitsubishi136PowerByte = 5; +const uint8_t kMitsubishi136PowerOffset = 6; +const uint8_t kMitsubishi136PowerBit = 1 << kMitsubishi136PowerOffset; +const uint8_t kMitsubishi136TempByte = 6; +const uint8_t kMitsubishi136MinTemp = 17; // 17C +const uint8_t kMitsubishi136MaxTemp = 30; // 30C +const uint8_t kMitsubishi136ModeByte = kMitsubishi136TempByte; +const uint8_t kMitsubishi136ModeOffset = 0; +const uint8_t kMitsubishi136Fan = 0b000; +const uint8_t kMitsubishi136Cool = 0b001; +const uint8_t kMitsubishi136Heat = 0b010; +const uint8_t kMitsubishi136Auto = 0b011; +const uint8_t kMitsubishi136Dry = 0b101; +const uint8_t kMitsubishi136SwingVByte = 7; +const uint8_t kMitsubishi136SwingVLowest = 0b0000; +const uint8_t kMitsubishi136SwingVLow = 0b0001; +const uint8_t kMitsubishi136SwingVHigh = 0b0010; +const uint8_t kMitsubishi136SwingVHighest = 0b0011; +const uint8_t kMitsubishi136SwingVAuto = 0b1100; +const uint8_t kMitsubishi136FanByte = kMitsubishi136SwingVByte; +// FanMask = 0b00000110; +const uint8_t kMitsubishi136FanOffset = 1; +const uint8_t kMitsubishi136FanSize = 2; // Bits +const uint8_t kMitsubishi136FanMin = 0b00; +const uint8_t kMitsubishi136FanLow = 0b01; +const uint8_t kMitsubishi136FanMed = 0b10; +const uint8_t kMitsubishi136FanMax = 0b11; +const uint8_t kMitsubishi136FanQuiet = kMitsubishi136FanMin; + +// Mitsubishi112 + +// remote_state[5] +const uint8_t kMitsubishi112PowerByte = 5; +const uint8_t kMitsubishi112PowerOffset = 2; // 0b00000100 +// remote_state[6] +const uint8_t kMitsubishi112ModeByte = 6; +const uint8_t kMitsubishi112ModeOffset = 0; // Mask 0b00000111 +const uint8_t kMitsubishi112Cool = 0b011; +const uint8_t kMitsubishi112Heat = 0b001; +const uint8_t kMitsubishi112Auto = 0b111; +const uint8_t kMitsubishi112Dry = 0b010; +// remote_state[7] +const uint8_t kMitsubishi112TempByte = 7; +const uint8_t kMitsubishi112TempSize = 4; // Mask 0b00001111 +const uint8_t kMitsubishi112MinTemp = 16; // 16C +const uint8_t kMitsubishi112MaxTemp = 31; // 31C +// remote_state[8] +const uint8_t kMitsubishi112FanByte = 8; +const uint8_t kMitsubishi112FanOffset = 0; // Mask 0b00000111; +const uint8_t kMitsubishi112FanSize = 3; +const uint8_t kMitsubishi112FanMin = 0b010; +const uint8_t kMitsubishi112FanLow = 0b011; +const uint8_t kMitsubishi112FanMed = 0b101; +const uint8_t kMitsubishi112FanMax = 0b000; +const uint8_t kMitsubishi112FanQuiet = kMitsubishi112FanMin; +const uint8_t kMitsubishi112SwingVByte = kMitsubishi112FanByte; +const uint8_t kMitsubishi112SwingVOffset = 3; // Mask 0b00111000 +const uint8_t kMitsubishi112SwingVSize = 3; // Mask 0b00111000 +const uint8_t kMitsubishi112SwingVLowest = 0b101; +const uint8_t kMitsubishi112SwingVLow = 0b100; +const uint8_t kMitsubishi112SwingVMiddle = 0b011; +const uint8_t kMitsubishi112SwingVHigh = 0b010; +const uint8_t kMitsubishi112SwingVHighest = 0b001; +const uint8_t kMitsubishi112SwingVAuto = 0b111; +// remote_state[12] +const uint8_t kMitsubishi112SwingHByte = 12; +const uint8_t kMitsubishi112SwingHSize = 4; +const uint8_t kMitsubishi112SwingHOffset = 2; // Mask 0b00111100 +const uint8_t kMitsubishi112SwingHLeftMax = 0b0001; +const uint8_t kMitsubishi112SwingHLeft = 0b0010; +const uint8_t kMitsubishi112SwingHMiddle = 0b0011; +const uint8_t kMitsubishi112SwingHRight = 0b0100; +const uint8_t kMitsubishi112SwingHRightMax = 0b0101; +const uint8_t kMitsubishi112SwingHWide = 0b1000; +const uint8_t kMitsubishi112SwingHAuto = 0b1100; + +// Legacy defines (Deprecated) +#define MITSUBISHI_AC_VANE_AUTO_MOVE kMitsubishiAcVaneAutoMove +#define MITSUBISHI_AC_VANE_AUTO kMitsubishiAcVaneAuto +#define MITSUBISHI_AC_POWER kMitsubishiAcPower +#define MITSUBISHI_AC_MIN_TEMP kMitsubishiAcMinTemp +#define MITSUBISHI_AC_MAX_TEMP kMitsubishiAcMaxTemp +#define MITSUBISHI_AC_HEAT kMitsubishiAcHeat +#define MITSUBISHI_AC_FAN_SILENT kMitsubishiAcFanSilent +#define MITSUBISHI_AC_FAN_REAL_MAX kMitsubishiAcFanRealMax +#define MITSUBISHI_AC_FAN_MAX kMitsubishiAcFanMax +#define MITSUBISHI_AC_FAN_AUTO kMitsubishiAcFanAuto +#define MITSUBISHI_AC_DRY kMitsubishiAcDry +#define MITSUBISHI_AC_COOL kMitsubishiAcCool +#define MITSUBISHI_AC_AUTO kMitsubishiAcAuto + +class IRMitsubishiAC { + public: + explicit IRMitsubishiAC(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + void stateReset(void); + static bool validChecksum(const uint8_t* data); +#if SEND_MITSUBISHI_AC + void send(const uint16_t repeat = kMitsubishiACMinRepeat); + uint8_t calibrate(void) { return _irsend.calibrate(); } +#endif // SEND_MITSUBISHI_AC + void begin(void); + void on(void); + void off(void); + void setPower(const bool on); + bool getPower(void); + void setTemp(const uint8_t degrees); + uint8_t getTemp(void); + void setFan(const uint8_t speed); + uint8_t getFan(void); + void setMode(const uint8_t mode); + uint8_t getMode(void); + void setVane(const uint8_t position); + void setWideVane(const uint8_t position); + uint8_t getVane(void); + uint8_t getWideVane(void); + uint8_t* getRaw(void); + void setRaw(const uint8_t* data); + uint8_t getClock(void); + void setClock(const uint8_t clock); + uint8_t getStartClock(void); + void setStartClock(const uint8_t clock); + uint8_t getStopClock(void); + void setStopClock(const uint8_t clock); + uint8_t getTimer(void); + void setTimer(const uint8_t timer); + 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); + stdAc::state_t toCommon(void); + String toString(void); +#ifndef UNIT_TEST + + private: + IRsend _irsend; +#else + IRsendTest _irsend; +#endif + uint8_t remote_state[kMitsubishiACStateLength]; + void checksum(void); + static uint8_t calculateChecksum(const uint8_t* data); +}; + +class IRMitsubishi136 { + public: + explicit IRMitsubishi136(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + + + void stateReset(void); +#if SEND_MITSUBISHI136 + void send(const uint16_t repeat = kMitsubishi136MinRepeat); + uint8_t calibrate(void) { return _irsend.calibrate(); } +#endif // SEND_MITSUBISHI136 + void begin(void); + static bool validChecksum(const uint8_t* data, + const uint16_t len = kMitsubishi136StateLength); + void on(void); + void off(void); + void setPower(const bool on); + bool getPower(void); + void setTemp(const uint8_t degrees); + uint8_t getTemp(void); + void setFan(const uint8_t speed); + uint8_t getFan(void); + void setMode(const uint8_t mode); + uint8_t getMode(void); + void setSwingV(const uint8_t position); + uint8_t getSwingV(void); + void setQuiet(const bool on); + bool getQuiet(void); + uint8_t* getRaw(void); + void setRaw(const uint8_t* data); + static uint8_t convertMode(const stdAc::opmode_t mode); + static uint8_t convertFan(const stdAc::fanspeed_t speed); + static uint8_t convertSwingV(const stdAc::swingv_t position); + static stdAc::opmode_t toCommonMode(const uint8_t mode); + static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); + static stdAc::swingv_t toCommonSwingV(const uint8_t pos); + stdAc::state_t toCommon(void); + String toString(void); +#ifndef UNIT_TEST + + private: + IRsend _irsend; +#else + IRsendTest _irsend; +#endif + uint8_t remote_state[kMitsubishi136StateLength]; + void checksum(void); +}; + + +class IRMitsubishi112 { + public: + explicit IRMitsubishi112(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + + + void stateReset(void); +#if SEND_MITSUBISHI112 + void send(const uint16_t repeat = kMitsubishi112MinRepeat); + uint8_t calibrate(void) { return _irsend.calibrate(); } +#endif // SEND_MITSUBISHI112 + void begin(void); + void on(void); + void off(void); + void setPower(const bool on); + bool getPower(void); + void setTemp(const uint8_t degrees); + uint8_t getTemp(void); + void setFan(const uint8_t speed); + uint8_t getFan(void); + void setMode(const uint8_t mode); + uint8_t getMode(void); + void setSwingV(const uint8_t position); + uint8_t getSwingV(void); + void setSwingH(const uint8_t position); + uint8_t getSwingH(void); + void setQuiet(const bool on); + bool getQuiet(void); + uint8_t* getRaw(void); + void setRaw(const uint8_t* data); + static uint8_t convertMode(const stdAc::opmode_t mode); + static uint8_t convertFan(const stdAc::fanspeed_t speed); + static uint8_t convertSwingV(const stdAc::swingv_t position); + static 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); + stdAc::state_t toCommon(void); + String toString(void); +#ifndef UNIT_TEST + + private: + IRsend _irsend; +#else + IRsendTest _irsend; +#endif + uint8_t remote_state[kMitsubishi112StateLength]; + void checksum(void); +}; + +#endif // IR_MITSUBISHI_H_ diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_MitsubishiHeavy.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_MitsubishiHeavy.cpp old mode 100755 new mode 100644 similarity index 63% rename from lib/IRremoteESP8266-2.6.5/src/ir_MitsubishiHeavy.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_MitsubishiHeavy.cpp index 6b4295991..35ba18548 --- a/lib/IRremoteESP8266-2.6.5/src/ir_MitsubishiHeavy.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_MitsubishiHeavy.cpp @@ -15,7 +15,9 @@ #include "ir_MitsubishiHeavy.h" #include +#include #include "IRremoteESP8266.h" +#include "IRtext.h" #include "IRutils.h" #ifndef ARDUINO #include @@ -39,6 +41,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_MITSUBISHIHEAVY // Send a MitsubishiHeavy 88 bit A/C message. @@ -94,10 +98,9 @@ void IRMitsubishiHeavy152Ac::send(const uint16_t repeat) { #endif // SEND_MITSUBISHIHEAVY void IRMitsubishiHeavy152Ac::stateReset(void) { - uint8_t i = 0; - for (; i < kMitsubishiHeavySigLength; i++) - remote_state[i] = kMitsubishiHeavyZmsSig[i]; - for (; i < kMitsubishiHeavy152StateLength - 3; i += 2) remote_state[i] = 0; + memcpy(remote_state, kMitsubishiHeavyZmsSig, kMitsubishiHeavySigLength); + for (uint8_t i = kMitsubishiHeavySigLength; + i < kMitsubishiHeavy152StateLength - 3; i += 2) remote_state[i] = 0; remote_state[17] = 0x80; } @@ -107,40 +110,32 @@ uint8_t *IRMitsubishiHeavy152Ac::getRaw(void) { } void IRMitsubishiHeavy152Ac::setRaw(const uint8_t *data) { - for (uint8_t i = 0; i < kMitsubishiHeavy152StateLength; i++) - remote_state[i] = data[i]; + memcpy(remote_state, data, kMitsubishiHeavy152StateLength); } -void IRMitsubishiHeavy152Ac::on(void) { - remote_state[5] |= kMitsubishiHeavyPowerBit; -} +void IRMitsubishiHeavy152Ac::on(void) { setPower(true); } -void IRMitsubishiHeavy152Ac::off(void) { - remote_state[5] &= ~kMitsubishiHeavyPowerBit; -} +void IRMitsubishiHeavy152Ac::off(void) { setPower(false); } void IRMitsubishiHeavy152Ac::setPower(const bool on) { - if (on) - this->on(); - else - this->off(); + setBit(&remote_state[5], kMitsubishiHeavyPowerOffset, on); } bool IRMitsubishiHeavy152Ac::getPower(void) { - return remote_state[5] & kMitsubishiHeavyPowerBit; + return GETBIT8(remote_state[5], kMitsubishiHeavyPowerOffset); } void IRMitsubishiHeavy152Ac::setTemp(const uint8_t temp) { uint8_t newtemp = temp; newtemp = std::min(newtemp, kMitsubishiHeavyMaxTemp); newtemp = std::max(newtemp, kMitsubishiHeavyMinTemp); - - remote_state[7] &= ~kMitsubishiHeavyTempMask; - remote_state[7] |= newtemp - kMitsubishiHeavyMinTemp; + setBits(&remote_state[7], kLowNibble, kNibbleSize, + newtemp - kMitsubishiHeavyMinTemp); } uint8_t IRMitsubishiHeavy152Ac::getTemp(void) { - return (remote_state[7] & kMitsubishiHeavyTempMask) + kMitsubishiHeavyMinTemp; + return GETBITS8(remote_state[7], kLowNibble, kNibbleSize) + + kMitsubishiHeavyMinTemp; } // Set the speed of the fan @@ -152,17 +147,14 @@ void IRMitsubishiHeavy152Ac::setFan(const uint8_t speed) { case kMitsubishiHeavy152FanHigh: case kMitsubishiHeavy152FanMax: case kMitsubishiHeavy152FanEcono: - case kMitsubishiHeavy152FanTurbo: - break; - default: - newspeed = kMitsubishiHeavy152FanAuto; + case kMitsubishiHeavy152FanTurbo: break; + default: newspeed = kMitsubishiHeavy152FanAuto; } - remote_state[9] &= ~kMitsubishiHeavyFanMask; - remote_state[9] |= newspeed; + setBits(&remote_state[9], kLowNibble, kNibbleSize, newspeed); } uint8_t IRMitsubishiHeavy152Ac::getFan(void) { - return remote_state[9] & kMitsubishiHeavyFanMask; + return GETBITS8(remote_state[9], kLowNibble, kNibbleSize); } void IRMitsubishiHeavy152Ac::setMode(const uint8_t mode) { @@ -176,43 +168,39 @@ void IRMitsubishiHeavy152Ac::setMode(const uint8_t mode) { default: newmode = kMitsubishiHeavyAuto; } - remote_state[5] &= ~kMitsubishiHeavyModeMask; - remote_state[5] |= newmode; + setBits(&remote_state[5], kMitsubishiHeavyModeOffset, kModeBitsSize, newmode); } uint8_t IRMitsubishiHeavy152Ac::getMode(void) { - return remote_state[5] & kMitsubishiHeavyModeMask; + return GETBITS8(remote_state[5], kMitsubishiHeavyModeOffset, kModeBitsSize); } void IRMitsubishiHeavy152Ac::setSwingVertical(const uint8_t pos) { - uint8_t newpos = std::min(pos, kMitsubishiHeavy152SwingVOff); - remote_state[11] &= ~kMitsubishiHeavy152SwingVMask; - remote_state[11] |= (newpos << 5); + setBits(&remote_state[11], kMitsubishiHeavy152SwingVOffset, + kMitsubishiHeavy152SwingVSize, + std::min(pos, kMitsubishiHeavy152SwingVOff)); } uint8_t IRMitsubishiHeavy152Ac::getSwingVertical(void) { - return remote_state[11] >> 5; + return GETBITS8(remote_state[11], kMitsubishiHeavy152SwingVOffset, + kMitsubishiHeavy152SwingVSize); } void IRMitsubishiHeavy152Ac::setSwingHorizontal(const uint8_t pos) { - uint8_t newpos = std::min(pos, kMitsubishiHeavy152SwingHOff); - remote_state[13] &= ~kMitsubishiHeavy152SwingHMask; - remote_state[13] |= (newpos & kMitsubishiHeavy152SwingHMask); + setBits(&remote_state[13], kLowNibble, kNibbleSize, + std::min(pos, kMitsubishiHeavy152SwingHOff)); } uint8_t IRMitsubishiHeavy152Ac::getSwingHorizontal(void) { - return remote_state[13] & kMitsubishiHeavy152SwingHMask; + return GETBITS8(remote_state[13], kLowNibble, kNibbleSize); } void IRMitsubishiHeavy152Ac::setNight(const bool on) { - if (on) - remote_state[15] |= kMitsubishiHeavyNightBit; - else - remote_state[15] &= ~kMitsubishiHeavyNightBit; + setBit(&remote_state[15], kMitsubishiHeavyNightOffset, on); } bool IRMitsubishiHeavy152Ac::getNight(void) { - return remote_state[15] & kMitsubishiHeavyNightBit; + return GETBIT8(remote_state[15], kMitsubishiHeavyNightOffset); } void IRMitsubishiHeavy152Ac::set3D(const bool on) { @@ -227,37 +215,28 @@ bool IRMitsubishiHeavy152Ac::get3D(void) { } void IRMitsubishiHeavy152Ac::setSilent(const bool on) { - if (on) - remote_state[15] |= kMitsubishiHeavySilentBit; - else - remote_state[15] &= ~kMitsubishiHeavySilentBit; + setBit(&remote_state[15], kMitsubishiHeavySilentOffset, on); } bool IRMitsubishiHeavy152Ac::getSilent(void) { - return remote_state[15] & kMitsubishiHeavySilentBit; + return GETBIT8(remote_state[15], kMitsubishiHeavySilentOffset); } void IRMitsubishiHeavy152Ac::setFilter(const bool on) { - if (on) - remote_state[5] |= kMitsubishiHeavyFilterBit; - else - remote_state[5] &= ~kMitsubishiHeavyFilterBit; + setBit(&remote_state[5], kMitsubishiHeavyFilterOffset, on); } bool IRMitsubishiHeavy152Ac::getFilter(void) { - return remote_state[5] & kMitsubishiHeavyFilterBit; + return GETBIT8(remote_state[5], kMitsubishiHeavyFilterOffset); } void IRMitsubishiHeavy152Ac::setClean(const bool on) { this->setFilter(on); - if (on) - remote_state[5] |= kMitsubishiHeavyCleanBit; - else - remote_state[5] &= ~kMitsubishiHeavyCleanBit; + setBit(&remote_state[5], kMitsubishiHeavyCleanOffset, on); } bool IRMitsubishiHeavy152Ac::getClean(void) { - return remote_state[5] & kMitsubishiHeavyCleanBit && this->getFilter(); + return GETBIT8(remote_state[5], kMitsubishiHeavyCleanOffset) && getFilter(); } void IRMitsubishiHeavy152Ac::setTurbo(const bool on) { @@ -314,74 +293,50 @@ bool IRMitsubishiHeavy152Ac::validChecksum(const uint8_t *state, // Convert a standard A/C mode into its native mode. uint8_t IRMitsubishiHeavy152Ac::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kMitsubishiHeavyCool; - case stdAc::opmode_t::kHeat: - return kMitsubishiHeavyHeat; - case stdAc::opmode_t::kDry: - return kMitsubishiHeavyDry; - case stdAc::opmode_t::kFan: - return kMitsubishiHeavyFan; - default: - return kMitsubishiHeavyAuto; + case stdAc::opmode_t::kCool: return kMitsubishiHeavyCool; + case stdAc::opmode_t::kHeat: return kMitsubishiHeavyHeat; + case stdAc::opmode_t::kDry: return kMitsubishiHeavyDry; + case stdAc::opmode_t::kFan: return kMitsubishiHeavyFan; + default: return kMitsubishiHeavyAuto; } } // Convert a standard A/C Fan speed into its native fan speed. uint8_t IRMitsubishiHeavy152Ac::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { - case stdAc::fanspeed_t::kMin: - return kMitsubishiHeavy152FanEcono; // Assumes Econo is slower than Low. - case stdAc::fanspeed_t::kLow: - return kMitsubishiHeavy152FanLow; - case stdAc::fanspeed_t::kMedium: - return kMitsubishiHeavy152FanMed; - case stdAc::fanspeed_t::kHigh: - return kMitsubishiHeavy152FanHigh; - case stdAc::fanspeed_t::kMax: - return kMitsubishiHeavy152FanMax; - default: - return kMitsubishiHeavy152FanAuto; + // Assumes Econo is slower than Low. + case stdAc::fanspeed_t::kMin: return kMitsubishiHeavy152FanEcono; + case stdAc::fanspeed_t::kLow: return kMitsubishiHeavy152FanLow; + case stdAc::fanspeed_t::kMedium: return kMitsubishiHeavy152FanMed; + case stdAc::fanspeed_t::kHigh: return kMitsubishiHeavy152FanHigh; + case stdAc::fanspeed_t::kMax: return kMitsubishiHeavy152FanMax; + default: return kMitsubishiHeavy152FanAuto; } } // Convert a standard A/C vertical swing into its native setting. uint8_t IRMitsubishiHeavy152Ac::convertSwingV(const stdAc::swingv_t position) { switch (position) { - case stdAc::swingv_t::kAuto: - return kMitsubishiHeavy152SwingVAuto; - case stdAc::swingv_t::kHighest: - return kMitsubishiHeavy152SwingVHighest; - case stdAc::swingv_t::kHigh: - return kMitsubishiHeavy152SwingVHigh; - case stdAc::swingv_t::kMiddle: - return kMitsubishiHeavy152SwingVMiddle; - case stdAc::swingv_t::kLow: - return kMitsubishiHeavy152SwingVLow; - case stdAc::swingv_t::kLowest: - return kMitsubishiHeavy152SwingVLowest; - default: - return kMitsubishiHeavy152SwingVOff; + case stdAc::swingv_t::kAuto: return kMitsubishiHeavy152SwingVAuto; + case stdAc::swingv_t::kHighest: return kMitsubishiHeavy152SwingVHighest; + case stdAc::swingv_t::kHigh: return kMitsubishiHeavy152SwingVHigh; + case stdAc::swingv_t::kMiddle: return kMitsubishiHeavy152SwingVMiddle; + case stdAc::swingv_t::kLow: return kMitsubishiHeavy152SwingVLow; + case stdAc::swingv_t::kLowest: return kMitsubishiHeavy152SwingVLowest; + default: return kMitsubishiHeavy152SwingVOff; } } // Convert a standard A/C horizontal swing into its native setting. uint8_t IRMitsubishiHeavy152Ac::convertSwingH(const stdAc::swingh_t position) { switch (position) { - case stdAc::swingh_t::kAuto: - return kMitsubishiHeavy152SwingHAuto; - case stdAc::swingh_t::kLeftMax: - return kMitsubishiHeavy152SwingHLeftMax; - case stdAc::swingh_t::kLeft: - return kMitsubishiHeavy152SwingHLeft; - case stdAc::swingh_t::kMiddle: - return kMitsubishiHeavy152SwingHMiddle; - case stdAc::swingh_t::kRight: - return kMitsubishiHeavy152SwingHRight; - case stdAc::swingh_t::kRightMax: - return kMitsubishiHeavy152SwingHRightMax; - default: - return kMitsubishiHeavy152SwingHOff; + case stdAc::swingh_t::kAuto: return kMitsubishiHeavy152SwingHAuto; + case stdAc::swingh_t::kLeftMax: return kMitsubishiHeavy152SwingHLeftMax; + case stdAc::swingh_t::kLeft: return kMitsubishiHeavy152SwingHLeft; + case stdAc::swingh_t::kMiddle: return kMitsubishiHeavy152SwingHMiddle; + case stdAc::swingh_t::kRight: return kMitsubishiHeavy152SwingHRight; + case stdAc::swingh_t::kRightMax: return kMitsubishiHeavy152SwingHRightMax; + default: return kMitsubishiHeavy152SwingHOff; } } @@ -390,34 +345,34 @@ stdAc::opmode_t IRMitsubishiHeavy152Ac::toCommonMode(const uint8_t mode) { switch (mode) { case kMitsubishiHeavyCool: return stdAc::opmode_t::kCool; case kMitsubishiHeavyHeat: return stdAc::opmode_t::kHeat; - case kMitsubishiHeavyDry: return stdAc::opmode_t::kDry; - case kMitsubishiHeavyFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kMitsubishiHeavyDry: return stdAc::opmode_t::kDry; + case kMitsubishiHeavyFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } // Convert a native fan speed to it's common equivalent. stdAc::fanspeed_t IRMitsubishiHeavy152Ac::toCommonFanSpeed(const uint8_t spd) { switch (spd) { - case kMitsubishiHeavy152FanMax: return stdAc::fanspeed_t::kMax; - case kMitsubishiHeavy152FanHigh: return stdAc::fanspeed_t::kHigh; - case kMitsubishiHeavy152FanMed: return stdAc::fanspeed_t::kMedium; - case kMitsubishiHeavy152FanLow: return stdAc::fanspeed_t::kLow; + case kMitsubishiHeavy152FanMax: return stdAc::fanspeed_t::kMax; + case kMitsubishiHeavy152FanHigh: return stdAc::fanspeed_t::kHigh; + case kMitsubishiHeavy152FanMed: return stdAc::fanspeed_t::kMedium; + case kMitsubishiHeavy152FanLow: return stdAc::fanspeed_t::kLow; case kMitsubishiHeavy152FanEcono: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + default: return stdAc::fanspeed_t::kAuto; } } // Convert a native vertical swing to it's common equivalent. stdAc::swingh_t IRMitsubishiHeavy152Ac::toCommonSwingH(const uint8_t pos) { switch (pos) { - case kMitsubishiHeavy152SwingHLeftMax: return stdAc::swingh_t::kLeftMax; - case kMitsubishiHeavy152SwingHLeft: return stdAc::swingh_t::kLeft; - case kMitsubishiHeavy152SwingHMiddle: return stdAc::swingh_t::kMiddle; - case kMitsubishiHeavy152SwingHRight: return stdAc::swingh_t::kRight; + case kMitsubishiHeavy152SwingHLeftMax: return stdAc::swingh_t::kLeftMax; + case kMitsubishiHeavy152SwingHLeft: return stdAc::swingh_t::kLeft; + case kMitsubishiHeavy152SwingHMiddle: return stdAc::swingh_t::kMiddle; + case kMitsubishiHeavy152SwingHRight: return stdAc::swingh_t::kRight; case kMitsubishiHeavy152SwingHRightMax: return stdAc::swingh_t::kRightMax; - case kMitsubishiHeavy152SwingHOff: return stdAc::swingh_t::kOff; - default: return stdAc::swingh_t::kAuto; + case kMitsubishiHeavy152SwingHOff: return stdAc::swingh_t::kOff; + default: return stdAc::swingh_t::kAuto; } } @@ -425,12 +380,12 @@ stdAc::swingh_t IRMitsubishiHeavy152Ac::toCommonSwingH(const uint8_t pos) { stdAc::swingv_t IRMitsubishiHeavy152Ac::toCommonSwingV(const uint8_t pos) { switch (pos) { case kMitsubishiHeavy152SwingVHighest: return stdAc::swingv_t::kHighest; - case kMitsubishiHeavy152SwingVHigh: return stdAc::swingv_t::kHigh; - case kMitsubishiHeavy152SwingVMiddle: return stdAc::swingv_t::kMiddle; - case kMitsubishiHeavy152SwingVLow: return stdAc::swingv_t::kLow; - case kMitsubishiHeavy152SwingVLowest: return stdAc::swingv_t::kLowest; - case kMitsubishiHeavy152SwingVOff: return stdAc::swingv_t::kOff; - default: return stdAc::swingv_t::kAuto; + case kMitsubishiHeavy152SwingVHigh: return stdAc::swingv_t::kHigh; + case kMitsubishiHeavy152SwingVMiddle: return stdAc::swingv_t::kMiddle; + case kMitsubishiHeavy152SwingVLow: return stdAc::swingv_t::kLow; + case kMitsubishiHeavy152SwingVLowest: return stdAc::swingv_t::kLowest; + case kMitsubishiHeavy152SwingVOff: return stdAc::swingv_t::kOff; + default: return stdAc::swingv_t::kAuto; } } @@ -463,104 +418,108 @@ stdAc::state_t IRMitsubishiHeavy152Ac::toCommon(void) { String IRMitsubishiHeavy152Ac::toString(void) { String result = ""; result.reserve(180); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kMitsubishiHeavyAuto, kMitsubishiHeavyCool, kMitsubishiHeavyHeat, kMitsubishiHeavyDry, kMitsubishiHeavyFan); result += addTempToString(getTemp()); - result += addIntToString(getFan(), F("Fan")); - result += F(" ("); + result += addIntToString(getFan(), kFanStr); + result += kSpaceLBraceStr; switch (this->getFan()) { case kMitsubishiHeavy152FanAuto: - result += F("Auto"); + result += kAutoStr; break; case kMitsubishiHeavy152FanHigh: - result += F("High"); + result += kHighStr; break; case kMitsubishiHeavy152FanLow: - result += F("Low"); + result += kLowStr; break; case kMitsubishiHeavy152FanMed: - result += F("Medium"); + result += kMedStr; break; case kMitsubishiHeavy152FanMax: - result += F("Max"); + result += kMaxStr; break; case kMitsubishiHeavy152FanEcono: - result += F("Econo"); + result += kEconoStr; break; case kMitsubishiHeavy152FanTurbo: - result += F("Turbo"); + result += kTurboStr; break; default: - result += F("UNKNOWN"); + result += kUnknownStr; } result += ')'; - result += addIntToString(getSwingVertical(), F("Swing (V)")); + result += addIntToString(getSwingVertical(), kSwingVStr); + result += kSpaceLBraceStr; switch (this->getSwingVertical()) { case kMitsubishiHeavy152SwingVAuto: - result += F(" (Auto)"); + result += kAutoStr; break; case kMitsubishiHeavy152SwingVHighest: - result += F(" (Highest)"); + result += kHighestStr; break; case kMitsubishiHeavy152SwingVHigh: - result += F(" (High)"); + result += kHighStr; break; case kMitsubishiHeavy152SwingVMiddle: - result += F(" (Middle)"); + result += kMiddleStr; break; case kMitsubishiHeavy152SwingVLow: - result += F(" (Low)"); + result += kLowStr; break; case kMitsubishiHeavy152SwingVLowest: - result += F(" (Lowest)"); + result += kLowestStr; break; case kMitsubishiHeavy152SwingVOff: - result += F(" (Off)"); + result += kOffStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } - result += addIntToString(getSwingHorizontal(), F("Swing (H)")); + result += ')'; + result += addIntToString(getSwingHorizontal(), kSwingHStr); + result += kSpaceLBraceStr; switch (this->getSwingHorizontal()) { case kMitsubishiHeavy152SwingHAuto: - result += F(" (Auto)"); + result += kAutoStr; break; case kMitsubishiHeavy152SwingHLeftMax: - result += F(" (Max Left)"); + result += kMaxLeftStr; break; case kMitsubishiHeavy152SwingHLeft: - result += F(" (Left)"); + result += kLeftStr; break; case kMitsubishiHeavy152SwingHMiddle: - result += F(" (Middle)"); + result += kMiddleStr; break; case kMitsubishiHeavy152SwingHRight: - result += F(" (Right)"); + result += kRightStr; break; case kMitsubishiHeavy152SwingHRightMax: - result += F(" (Max Right)"); + result += kMaxRightStr; break; case kMitsubishiHeavy152SwingHLeftRight: - result += F(" (Left Right)"); + result += kLeftStr + ' ' + kRightStr; break; case kMitsubishiHeavy152SwingHRightLeft: - result += F(" (Right Left)"); + result += kRightStr + ' ' + kLeftStr; break; case kMitsubishiHeavy152SwingHOff: - result += F(" (Off)"); + result += kOffStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } - result += addBoolToString(getSilent(), F("Silent")); - result += addBoolToString(getTurbo(), F("Turbo")); - result += addBoolToString(getEcono(), F("Econo")); - result += addBoolToString(getNight(), F("Night")); - result += addBoolToString(getFilter(), F("Filter")); - result += addBoolToString(get3D(), F("3D")); - result += addBoolToString(getClean(), F("Clean")); + result += ')'; + result += addBoolToString(getSilent(), kSilentStr); + result += addBoolToString(getTurbo(), kTurboStr); + result += addBoolToString(getEcono(), kEconoStr); + result += addBoolToString(getNight(), kNightStr); + result += addBoolToString(getFilter(), kFilterStr); + result += addBoolToString(get3D(), k3DStr); + result += addBoolToString(getClean(), kCleanStr); return result; } @@ -581,10 +540,9 @@ void IRMitsubishiHeavy88Ac::send(const uint16_t repeat) { #endif // SEND_MITSUBISHIHEAVY void IRMitsubishiHeavy88Ac::stateReset(void) { - uint8_t i = 0; - for (; i < kMitsubishiHeavySigLength; i++) - remote_state[i] = kMitsubishiHeavyZjsSig[i]; - for (; i < kMitsubishiHeavy88StateLength; i++) remote_state[i] = 0; + memcpy(remote_state, kMitsubishiHeavyZjsSig, kMitsubishiHeavySigLength); + for (uint8_t i = kMitsubishiHeavySigLength; i < kMitsubishiHeavy88StateLength; + i++) remote_state[i] = 0; } uint8_t *IRMitsubishiHeavy88Ac::getRaw(void) { @@ -593,40 +551,32 @@ uint8_t *IRMitsubishiHeavy88Ac::getRaw(void) { } void IRMitsubishiHeavy88Ac::setRaw(const uint8_t *data) { - for (uint8_t i = 0; i < kMitsubishiHeavy88StateLength; i++) - remote_state[i] = data[i]; + memcpy(remote_state, data, kMitsubishiHeavy88StateLength); } -void IRMitsubishiHeavy88Ac::on(void) { - remote_state[9] |= kMitsubishiHeavyPowerBit; -} +void IRMitsubishiHeavy88Ac::on(void) { setPower(true); } -void IRMitsubishiHeavy88Ac::off(void) { - remote_state[9] &= ~kMitsubishiHeavyPowerBit; -} +void IRMitsubishiHeavy88Ac::off(void) { setPower(false); } void IRMitsubishiHeavy88Ac::setPower(const bool on) { - if (on) - this->on(); - else - this->off(); + setBit(&remote_state[9], kMitsubishiHeavyPowerOffset, on); } bool IRMitsubishiHeavy88Ac::getPower(void) { - return remote_state[9] & kMitsubishiHeavyPowerBit; + return GETBIT8(remote_state[9], kMitsubishiHeavyPowerOffset); } void IRMitsubishiHeavy88Ac::setTemp(const uint8_t temp) { uint8_t newtemp = temp; newtemp = std::min(newtemp, kMitsubishiHeavyMaxTemp); newtemp = std::max(newtemp, kMitsubishiHeavyMinTemp); - - remote_state[9] &= kMitsubishiHeavyTempMask; - remote_state[9] |= ((newtemp - kMitsubishiHeavyMinTemp) << 4); + setBits(&remote_state[9], kHighNibble, kNibbleSize, + newtemp - kMitsubishiHeavyMinTemp); } uint8_t IRMitsubishiHeavy88Ac::getTemp(void) { - return (remote_state[9] >> 4) + kMitsubishiHeavyMinTemp; + return GETBITS8(remote_state[9], kHighNibble, kNibbleSize) + + kMitsubishiHeavyMinTemp; } // Set the speed of the fan @@ -637,17 +587,16 @@ void IRMitsubishiHeavy88Ac::setFan(const uint8_t speed) { case kMitsubishiHeavy88FanMed: case kMitsubishiHeavy88FanHigh: case kMitsubishiHeavy88FanTurbo: - case kMitsubishiHeavy88FanEcono: - break; - default: - newspeed = kMitsubishiHeavy88FanAuto; + case kMitsubishiHeavy88FanEcono: break; + default: newspeed = kMitsubishiHeavy88FanAuto; } - remote_state[7] &= ~kMitsubishiHeavy88FanMask; - remote_state[7] |= (newspeed << 5); + setBits(&remote_state[7], kMitsubishiHeavy88FanOffset, + kMitsubishiHeavy88FanSize, newspeed); } uint8_t IRMitsubishiHeavy88Ac::getFan(void) { - return remote_state[7] >> 5; + return GETBITS8(remote_state[7], kMitsubishiHeavy88FanOffset, + kMitsubishiHeavy88FanSize); } void IRMitsubishiHeavy88Ac::setMode(const uint8_t mode) { @@ -661,12 +610,11 @@ void IRMitsubishiHeavy88Ac::setMode(const uint8_t mode) { default: newmode = kMitsubishiHeavyAuto; } - remote_state[9] &= ~kMitsubishiHeavyModeMask; - remote_state[9] |= newmode; + setBits(&remote_state[9], kMitsubishiHeavyModeOffset, kModeBitsSize, newmode); } uint8_t IRMitsubishiHeavy88Ac::getMode(void) { - return remote_state[9] & kMitsubishiHeavyModeMask; + return GETBITS8(remote_state[9], kMitsubishiHeavyModeOffset, kModeBitsSize); } void IRMitsubishiHeavy88Ac::setSwingVertical(const uint8_t pos) { @@ -677,21 +625,22 @@ void IRMitsubishiHeavy88Ac::setSwingVertical(const uint8_t pos) { case kMitsubishiHeavy88SwingVHigh: case kMitsubishiHeavy88SwingVMiddle: case kMitsubishiHeavy88SwingVLow: - case kMitsubishiHeavy88SwingVLowest: - newpos = pos; - break; - default: - newpos = kMitsubishiHeavy88SwingVOff; + case kMitsubishiHeavy88SwingVLowest: newpos = pos; break; + default: newpos = kMitsubishiHeavy88SwingVOff; } - remote_state[5] &= ~kMitsubishiHeavy88SwingVMaskByte5; - remote_state[5] |= (newpos & kMitsubishiHeavy88SwingVMaskByte5); - remote_state[7] &= ~kMitsubishiHeavy88SwingVMaskByte7; - remote_state[7] |= (newpos & kMitsubishiHeavy88SwingVMaskByte7); + setBit(&remote_state[5], kMitsubishiHeavy88SwingVByte5Offset, + newpos & 1); + setBits(&remote_state[7], kMitsubishiHeavy88SwingVByte7Offset, + kMitsubishiHeavy88SwingVByte7Size, + newpos >> kMitsubishiHeavy88SwingVByte5Size); } uint8_t IRMitsubishiHeavy88Ac::getSwingVertical(void) { - return (remote_state[5] & kMitsubishiHeavy88SwingVMaskByte5) | - (remote_state[7] & kMitsubishiHeavy88SwingVMaskByte7); + return GETBITS8(remote_state[5], kMitsubishiHeavy88SwingVByte5Offset, + kMitsubishiHeavy88SwingVByte5Size) | + (GETBITS8(remote_state[7], kMitsubishiHeavy88SwingVByte7Offset, + kMitsubishiHeavy88SwingVByte7Size) << + kMitsubishiHeavy88SwingVByte5Size); } void IRMitsubishiHeavy88Ac::setSwingHorizontal(const uint8_t pos) { @@ -705,18 +654,22 @@ void IRMitsubishiHeavy88Ac::setSwingHorizontal(const uint8_t pos) { case kMitsubishiHeavy88SwingHRightMax: case kMitsubishiHeavy88SwingHLeftRight: case kMitsubishiHeavy88SwingHRightLeft: - case kMitsubishiHeavy88SwingH3D: - newpos = pos; - break; - default: - newpos = kMitsubishiHeavy88SwingHOff; + case kMitsubishiHeavy88SwingH3D: newpos = pos; break; + default: newpos = kMitsubishiHeavy88SwingHOff; } - remote_state[5] &= ~kMitsubishiHeavy88SwingHMask; - remote_state[5] |= newpos; + setBits(&remote_state[5], kMitsubishiHeavy88SwingHOffset1, + kMitsubishiHeavy88SwingHSize, newpos); + setBits(&remote_state[5], kMitsubishiHeavy88SwingHOffset2, + kMitsubishiHeavy88SwingHSize, + newpos >> kMitsubishiHeavy88SwingHSize); } uint8_t IRMitsubishiHeavy88Ac::getSwingHorizontal(void) { - return remote_state[5] & kMitsubishiHeavy88SwingHMask; + return GETBITS8(remote_state[5], kMitsubishiHeavy88SwingHOffset1, + kMitsubishiHeavy88SwingHSize) | + (GETBITS8(remote_state[5], kMitsubishiHeavy88SwingHOffset2, + kMitsubishiHeavy88SwingHSize) << + kMitsubishiHeavy88SwingHSize); } void IRMitsubishiHeavy88Ac::setTurbo(const bool on) { @@ -751,14 +704,11 @@ bool IRMitsubishiHeavy88Ac::get3D(void) { } void IRMitsubishiHeavy88Ac::setClean(const bool on) { - if (on) - remote_state[5] |= kMitsubishiHeavy88CleanBit; - else - remote_state[5] &= ~kMitsubishiHeavy88CleanBit; + setBit(&remote_state[5], kMitsubishiHeavy88CleanOffset, on); } bool IRMitsubishiHeavy88Ac::getClean(void) { - return remote_state[5] & kMitsubishiHeavy88CleanBit; + return GETBIT8(remote_state[5], kMitsubishiHeavy88CleanOffset); } // Verify the given state has a ZJ-S signature. @@ -791,58 +741,39 @@ uint8_t IRMitsubishiHeavy88Ac::convertMode(const stdAc::opmode_t mode) { // Convert a standard A/C Fan speed into its native fan speed. uint8_t IRMitsubishiHeavy88Ac::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { - case stdAc::fanspeed_t::kMin: - return kMitsubishiHeavy88FanEcono; // Assumes Econo is slower than Low. - case stdAc::fanspeed_t::kLow: - return kMitsubishiHeavy88FanLow; - case stdAc::fanspeed_t::kMedium: - return kMitsubishiHeavy88FanMed; - case stdAc::fanspeed_t::kHigh: - return kMitsubishiHeavy88FanHigh; - case stdAc::fanspeed_t::kMax: - return kMitsubishiHeavy88FanTurbo; - default: - return kMitsubishiHeavy88FanAuto; + // Assumes Econo is slower than Low. + case stdAc::fanspeed_t::kMin: return kMitsubishiHeavy88FanEcono; + case stdAc::fanspeed_t::kLow: return kMitsubishiHeavy88FanLow; + case stdAc::fanspeed_t::kMedium: return kMitsubishiHeavy88FanMed; + case stdAc::fanspeed_t::kHigh: return kMitsubishiHeavy88FanHigh; + case stdAc::fanspeed_t::kMax: return kMitsubishiHeavy88FanTurbo; + default: return kMitsubishiHeavy88FanAuto; } } // Convert a standard A/C vertical swing into its native setting. uint8_t IRMitsubishiHeavy88Ac::convertSwingV(const stdAc::swingv_t position) { switch (position) { - case stdAc::swingv_t::kAuto: - return kMitsubishiHeavy88SwingVAuto; - case stdAc::swingv_t::kHighest: - return kMitsubishiHeavy88SwingVHighest; - case stdAc::swingv_t::kHigh: - return kMitsubishiHeavy88SwingVHigh; - case stdAc::swingv_t::kMiddle: - return kMitsubishiHeavy88SwingVMiddle; - case stdAc::swingv_t::kLow: - return kMitsubishiHeavy88SwingVLow; - case stdAc::swingv_t::kLowest: - return kMitsubishiHeavy88SwingVLowest; - default: - return kMitsubishiHeavy88SwingVOff; + case stdAc::swingv_t::kAuto: return kMitsubishiHeavy88SwingVAuto; + case stdAc::swingv_t::kHighest: return kMitsubishiHeavy88SwingVHighest; + case stdAc::swingv_t::kHigh: return kMitsubishiHeavy88SwingVHigh; + case stdAc::swingv_t::kMiddle: return kMitsubishiHeavy88SwingVMiddle; + case stdAc::swingv_t::kLow: return kMitsubishiHeavy88SwingVLow; + case stdAc::swingv_t::kLowest: return kMitsubishiHeavy88SwingVLowest; + default: return kMitsubishiHeavy88SwingVOff; } } // Convert a standard A/C horizontal swing into its native setting. uint8_t IRMitsubishiHeavy88Ac::convertSwingH(const stdAc::swingh_t position) { switch (position) { - case stdAc::swingh_t::kAuto: - return kMitsubishiHeavy88SwingHAuto; - case stdAc::swingh_t::kLeftMax: - return kMitsubishiHeavy88SwingHLeftMax; - case stdAc::swingh_t::kLeft: - return kMitsubishiHeavy88SwingHLeft; - case stdAc::swingh_t::kMiddle: - return kMitsubishiHeavy88SwingHMiddle; - case stdAc::swingh_t::kRight: - return kMitsubishiHeavy88SwingHRight; - case stdAc::swingh_t::kRightMax: - return kMitsubishiHeavy88SwingHRightMax; - default: - return kMitsubishiHeavy88SwingHOff; + case stdAc::swingh_t::kAuto: return kMitsubishiHeavy88SwingHAuto; + case stdAc::swingh_t::kLeftMax: return kMitsubishiHeavy88SwingHLeftMax; + case stdAc::swingh_t::kLeft: return kMitsubishiHeavy88SwingHLeft; + case stdAc::swingh_t::kMiddle: return kMitsubishiHeavy88SwingHMiddle; + case stdAc::swingh_t::kRight: return kMitsubishiHeavy88SwingHRight; + case stdAc::swingh_t::kRightMax: return kMitsubishiHeavy88SwingHRightMax; + default: return kMitsubishiHeavy88SwingHOff; } } @@ -850,24 +781,24 @@ uint8_t IRMitsubishiHeavy88Ac::convertSwingH(const stdAc::swingh_t position) { stdAc::fanspeed_t IRMitsubishiHeavy88Ac::toCommonFanSpeed(const uint8_t speed) { switch (speed) { case kMitsubishiHeavy88FanTurbo: return stdAc::fanspeed_t::kMax; - case kMitsubishiHeavy88FanHigh: return stdAc::fanspeed_t::kHigh; - case kMitsubishiHeavy88FanMed: return stdAc::fanspeed_t::kMedium; - case kMitsubishiHeavy88FanLow: return stdAc::fanspeed_t::kLow; + case kMitsubishiHeavy88FanHigh: return stdAc::fanspeed_t::kHigh; + case kMitsubishiHeavy88FanMed: return stdAc::fanspeed_t::kMedium; + case kMitsubishiHeavy88FanLow: return stdAc::fanspeed_t::kLow; case kMitsubishiHeavy88FanEcono: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + default: return stdAc::fanspeed_t::kAuto; } } // Convert a native vertical swing to it's common equivalent. stdAc::swingh_t IRMitsubishiHeavy88Ac::toCommonSwingH(const uint8_t pos) { switch (pos) { - case kMitsubishiHeavy88SwingHLeftMax: return stdAc::swingh_t::kLeftMax; - case kMitsubishiHeavy88SwingHLeft: return stdAc::swingh_t::kLeft; - case kMitsubishiHeavy88SwingHMiddle: return stdAc::swingh_t::kMiddle; - case kMitsubishiHeavy88SwingHRight: return stdAc::swingh_t::kRight; + case kMitsubishiHeavy88SwingHLeftMax: return stdAc::swingh_t::kLeftMax; + case kMitsubishiHeavy88SwingHLeft: return stdAc::swingh_t::kLeft; + case kMitsubishiHeavy88SwingHMiddle: return stdAc::swingh_t::kMiddle; + case kMitsubishiHeavy88SwingHRight: return stdAc::swingh_t::kRight; case kMitsubishiHeavy88SwingHRightMax: return stdAc::swingh_t::kRightMax; - case kMitsubishiHeavy88SwingHOff: return stdAc::swingh_t::kOff; - default: return stdAc::swingh_t::kAuto; + case kMitsubishiHeavy88SwingHOff: return stdAc::swingh_t::kOff; + default: return stdAc::swingh_t::kAuto; } } @@ -875,12 +806,12 @@ stdAc::swingh_t IRMitsubishiHeavy88Ac::toCommonSwingH(const uint8_t pos) { stdAc::swingv_t IRMitsubishiHeavy88Ac::toCommonSwingV(const uint8_t pos) { switch (pos) { case kMitsubishiHeavy88SwingVHighest: return stdAc::swingv_t::kHighest; - case kMitsubishiHeavy88SwingVHigh: return stdAc::swingv_t::kHigh; - case kMitsubishiHeavy88SwingVMiddle: return stdAc::swingv_t::kMiddle; - case kMitsubishiHeavy88SwingVLow: return stdAc::swingv_t::kLow; - case kMitsubishiHeavy88SwingVLowest: return stdAc::swingv_t::kLowest; - case kMitsubishiHeavy88SwingVOff: return stdAc::swingv_t::kOff; - default: return stdAc::swingv_t::kAuto; + case kMitsubishiHeavy88SwingVHigh: return stdAc::swingv_t::kHigh; + case kMitsubishiHeavy88SwingVMiddle: return stdAc::swingv_t::kMiddle; + case kMitsubishiHeavy88SwingVLow: return stdAc::swingv_t::kLow; + case kMitsubishiHeavy88SwingVLowest: return stdAc::swingv_t::kLowest; + case kMitsubishiHeavy88SwingVOff: return stdAc::swingv_t::kOff; + default: return stdAc::swingv_t::kAuto; } } @@ -913,101 +844,105 @@ stdAc::state_t IRMitsubishiHeavy88Ac::toCommon(void) { String IRMitsubishiHeavy88Ac::toString(void) { String result = ""; result.reserve(140); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kMitsubishiHeavyAuto, kMitsubishiHeavyCool, kMitsubishiHeavyHeat, kMitsubishiHeavyDry, kMitsubishiHeavyFan); result += addTempToString(getTemp()); - result += addIntToString(getFan(), F("Fan")); - result += F(" ("); + result += addIntToString(getFan(), kFanStr); + result += kSpaceLBraceStr; switch (this->getFan()) { case kMitsubishiHeavy88FanAuto: - result += F("Auto"); + result += kAutoStr; break; case kMitsubishiHeavy88FanHigh: - result += F("High"); + result += kHighStr; break; case kMitsubishiHeavy88FanLow: - result += F("Low"); + result += kLowStr; break; case kMitsubishiHeavy88FanMed: - result += F("Medium"); + result += kMedStr; break; case kMitsubishiHeavy88FanEcono: - result += F("Econo"); + result += kEconoStr; break; case kMitsubishiHeavy88FanTurbo: - result += F("Turbo"); + result += kTurboStr; break; default: - result += F("UNKNOWN"); + result += kUnknownStr; } result += ')'; - result += addIntToString(getSwingVertical(), F("Swing (V)")); + result += addIntToString(getSwingVertical(), kSwingVStr); + result += kSpaceLBraceStr; switch (this->getSwingVertical()) { case kMitsubishiHeavy88SwingVAuto: - result += F(" (Auto)"); + result += kAutoStr; break; case kMitsubishiHeavy88SwingVHighest: - result += F(" (Highest)"); + result += kHighestStr; break; case kMitsubishiHeavy88SwingVHigh: - result += F(" (High)"); + result += kHighStr; break; case kMitsubishiHeavy88SwingVMiddle: - result += F(" (Middle)"); + result += kMiddleStr; break; case kMitsubishiHeavy88SwingVLow: - result += F(" (Low)"); + result += kLowStr; break; case kMitsubishiHeavy88SwingVLowest: - result += F(" (Lowest)"); + result += kLowestStr; break; case kMitsubishiHeavy88SwingVOff: - result += F(" (Off)"); + result += kOffStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } - result += addIntToString(getSwingHorizontal(), F("Swing (H)")); + result += ')'; + result += addIntToString(getSwingHorizontal(), kSwingHStr); + result += kSpaceLBraceStr; switch (this->getSwingHorizontal()) { case kMitsubishiHeavy88SwingHAuto: - result += F(" (Auto)"); + result += kAutoStr; break; case kMitsubishiHeavy88SwingHLeftMax: - result += F(" (Max Left)"); + result += kMaxLeftStr; break; case kMitsubishiHeavy88SwingHLeft: - result += F(" (Left)"); + result += kLeftStr; break; case kMitsubishiHeavy88SwingHMiddle: - result += F(" (Middle)"); + result += kMiddleStr; break; case kMitsubishiHeavy88SwingHRight: - result += F(" (Right)"); + result += kRightStr; break; case kMitsubishiHeavy88SwingHRightMax: - result += F(" (Max Right)"); + result += kMaxRightStr; break; case kMitsubishiHeavy88SwingHLeftRight: - result += F(" (Left Right)"); + result += kLeftStr + ' ' + kRightStr; break; case kMitsubishiHeavy88SwingHRightLeft: - result += F(" (Right Left)"); + result += kRightStr + ' ' + kLeftStr; break; case kMitsubishiHeavy88SwingH3D: - result += F(" (3D)"); + result += k3DStr; break; case kMitsubishiHeavy88SwingHOff: - result += F(" (Off)"); + result += kOffStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } - result += addBoolToString(getTurbo(), F("Turbo")); - result += addBoolToString(getEcono(), F("Econo")); - result += addBoolToString(get3D(), F("3D")); - result += addBoolToString(getClean(), F("Clean")); + result += ')'; + result += addBoolToString(getTurbo(), kTurboStr); + result += addBoolToString(getEcono(), kEconoStr); + result += addBoolToString(get3D(), k3DStr); + result += addBoolToString(getClean(), kCleanStr); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_MitsubishiHeavy.h b/lib/IRremoteESP8266-2.7.0/src/ir_MitsubishiHeavy.h old mode 100755 new mode 100644 similarity index 77% rename from lib/IRremoteESP8266-2.6.5/src/ir_MitsubishiHeavy.h rename to lib/IRremoteESP8266-2.7.0/src/ir_MitsubishiHeavy.h index c52eeb951..2c2097d03 --- a/lib/IRremoteESP8266-2.6.5/src/ir_MitsubishiHeavy.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_MitsubishiHeavy.h @@ -32,21 +32,21 @@ const uint8_t kMitsubishiHeavySigLength = 5; const uint8_t kMitsubishiHeavyZmsSig[kMitsubishiHeavySigLength] = { 0xAD, 0x51, 0x3C, 0xE5, 0x1A}; // Byte[5] -const uint8_t kMitsubishiHeavyFilterBit = 0b01000000; -const uint8_t kMitsubishiHeavyCleanBit = 0b00100000; -const uint8_t kMitsubishiHeavyPowerBit = 0b00001000; // Byte 9 on ZJS -const uint8_t kMitsubishiHeavyModeMask = 0b00000111; // Byte 9 on ZJS +const uint8_t kMitsubishiHeavyModeOffset = 0; +// Mode Mask = 0b00000111; // Byte 9 on ZJS const uint8_t kMitsubishiHeavyAuto = 0; // 0b000 const uint8_t kMitsubishiHeavyCool = 1; // 0b001 const uint8_t kMitsubishiHeavyDry = 2; // 0b010 const uint8_t kMitsubishiHeavyFan = 3; // 0b011 const uint8_t kMitsubishiHeavyHeat = 4; // 0b100 +const uint8_t kMitsubishiHeavyPowerOffset = 3; // Byte 9 on ZJS +const uint8_t kMitsubishiHeavyCleanOffset = 5; +const uint8_t kMitsubishiHeavyFilterOffset = 6; // Byte[7] -const uint8_t kMitsubishiHeavyTempMask = 0b00001111; const uint8_t kMitsubishiHeavyMinTemp = 17; // 17C const uint8_t kMitsubishiHeavyMaxTemp = 31; // 31C // Byte[9] -const uint8_t kMitsubishiHeavyFanMask = 0b00001111; // ~Byte 7 on ZJS. +// FanMask = 0b00001111; // ~Byte 7 on ZJS. const uint8_t kMitsubishiHeavy152FanAuto = 0x0; // 0b0000 const uint8_t kMitsubishiHeavy152FanLow = 0x1; // 0b0001 const uint8_t kMitsubishiHeavy152FanMed = 0x2; // 0b0010 @@ -56,7 +56,8 @@ const uint8_t kMitsubishiHeavy152FanEcono = 0x6; // 0b0110 const uint8_t kMitsubishiHeavy152FanTurbo = 0x8; // 0b1000 // Byte[11] const uint8_t kMitsubishiHeavy3DMask = 0b00010010; -const uint8_t kMitsubishiHeavy152SwingVMask = 0b11100000; +const uint8_t kMitsubishiHeavy152SwingVOffset = 5; +const uint8_t kMitsubishiHeavy152SwingVSize = 3; // Bits const uint8_t kMitsubishiHeavy152SwingVAuto = 0; // 0b000 const uint8_t kMitsubishiHeavy152SwingVHighest = 1; // 0b001 const uint8_t kMitsubishiHeavy152SwingVHigh = 2; // 0b010 @@ -65,7 +66,6 @@ const uint8_t kMitsubishiHeavy152SwingVLow = 4; // 0b100 const uint8_t kMitsubishiHeavy152SwingVLowest = 5; // 0b101 const uint8_t kMitsubishiHeavy152SwingVOff = 6; // 0b110 // Byte[13] -const uint8_t kMitsubishiHeavy152SwingHMask = 0b00001111; const uint8_t kMitsubishiHeavy152SwingHAuto = 0; // 0b0000 const uint8_t kMitsubishiHeavy152SwingHLeftMax = 1; // 0b0001 const uint8_t kMitsubishiHeavy152SwingHLeft = 2; // 0b0010 @@ -76,46 +76,50 @@ const uint8_t kMitsubishiHeavy152SwingHRightLeft = 6; // 0b0110 const uint8_t kMitsubishiHeavy152SwingHLeftRight = 7; // 0b0111 const uint8_t kMitsubishiHeavy152SwingHOff = 8; // 0b1000 // Byte[15] -const uint8_t kMitsubishiHeavyNightBit = 0b01000000; -const uint8_t kMitsubishiHeavySilentBit = 0b10000000; +const uint8_t kMitsubishiHeavyNightOffset = 6; +const uint8_t kMitsubishiHeavySilentOffset = 7; // ZJS (88 bit) const uint8_t kMitsubishiHeavyZjsSig[kMitsubishiHeavySigLength] = { 0xAD, 0x51, 0x3C, 0xD9, 0x26}; // Byte [5] -const uint8_t kMitsubishiHeavy88CleanBit = 0b00100000; -const uint8_t kMitsubishiHeavy88SwingHMask = 0b11001100; -const uint8_t kMitsubishiHeavy88SwingHAuto = 0x80; // 0b10000000 -const uint8_t kMitsubishiHeavy88SwingHLeftMax = 0x04; // 0b00000100 -const uint8_t kMitsubishiHeavy88SwingHLeft = 0x44; // 0b01000100 -const uint8_t kMitsubishiHeavy88SwingHMiddle = 0x84; // 0b10000100 -const uint8_t kMitsubishiHeavy88SwingHRight = 0xC4; // 0b11000100 -const uint8_t kMitsubishiHeavy88SwingHRightMax = 0x08; // 0b00001000 -const uint8_t kMitsubishiHeavy88SwingHRightLeft = 0x88; // 0b10001000 -const uint8_t kMitsubishiHeavy88SwingHLeftRight = 0x48; // 0b01001000 -const uint8_t kMitsubishiHeavy88SwingHOff = 0x00; // 0b00000000 -const uint8_t kMitsubishiHeavy88SwingH3D = 0xC8; // 0b11001000 +const uint8_t kMitsubishiHeavy88CleanOffset = 5; +const uint8_t kMitsubishiHeavy88SwingHOffset1 = 2; +const uint8_t kMitsubishiHeavy88SwingHOffset2 = 6; +const uint8_t kMitsubishiHeavy88SwingHSize = 2; // Bits (per offset) +const uint8_t kMitsubishiHeavy88SwingHOff = 0b0000; +const uint8_t kMitsubishiHeavy88SwingHAuto = 0b1000; +const uint8_t kMitsubishiHeavy88SwingHLeftMax = 0b0001; +const uint8_t kMitsubishiHeavy88SwingHLeft = 0b0101; +const uint8_t kMitsubishiHeavy88SwingHMiddle = 0b1001; +const uint8_t kMitsubishiHeavy88SwingHRight = 0b1101; +const uint8_t kMitsubishiHeavy88SwingHRightMax = 0b0010; +const uint8_t kMitsubishiHeavy88SwingHRightLeft = 0b1010; +const uint8_t kMitsubishiHeavy88SwingHLeftRight = 0b0110; +const uint8_t kMitsubishiHeavy88SwingH3D = 0b1110; // Byte[7] -const uint8_t kMitsubishiHeavy88FanMask = 0b11100000; +const uint8_t kMitsubishiHeavy88FanOffset = 5; +const uint8_t kMitsubishiHeavy88FanSize = 3; // Bits const uint8_t kMitsubishiHeavy88FanAuto = 0; // 0b000 const uint8_t kMitsubishiHeavy88FanLow = 2; // 0b010 const uint8_t kMitsubishiHeavy88FanMed = 3; // 0b011 const uint8_t kMitsubishiHeavy88FanHigh = 4; // 0b100 const uint8_t kMitsubishiHeavy88FanTurbo = 6; // 0b110 const uint8_t kMitsubishiHeavy88FanEcono = 7; // 0b111 -const uint8_t kMitsubishiHeavy88SwingVMaskByte5 = 0b00000010; -const uint8_t kMitsubishiHeavy88SwingVMaskByte7 = 0b00011000; -const uint8_t kMitsubishiHeavy88SwingVMask = - kMitsubishiHeavy88SwingVMaskByte5 | kMitsubishiHeavy88SwingVMaskByte7; - // i.e. 0b00011010 -const uint8_t kMitsubishiHeavy88SwingVAuto = 0b00010000; // 0x10 -const uint8_t kMitsubishiHeavy88SwingVHighest = 0b00011000; // 0x18 -const uint8_t kMitsubishiHeavy88SwingVHigh = 0b00000010; // 0x02 -const uint8_t kMitsubishiHeavy88SwingVMiddle = 0b00001010; // 0x0A -const uint8_t kMitsubishiHeavy88SwingVLow = 0b00010010; // 0x12 -const uint8_t kMitsubishiHeavy88SwingVLowest = 0b00011010; // 0x1A -const uint8_t kMitsubishiHeavy88SwingVOff = 0b00000000; // 0x00 +const uint8_t kMitsubishiHeavy88SwingVByte5Offset = 1; +const uint8_t kMitsubishiHeavy88SwingVByte5Size = 1; +const uint8_t kMitsubishiHeavy88SwingVByte7Offset = 3; +const uint8_t kMitsubishiHeavy88SwingVByte7Size = 2; + + // Mask 0b111 +const uint8_t kMitsubishiHeavy88SwingVOff = 0b000; // 0 +const uint8_t kMitsubishiHeavy88SwingVAuto = 0b100; // 4 +const uint8_t kMitsubishiHeavy88SwingVHighest = 0b110; // 6 +const uint8_t kMitsubishiHeavy88SwingVHigh = 0b001; // 1 +const uint8_t kMitsubishiHeavy88SwingVMiddle = 0b011; // 3 +const uint8_t kMitsubishiHeavy88SwingVLow = 0b101; // 5 +const uint8_t kMitsubishiHeavy88SwingVLowest = 0b111; // 7 // Byte[9] is Power & Mode & Temp. diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_NEC.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_NEC.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_NEC.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_NEC.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_NEC.h b/lib/IRremoteESP8266-2.7.0/src/ir_NEC.h old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_NEC.h rename to lib/IRremoteESP8266-2.7.0/src/ir_NEC.h diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Neoclima.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Neoclima.cpp old mode 100755 new mode 100644 similarity index 69% rename from lib/IRremoteESP8266-2.6.5/src/ir_Neoclima.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Neoclima.cpp index 353d43b14..8b944293e --- a/lib/IRremoteESP8266-2.6.5/src/ir_Neoclima.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Neoclima.cpp @@ -15,8 +15,10 @@ #include "ir_Neoclima.h" #include +#include #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // Constants @@ -34,6 +36,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_NEOCLIMA // Send a Neoclima message. @@ -73,13 +77,9 @@ IRNeoclimaAc::IRNeoclimaAc(const uint16_t pin, const bool inverted, } void IRNeoclimaAc::stateReset(void) { - for (uint8_t i = 0; i < kNeoclimaStateLength; i++) - remote_state[i] = 0x0; - remote_state[7] = 0x6A; - remote_state[8] = 0x00; - remote_state[9] = 0x2A; - remote_state[10] = 0xA5; - // [11] is the checksum. + static const uint8_t kReset[kNeoclimaStateLength] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x00, 0x2A, 0xA5}; + setRaw(kReset); } void IRNeoclimaAc::begin(void) { _irsend.begin(); } @@ -104,8 +104,7 @@ void IRNeoclimaAc::checksum(uint16_t length) { #if SEND_NEOCLIMA void IRNeoclimaAc::send(const uint16_t repeat) { - this->checksum(); - _irsend.sendNeoclima(remote_state, kNeoclimaStateLength, repeat); + _irsend.sendNeoclima(getRaw(), kNeoclimaStateLength, repeat); } #endif // SEND_NEOCLIMA @@ -115,8 +114,7 @@ uint8_t *IRNeoclimaAc::getRaw(void) { } void IRNeoclimaAc::setRaw(const uint8_t new_code[], const uint16_t length) { - for (uint8_t i = 0; i < length && i < kNeoclimaStateLength; i++) - remote_state[i] = new_code[i]; + memcpy(remote_state, new_code, std::min(length, kNeoclimaStateLength)); } @@ -138,8 +136,8 @@ void IRNeoclimaAc::setButton(const uint8_t button) { case kNeoclimaButtonFresh: case kNeoclimaButton8CHeat: case kNeoclimaButtonTurbo: - remote_state[5] &= ~kNeoclimaButtonMask; - remote_state[5] |= button; + setBits(&remote_state[5], kNeoclimaButtonOffset, kNeoclimaButtonSize, + button); break; default: this->setButton(kNeoclimaButtonPower); @@ -147,7 +145,7 @@ void IRNeoclimaAc::setButton(const uint8_t button) { } uint8_t IRNeoclimaAc::getButton(void) { - return remote_state[5] & kNeoclimaButtonMask; + return GETBITS8(remote_state[5], kNeoclimaButtonOffset, kNeoclimaButtonSize); } void IRNeoclimaAc::on(void) { this->setPower(true); } @@ -156,14 +154,11 @@ void IRNeoclimaAc::off(void) { this->setPower(false); } void IRNeoclimaAc::setPower(const bool on) { this->setButton(kNeoclimaButtonPower); - if (on) - remote_state[7] |= kNeoclimaPowerMask; - else - remote_state[7] &= ~kNeoclimaPowerMask; + setBit(&remote_state[7], kNeoclimaPowerOffset, on); } bool IRNeoclimaAc::getPower(void) { - return remote_state[7] & kNeoclimaPowerMask; + return GETBIT8(remote_state[7], kNeoclimaPowerOffset); } void IRNeoclimaAc::setMode(const uint8_t mode) { @@ -176,8 +171,7 @@ void IRNeoclimaAc::setMode(const uint8_t mode) { case kNeoclimaCool: case kNeoclimaFan: case kNeoclimaHeat: - remote_state[9] &= ~kNeoclimaModeMask; - remote_state[9] |= (mode << 5); + setBits(&remote_state[9], kNeoclimaModeOffset, kModeBitsSize, mode); this->setButton(kNeoclimaButtonMode); break; default: @@ -187,22 +181,17 @@ void IRNeoclimaAc::setMode(const uint8_t mode) { } uint8_t IRNeoclimaAc::getMode(void) { - return (remote_state[9] & kNeoclimaModeMask) >> 5; + return GETBITS8(remote_state[9], kNeoclimaModeOffset, kModeBitsSize); } // Convert a standard A/C mode into its native mode. uint8_t IRNeoclimaAc::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kNeoclimaCool; - case stdAc::opmode_t::kHeat: - return kNeoclimaHeat; - case stdAc::opmode_t::kDry: - return kNeoclimaDry; - case stdAc::opmode_t::kFan: - return kNeoclimaFan; - default: - return kNeoclimaAuto; + case stdAc::opmode_t::kCool: return kNeoclimaCool; + case stdAc::opmode_t::kHeat: return kNeoclimaHeat; + case stdAc::opmode_t::kDry: return kNeoclimaDry; + case stdAc::opmode_t::kFan: return kNeoclimaFan; + default: return kNeoclimaAuto; } } @@ -211,9 +200,9 @@ stdAc::opmode_t IRNeoclimaAc::toCommonMode(const uint8_t mode) { switch (mode) { case kNeoclimaCool: return stdAc::opmode_t::kCool; case kNeoclimaHeat: return stdAc::opmode_t::kHeat; - case kNeoclimaDry: return stdAc::opmode_t::kDry; - case kNeoclimaFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kNeoclimaDry: return stdAc::opmode_t::kDry; + case kNeoclimaFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -226,13 +215,14 @@ void IRNeoclimaAc::setTemp(const uint8_t temp) { this->setButton(kNeoclimaButtonTempDown); else if (newtemp > oldtemp) this->setButton(kNeoclimaButtonTempUp); - remote_state[9] = (remote_state[9] & ~kNeoclimaTempMask) | - (newtemp - kNeoclimaMinTemp); + setBits(&remote_state[9], kNeoclimaTempOffset, kNeoclimaTempSize, + newtemp - kNeoclimaMinTemp); } // Return the set temp. in deg C uint8_t IRNeoclimaAc::getTemp(void) { - return (remote_state[9] & kNeoclimaTempMask) + kNeoclimaMinTemp; + return GETBITS8(remote_state[9], kNeoclimaTempOffset, kNeoclimaTempSize) + + kNeoclimaMinTemp; } // Set the speed of the fan, 0-3, 0 is auto, 1-3 is the speed @@ -247,8 +237,7 @@ void IRNeoclimaAc::setFan(const uint8_t speed) { } // FALL-THRU case kNeoclimaFanLow: - remote_state[7] &= ~kNeoclimaFanMask; - remote_state[7] |= (speed << 5); + setBits(&remote_state[7], kNeoclimaFanOffest, kNeoclimaFanSize, speed); this->setButton(kNeoclimaButtonFanSpeed); break; default: @@ -258,22 +247,18 @@ void IRNeoclimaAc::setFan(const uint8_t speed) { } uint8_t IRNeoclimaAc::getFan(void) { - return (remote_state[7] & kNeoclimaFanMask) >> 5; + return GETBITS8(remote_state[7], kNeoclimaFanOffest, kNeoclimaFanSize); } // Convert a standard A/C Fan speed into its native fan speed. uint8_t IRNeoclimaAc::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kNeoclimaFanLow; - case stdAc::fanspeed_t::kMedium: - return kNeoclimaFanMed; + case stdAc::fanspeed_t::kLow: return kNeoclimaFanLow; + case stdAc::fanspeed_t::kMedium: return kNeoclimaFanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kNeoclimaFanHigh; - default: - return kNeoclimaFanAuto; + case stdAc::fanspeed_t::kMax: return kNeoclimaFanHigh; + default: return kNeoclimaFanAuto; } } @@ -281,106 +266,86 @@ uint8_t IRNeoclimaAc::convertFan(const stdAc::fanspeed_t speed) { stdAc::fanspeed_t IRNeoclimaAc::toCommonFanSpeed(const uint8_t speed) { switch (speed) { case kNeoclimaFanHigh: return stdAc::fanspeed_t::kMax; - case kNeoclimaFanMed: return stdAc::fanspeed_t::kMedium; - case kNeoclimaFanLow: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kNeoclimaFanMed: return stdAc::fanspeed_t::kMedium; + case kNeoclimaFanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } void IRNeoclimaAc::setSleep(const bool on) { this->setButton(kNeoclimaButtonSleep); - if (on) - remote_state[7] |= kNeoclimaSleepMask; - else - remote_state[7] &= ~kNeoclimaSleepMask; + setBit(&remote_state[7], kNeoclimaSleepOffset, on); } bool IRNeoclimaAc::getSleep(void) { - return remote_state[7] & kNeoclimaSleepMask; + return GETBIT8(remote_state[7], kNeoclimaSleepOffset); } // A.k.a. Swing void IRNeoclimaAc::setSwingV(const bool on) { this->setButton(kNeoclimaButtonSwing); - remote_state[7] &= ~kNeoclimaSwingVMask; - remote_state[7] |= on ? kNeoclimaSwingVOn : kNeoclimaSwingVOff; + setBits(&remote_state[7], kNeoclimaSwingVOffset, kNeoclimaSwingVSize, + on ? kNeoclimaSwingVOn : kNeoclimaSwingVOff); } bool IRNeoclimaAc::getSwingV(void) { - return (remote_state[7] & kNeoclimaSwingVMask) == kNeoclimaSwingVOn; + return GETBITS8(remote_state[7], kNeoclimaSwingVOffset, + kNeoclimaSwingVSize) == kNeoclimaSwingVOn; } // A.k.a. Air Flow void IRNeoclimaAc::setSwingH(const bool on) { this->setButton(kNeoclimaButtonAirFlow); - if (on) - remote_state[7] &= ~kNeoclimaSwingHMask; - else - remote_state[7] |= kNeoclimaSwingHMask; + setBit(&remote_state[7], kNeoclimaSwingHOffset, !on); // Cleared when `on` } bool IRNeoclimaAc::getSwingH(void) { - return !(remote_state[7] & kNeoclimaSwingHMask); + return !GETBIT8(remote_state[7], kNeoclimaSwingHOffset); } void IRNeoclimaAc::setTurbo(const bool on) { this->setButton(kNeoclimaButtonTurbo); - if (on) - remote_state[3] |= kNeoclimaTurboMask; - else - remote_state[3] &= ~kNeoclimaTurboMask; + setBit(&remote_state[3], kNeoclimaTurboOffset, on); } bool IRNeoclimaAc::getTurbo(void) { - return remote_state[3] & kNeoclimaTurboMask; + return GETBIT8(remote_state[3], kNeoclimaTurboOffset); } void IRNeoclimaAc::setFresh(const bool on) { this->setButton(kNeoclimaButtonFresh); - if (on) - remote_state[5] |= kNeoclimaFreshMask; - else - remote_state[5] &= ~kNeoclimaFreshMask; + setBit(&remote_state[5], kNeoclimaFreshOffset, on); } bool IRNeoclimaAc::getFresh(void) { - return remote_state[5] & kNeoclimaFreshMask; + return GETBIT8(remote_state[5], kNeoclimaFreshOffset); } void IRNeoclimaAc::setHold(const bool on) { this->setButton(kNeoclimaButtonHold); - if (on) - remote_state[3] |= kNeoclimaHoldMask; - else - remote_state[3] &= ~kNeoclimaHoldMask; + setBit(&remote_state[3], kNeoclimaHoldOffset, on); } bool IRNeoclimaAc::getHold(void) { - return remote_state[3] & kNeoclimaHoldMask; + return GETBIT8(remote_state[3], kNeoclimaHoldOffset); } void IRNeoclimaAc::setIon(const bool on) { this->setButton(kNeoclimaButtonIon); - if (on) - remote_state[1] |= kNeoclimaIonMask; - else - remote_state[1] &= ~kNeoclimaIonMask; + setBit(&remote_state[1], kNeoclimaIonOffset, on); } bool IRNeoclimaAc::getIon(void) { - return remote_state[1] & kNeoclimaIonMask; + return GETBIT8(remote_state[1], kNeoclimaIonOffset); } void IRNeoclimaAc::setLight(const bool on) { this->setButton(kNeoclimaButtonLight); - if (on) - remote_state[3] |= kNeoclimaLightMask; - else - remote_state[3] &= ~kNeoclimaLightMask; + setBit(&remote_state[3], kNeoclimaLightOffset, on); } bool IRNeoclimaAc::getLight(void) { - return remote_state[3] & kNeoclimaLightMask; + return GETBIT8(remote_state[3], kNeoclimaLightOffset); } // This feature maintains the room temperature steadily at 8°C and prevents the @@ -388,26 +353,20 @@ bool IRNeoclimaAc::getLight(void) { // nobody is at home over a longer period during severe winter. void IRNeoclimaAc::set8CHeat(const bool on) { this->setButton(kNeoclimaButton8CHeat); - if (on) - remote_state[1] |= kNeoclima8CHeatMask; - else - remote_state[1] &= ~kNeoclima8CHeatMask; + setBit(&remote_state[1], kNeoclima8CHeatOffset, on); } bool IRNeoclimaAc::get8CHeat(void) { - return remote_state[1] & kNeoclima8CHeatMask; + return GETBIT8(remote_state[1], kNeoclima8CHeatOffset); } void IRNeoclimaAc::setEye(const bool on) { this->setButton(kNeoclimaButtonEye); - if (on) - remote_state[3] |= kNeoclimaEyeMask; - else - remote_state[3] &= ~kNeoclimaEyeMask; + setBit(&remote_state[3], kNeoclimaEyeOffset, on); } bool IRNeoclimaAc::getEye(void) { - return remote_state[3] & kNeoclimaEyeMask; + return GETBIT8(remote_state[3], kNeoclimaEyeOffset); } /* DISABLED @@ -456,44 +415,44 @@ stdAc::state_t IRNeoclimaAc::toCommon(void) { String IRNeoclimaAc::toString(void) { String result = ""; result.reserve(100); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kNeoclimaAuto, kNeoclimaCool, kNeoclimaHeat, kNeoclimaDry, kNeoclimaFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kNeoclimaFanHigh, kNeoclimaFanLow, kNeoclimaFanAuto, kNeoclimaFanAuto, kNeoclimaFanMed); - result += addBoolToString(getSwingV(), F("Swing(V)")); - result += addBoolToString(getSwingH(), F("Swing(H)")); - result += addBoolToString(getSleep(), F("Sleep")); - result += addBoolToString(getTurbo(), F("Turbo")); - result += addBoolToString(getHold(), F("Hold")); - result += addBoolToString(getIon(), F("Ion")); - result += addBoolToString(getEye(), F("Eye")); - result += addBoolToString(getLight(), F("Light")); - result += addBoolToString(getFollow(), F("Follow")); - result += addBoolToString(get8CHeat(), F("8C Heat")); - result += addBoolToString(getFresh(), F("Fresh")); - result += addIntToString(getButton(), F("Button")); - result += F(" ("); + result += addBoolToString(getSwingV(), kSwingVStr); + result += addBoolToString(getSwingH(), kSwingHStr); + result += addBoolToString(getSleep(), kSleepStr); + result += addBoolToString(getTurbo(), kTurboStr); + result += addBoolToString(getHold(), kHoldStr); + result += addBoolToString(getIon(), kIonStr); + result += addBoolToString(getEye(), kEyeStr); + result += addBoolToString(getLight(), kLightStr); + result += addBoolToString(getFollow(), kFollowStr); + result += addBoolToString(get8CHeat(), k8CHeatStr); + result += addBoolToString(getFresh(), kFreshStr); + result += addIntToString(getButton(), kButtonStr); + result += kSpaceLBraceStr; switch (this->getButton()) { - case kNeoclimaButtonPower: result += F("Power"); break; - case kNeoclimaButtonMode: result += F("Mode"); break; - case kNeoclimaButtonTempUp: result += F("Temp Up"); break; - case kNeoclimaButtonTempDown: result += F("Temp Down"); break; - case kNeoclimaButtonSwing: result += F("Swing"); break; - case kNeoclimaButtonFanSpeed: result += F("Speed"); break; - case kNeoclimaButtonAirFlow: result += F("Air Flow"); break; - case kNeoclimaButtonHold: result += F("Hold"); break; - case kNeoclimaButtonSleep: result += F("Sleep"); break; - case kNeoclimaButtonLight: result += F("Light"); break; - case kNeoclimaButtonEye: result += F("Eye"); break; - case kNeoclimaButtonFollow: result += F("Follow"); break; - case kNeoclimaButtonIon: result += F("Ion"); break; - case kNeoclimaButtonFresh: result += F("Fresh"); break; - case kNeoclimaButton8CHeat: result += F("8C Heat"); break; - case kNeoclimaButtonTurbo: result += F("Turbo"); break; + case kNeoclimaButtonPower: result += kPowerStr; break; + case kNeoclimaButtonMode: result += kModeStr; break; + case kNeoclimaButtonTempUp: result += kTempUpStr; break; + case kNeoclimaButtonTempDown: result += kTempDownStr; break; + case kNeoclimaButtonSwing: result += kSwingStr; break; + case kNeoclimaButtonFanSpeed: result += kFanStr; break; + case kNeoclimaButtonAirFlow: result += kAirFlowStr; break; + case kNeoclimaButtonHold: result += kHoldStr; break; + case kNeoclimaButtonSleep: result += kSleepStr; break; + case kNeoclimaButtonLight: result += kLightStr; break; + case kNeoclimaButtonEye: result += kEyeStr; break; + case kNeoclimaButtonFollow: result += kFollowStr; break; + case kNeoclimaButtonIon: result += kIonStr; break; + case kNeoclimaButtonFresh: result += kFreshStr; break; + case kNeoclimaButton8CHeat: result += k8CHeatStr; break; + case kNeoclimaButtonTurbo: result += kTurboStr; break; default: - result += F("Unknown"); + result += kUnknownStr; } result += ')'; return result; diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Neoclima.h b/lib/IRremoteESP8266-2.7.0/src/ir_Neoclima.h old mode 100755 new mode 100644 similarity index 83% rename from lib/IRremoteESP8266-2.6.5/src/ir_Neoclima.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Neoclima.h index 9e99c8a9e..360c665d6 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Neoclima.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Neoclima.h @@ -28,16 +28,17 @@ // Constants // state[1] -const uint8_t kNeoclima8CHeatMask = 0b00000010; -const uint8_t kNeoclimaIonMask = 0b00000100; +const uint8_t kNeoclima8CHeatOffset = 1; +const uint8_t kNeoclimaIonOffset = 2; // state[3] -const uint8_t kNeoclimaLightMask = 0b00000001; -const uint8_t kNeoclimaHoldMask = 0b00000100; -const uint8_t kNeoclimaTurboMask = 0b00001000; -const uint8_t kNeoclimaEyeMask = 0b01000000; +const uint8_t kNeoclimaLightOffset = 0; +const uint8_t kNeoclimaHoldOffset = 2; +const uint8_t kNeoclimaTurboOffset = 3; +const uint8_t kNeoclimaEyeOffset = 6; // state[5] -const uint8_t kNeoclimaFreshMask = 0b10000000; -const uint8_t kNeoclimaButtonMask = 0b00011111; +const uint8_t kNeoclimaFreshOffset = 7; +const uint8_t kNeoclimaButtonOffset = 0; +const uint8_t kNeoclimaButtonSize = 5; const uint8_t kNeoclimaButtonPower = 0x00; const uint8_t kNeoclimaButtonMode = 0x01; const uint8_t kNeoclimaButtonTempUp = 0x02; @@ -55,13 +56,15 @@ const uint8_t kNeoclimaButtonIon = 0x14; const uint8_t kNeoclimaButtonFresh = 0x15; const uint8_t kNeoclimaButton8CHeat = 0x1D; // state[7] -const uint8_t kNeoclimaSleepMask = 0b00000001; -const uint8_t kNeoclimaPowerMask = 0b00000010; -const uint8_t kNeoclimaSwingVMask = 0b00001100; -const uint8_t kNeoclimaSwingVOn = 0b00000100; -const uint8_t kNeoclimaSwingVOff = 0b00001000; -const uint8_t kNeoclimaSwingHMask = 0b00010000; -const uint8_t kNeoclimaFanMask = 0b01100000; +const uint8_t kNeoclimaSleepOffset = 0; +const uint8_t kNeoclimaPowerOffset = 1; +const uint8_t kNeoclimaSwingVOffset = 2; +const uint8_t kNeoclimaSwingVSize = 2; // Bits +const uint8_t kNeoclimaSwingVOn = 0b01; +const uint8_t kNeoclimaSwingVOff = 0b10; +const uint8_t kNeoclimaSwingHOffset = 4; +const uint8_t kNeoclimaFanOffest = 5; +const uint8_t kNeoclimaFanSize = 2; const uint8_t kNeoclimaFanAuto = 0b00; const uint8_t kNeoclimaFanHigh = 0b01; const uint8_t kNeoclimaFanMed = 0b10; @@ -69,10 +72,11 @@ const uint8_t kNeoclimaFanLow = 0b11; // state[8] const uint8_t kNeoclimaFollowMe = 0x5D; // Also 0x5F // state[9] -const uint8_t kNeoclimaTempMask = 0b00011111; +const uint8_t kNeoclimaTempOffset = 0; +const uint8_t kNeoclimaTempSize = 5; // Bits const uint8_t kNeoclimaMinTemp = 16; // 16C const uint8_t kNeoclimaMaxTemp = 32; // 32C -const uint8_t kNeoclimaModeMask = 0b11100000; +const uint8_t kNeoclimaModeOffset = 5; const uint8_t kNeoclimaAuto = 0b000; const uint8_t kNeoclimaCool = 0b001; const uint8_t kNeoclimaDry = 0b010; diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Nikai.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Nikai.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Nikai.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Nikai.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Panasonic.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Panasonic.cpp old mode 100755 new mode 100644 similarity index 72% rename from lib/IRremoteESP8266-2.6.5/src/ir_Panasonic.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Panasonic.cpp index 1a24ac41f..a25f4cb02 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Panasonic.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Panasonic.cpp @@ -5,11 +5,13 @@ #include "ir_Panasonic.h" #include +#include #ifndef ARDUINO #include #endif #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // Panasonic protocol originally added by Kristian Lauszus from: @@ -66,8 +68,11 @@ using irutils::addFanToString; using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; +using irutils::addModelToString; using irutils::addTempToString; using irutils::minsToString; +using irutils::setBit; +using irutils::setBits; #if (SEND_PANASONIC || SEND_DENON) // Send a Panasonic formatted message. @@ -165,13 +170,13 @@ bool IRrecv::decodePanasonic(decode_results *results, const uint16_t nbits, kPanasonicBitMark, kPanasonicEndGap, true)) return false; // Compliance uint32_t address = data >> 32; - uint32_t command = data & 0xFFFFFFFF; + uint32_t command = data; if (strict) { if (address != manufacturer) // Verify the Manufacturer code. return false; // Verify the checksum. - uint8_t checksumOrig = data & 0xFF; - uint8_t checksumCalc = ((data >> 24) ^ (data >> 16) ^ (data >> 8)) & 0xFF; + uint8_t checksumOrig = data; + uint8_t checksumCalc = (data >> 24) ^ (data >> 16) ^ (data >> 8); if (checksumOrig != checksumCalc) return false; } @@ -179,7 +184,7 @@ bool IRrecv::decodePanasonic(decode_results *results, const uint16_t nbits, results->value = data; results->address = address; results->command = command; - results->decode_type = PANASONIC; + results->decode_type = decode_type_t::PANASONIC; results->bits = nbits; return true; } @@ -228,8 +233,7 @@ IRPanasonicAc::IRPanasonicAc(const uint16_t pin, const bool inverted, : _irsend(pin, inverted, use_modulation) { this->stateReset(); } void IRPanasonicAc::stateReset(void) { - for (uint8_t i = 0; i < kPanasonicAcStateLength; i++) - remote_state[i] = kPanasonicKnownGoodState[i]; + memcpy(remote_state, kPanasonicKnownGoodState, kPanasonicAcStateLength); _temp = 25; // An initial saved desired temp. Completely made up. _swingh = kPanasonicAcSwingHMiddle; // A similar made up value for H Swing. } @@ -258,22 +262,20 @@ void IRPanasonicAc::fixChecksum(const uint16_t length) { #if SEND_PANASONIC_AC void IRPanasonicAc::send(const uint16_t repeat) { - this->fixChecksum(); - _irsend.sendPanasonicAC(remote_state, kPanasonicAcStateLength, repeat); + _irsend.sendPanasonicAC(getRaw(), kPanasonicAcStateLength, repeat); } #endif // SEND_PANASONIC_AC void IRPanasonicAc::setModel(const panasonic_ac_remote_model_t model) { switch (model) { - case kPanasonicDke: - case kPanasonicJke: - case kPanasonicLke: - case kPanasonicNke: - case kPanasonicCkp: - case kPanasonicRkr: - break; - default: // Only proceed if we know what to do. - return; + case panasonic_ac_remote_model_t::kPanasonicDke: + case panasonic_ac_remote_model_t::kPanasonicJke: + case panasonic_ac_remote_model_t::kPanasonicLke: + case panasonic_ac_remote_model_t::kPanasonicNke: + case panasonic_ac_remote_model_t::kPanasonicCkp: + case panasonic_ac_remote_model_t::kPanasonicRkr: break; + // Only proceed if we know what to do. + default: return; } // clear & set the various bits and bytes. remote_state[13] &= 0xF0; @@ -314,14 +316,17 @@ panasonic_ac_remote_model_t IRPanasonicAc::getModel(void) { if (remote_state[23] == 0x89) return kPanasonicRkr; if (remote_state[17] == 0x00) { if ((remote_state[21] & 0x10) && (remote_state[23] & 0x01)) - return kPanasonicCkp; - if (remote_state[23] & 0x80) return kPanasonicJke; + return panasonic_ac_remote_model_t::kPanasonicCkp; + if (remote_state[23] & 0x80) + return panasonic_ac_remote_model_t::kPanasonicJke; } if (remote_state[17] == 0x06 && (remote_state[13] & 0x0F) == 0x02) - return kPanasonicLke; - if (remote_state[23] == 0x01) return kPanasonicDke; - if (remote_state[17] == 0x06) return kPanasonicNke; - return kPanasonicUnknown; + return panasonic_ac_remote_model_t::kPanasonicLke; + if (remote_state[23] == 0x01) + return panasonic_ac_remote_model_t::kPanasonicDke; + if (remote_state[17] == 0x06) + return panasonic_ac_remote_model_t::kPanasonicNke; + return panasonic_ac_remote_model_t::kPanasonicUnknown; // Default } uint8_t *IRPanasonicAc::getRaw(void) { @@ -330,9 +335,7 @@ uint8_t *IRPanasonicAc::getRaw(void) { } void IRPanasonicAc::setRaw(const uint8_t state[]) { - for (uint8_t i = 0; i < kPanasonicAcStateLength; i++) { - remote_state[i] = state[i]; - } + memcpy(remote_state, state, kPanasonicAcStateLength); } // Control the power state of the A/C unit. @@ -347,24 +350,23 @@ void IRPanasonicAc::setRaw(const uint8_t state[]) { // For all other models, setPower(true) should set the internal state to // turn it on, and setPower(false) should turn it off. void IRPanasonicAc::setPower(const bool on) { - if (on) - this->on(); - else - this->off(); + setBit(&remote_state[13], kPanasonicAcPowerOffset, on); } // Return the A/C power state of the remote. // Except for CKP models, where it returns if the power state will be toggled // on the A/C unit when the next message is sent. bool IRPanasonicAc::getPower(void) { - return (remote_state[13] & kPanasonicAcPower) == kPanasonicAcPower; + return GETBIT8(remote_state[13], kPanasonicAcPowerOffset); } -void IRPanasonicAc::on(void) { remote_state[13] |= kPanasonicAcPower; } +void IRPanasonicAc::on(void) { setPower(true); } -void IRPanasonicAc::off(void) { remote_state[13] &= ~kPanasonicAcPower; } +void IRPanasonicAc::off(void) { setPower(false); } -uint8_t IRPanasonicAc::getMode(void) { return remote_state[13] >> 4; } +uint8_t IRPanasonicAc::getMode(void) { + return GETBITS8(remote_state[13], kHighNibble, kModeBitsSize); +} void IRPanasonicAc::setMode(const uint8_t desired) { uint8_t mode = kPanasonicAcAuto; // Default to Auto mode. @@ -384,10 +386,13 @@ void IRPanasonicAc::setMode(const uint8_t desired) { break; } remote_state[13] &= 0x0F; // Clear the previous mode bits. - remote_state[13] |= mode << 4; + setBits(&remote_state[13], kHighNibble, kModeBitsSize, mode); } -uint8_t IRPanasonicAc::getTemp(void) { return remote_state[14] >> 1; } +uint8_t IRPanasonicAc::getTemp(void) { + return GETBITS8(remote_state[14], kPanasonicAcTempOffset, + kPanasonicAcTempSize); +} // Set the desitred temperature in Celsius. // Args: @@ -399,25 +404,27 @@ void IRPanasonicAc::setTemp(const uint8_t celsius, const bool remember) { uint8_t temperature; temperature = std::max(celsius, kPanasonicAcMinTemp); temperature = std::min(temperature, kPanasonicAcMaxTemp); - remote_state[14] = temperature << 1; if (remember) _temp = temperature; + setBits(&remote_state[14], kPanasonicAcTempOffset, kPanasonicAcTempSize, + temperature); } uint8_t IRPanasonicAc::getSwingVertical(void) { - return remote_state[16] & 0x0F; + return GETBITS8(remote_state[16], kLowNibble, kNibbleSize); } void IRPanasonicAc::setSwingVertical(const uint8_t desired_elevation) { uint8_t elevation = desired_elevation; if (elevation != kPanasonicAcSwingVAuto) { - elevation = std::max(elevation, kPanasonicAcSwingVUp); - elevation = std::min(elevation, kPanasonicAcSwingVDown); + elevation = std::max(elevation, kPanasonicAcSwingVHighest); + elevation = std::min(elevation, kPanasonicAcSwingVLowest); } - remote_state[16] &= 0xF0; - remote_state[16] |= elevation; + setBits(&remote_state[16], kLowNibble, kNibbleSize, elevation); } -uint8_t IRPanasonicAc::getSwingHorizontal(void) { return remote_state[17]; } +uint8_t IRPanasonicAc::getSwingHorizontal(void) { + return GETBITS8(remote_state[17], kLowNibble, kNibbleSize); +} void IRPanasonicAc::setSwingHorizontal(const uint8_t desired_direction) { switch (desired_direction) { @@ -426,10 +433,9 @@ void IRPanasonicAc::setSwingHorizontal(const uint8_t desired_direction) { case kPanasonicAcSwingHFullLeft: case kPanasonicAcSwingHLeft: case kPanasonicAcSwingHRight: - case kPanasonicAcSwingHFullRight: - break; - default: // Ignore anything that isn't valid. - return; + case kPanasonicAcSwingHFullRight: break; + // Ignore anything that isn't valid. + default: return; } _swingh = desired_direction; // Store the direction for later. uint8_t direction = desired_direction; @@ -444,129 +450,120 @@ void IRPanasonicAc::setSwingHorizontal(const uint8_t desired_direction) { default: // Ignore everything else. return; } - remote_state[17] = direction; + setBits(&remote_state[17], kLowNibble, kNibbleSize, direction); } void IRPanasonicAc::setFan(const uint8_t speed) { - if (speed <= kPanasonicAcFanMax || speed == kPanasonicAcFanAuto) - remote_state[16] = - (remote_state[16] & 0x0F) | ((speed + kPanasonicAcFanOffset) << 4); + switch (speed) { + case kPanasonicAcFanMin: + case kPanasonicAcFanMed: + case kPanasonicAcFanMax: + case kPanasonicAcFanAuto: + setBits(&remote_state[16], kHighNibble, kNibbleSize, + speed + kPanasonicAcFanDelta); + break; + default: setFan(kPanasonicAcFanAuto); + } } uint8_t IRPanasonicAc::getFan(void) { - return (remote_state[16] >> 4) - kPanasonicAcFanOffset; + return GETBITS8(remote_state[16], kHighNibble, kNibbleSize) - + kPanasonicAcFanDelta; } bool IRPanasonicAc::getQuiet(void) { switch (this->getModel()) { case kPanasonicRkr: case kPanasonicCkp: - return remote_state[21] & kPanasonicAcQuietCkp; + return GETBIT8(remote_state[21], kPanasonicAcQuietCkpOffset); default: - return remote_state[21] & kPanasonicAcQuiet; + return GETBIT8(remote_state[21], kPanasonicAcQuietOffset); } } void IRPanasonicAc::setQuiet(const bool on) { - uint8_t quiet; + uint8_t offset; switch (this->getModel()) { case kPanasonicRkr: - case kPanasonicCkp: - quiet = kPanasonicAcQuietCkp; - break; - default: - quiet = kPanasonicAcQuiet; - } - - if (on) { - this->setPowerful(false); // Powerful is mutually exclusive. - remote_state[21] |= quiet; - } else { - remote_state[21] &= ~quiet; + case kPanasonicCkp: offset = kPanasonicAcQuietCkpOffset; break; + default: offset = kPanasonicAcQuietOffset; } + if (on) this->setPowerful(false); // Powerful is mutually exclusive. + setBit(&remote_state[21], offset, on); } bool IRPanasonicAc::getPowerful(void) { switch (this->getModel()) { case kPanasonicRkr: case kPanasonicCkp: - return remote_state[21] & kPanasonicAcPowerfulCkp; + return GETBIT8(remote_state[21], kPanasonicAcPowerfulCkpOffset); default: - return remote_state[21] & kPanasonicAcPowerful; + return GETBIT8(remote_state[21], kPanasonicAcPowerfulOffset); } } void IRPanasonicAc::setPowerful(const bool on) { - uint8_t powerful; + uint8_t offset; switch (this->getModel()) { case kPanasonicRkr: - case kPanasonicCkp: - powerful = kPanasonicAcPowerfulCkp; - break; - default: - powerful = kPanasonicAcPowerful; + case kPanasonicCkp: offset = kPanasonicAcPowerfulCkpOffset; break; + default: offset = kPanasonicAcPowerfulOffset; } - if (on) { - this->setQuiet(false); // Quiet is mutually exclusive. - remote_state[21] |= powerful; - } else { - remote_state[21] &= ~powerful; - } + if (on) this->setQuiet(false); // Quiet is mutually exclusive. + setBit(&remote_state[21], offset, on); } +// Convert standard (military/24hr) time to nr. of minutes since midnight. uint16_t IRPanasonicAc::encodeTime(const uint8_t hours, const uint8_t mins) { return std::min(hours, (uint8_t)23) * 60 + std::min(mins, (uint8_t)59); } -uint16_t IRPanasonicAc::getClock(void) { - uint16_t result = ((remote_state[25] & 0b00000111) << 8) + remote_state[24]; +uint16_t IRPanasonicAc::_getTime(const uint8_t ptr[]) { + uint16_t result = (GETBITS8( + ptr[1], kLowNibble, kPanasonicAcTimeOverflowSize) << + (kPanasonicAcTimeSize - kPanasonicAcTimeOverflowSize)) + ptr[0]; if (result == kPanasonicAcTimeSpecial) return 0; return result; } +uint16_t IRPanasonicAc::getClock(void) { return _getTime(&remote_state[24]); } + +void IRPanasonicAc::_setTime(uint8_t * const ptr, + const uint16_t mins_since_midnight, + const bool round_down) { + uint16_t corrected = std::min(mins_since_midnight, kPanasonicAcTimeMax); + if (round_down) corrected -= corrected % 10; + if (mins_since_midnight == kPanasonicAcTimeSpecial) + corrected = kPanasonicAcTimeSpecial; + ptr[0] = corrected; + setBits(&ptr[1], kLowNibble, kPanasonicAcTimeOverflowSize, + corrected >> (kPanasonicAcTimeSize - kPanasonicAcTimeOverflowSize)); +} + void IRPanasonicAc::setClock(const uint16_t mins_since_midnight) { - uint16_t corrected = std::min(mins_since_midnight, kPanasonicAcTimeMax); - if (mins_since_midnight == kPanasonicAcTimeSpecial) - corrected = kPanasonicAcTimeSpecial; - remote_state[24] = corrected & 0xFF; - remote_state[25] &= 0b11111000; - remote_state[25] |= (corrected >> 8); + _setTime(&remote_state[24], mins_since_midnight, false); } -uint16_t IRPanasonicAc::getOnTimer(void) { - uint16_t result = ((remote_state[19] & 0b00000111) << 8) + remote_state[18]; - if (result == kPanasonicAcTimeSpecial) return 0; - return result; -} +uint16_t IRPanasonicAc::getOnTimer(void) { return _getTime(&remote_state[18]); } void IRPanasonicAc::setOnTimer(const uint16_t mins_since_midnight, const bool enable) { - // Ensure it's on a 10 minute boundary and no overflow. - uint16_t corrected = std::min(mins_since_midnight, kPanasonicAcTimeMax); - corrected -= corrected % 10; - if (mins_since_midnight == kPanasonicAcTimeSpecial) - corrected = kPanasonicAcTimeSpecial; - - if (enable) - remote_state[13] |= kPanasonicAcOnTimer; // Set the Ontimer flag. - else - remote_state[13] &= ~kPanasonicAcOnTimer; // Clear the Ontimer flag. + // Set the timer flag. + setBit(&remote_state[13], kPanasonicAcOnTimerOffset, enable); // Store the time. - remote_state[18] = corrected & 0xFF; - remote_state[19] &= 0b11111000; - remote_state[19] |= (corrected >> 8); + _setTime(&remote_state[18], mins_since_midnight, true); } void IRPanasonicAc::cancelOnTimer(void) { this->setOnTimer(0, false); } bool IRPanasonicAc::isOnTimerEnabled(void) { - return remote_state[13] & kPanasonicAcOnTimer; + return GETBIT8(remote_state[13], kPanasonicAcOnTimerOffset); } uint16_t IRPanasonicAc::getOffTimer(void) { - uint16_t result = - ((remote_state[20] & 0b01111111) << 4) + (remote_state[19] >> 4); + uint16_t result = (GETBITS8(remote_state[20], 0, 7) << kNibbleSize) | + GETBITS8(remote_state[19], kHighNibble, kNibbleSize); if (result == kPanasonicAcTimeSpecial) return 0; return result; } @@ -578,55 +575,39 @@ void IRPanasonicAc::setOffTimer(const uint16_t mins_since_midnight, corrected -= corrected % 10; if (mins_since_midnight == kPanasonicAcTimeSpecial) corrected = kPanasonicAcTimeSpecial; - - if (enable) - remote_state[13] |= kPanasonicAcOffTimer; // Set the OffTimer flag. - else - remote_state[13] &= ~kPanasonicAcOffTimer; // Clear the OffTimer flag. + // Set the timer flag. + setBit(&remote_state[13], kPanasonicAcOffTimerOffset, enable); // Store the time. - remote_state[19] &= 0b00001111; - remote_state[19] |= (corrected & 0b00001111) << 4; - remote_state[20] &= 0b10000000; - remote_state[20] |= corrected >> 4; + setBits(&remote_state[19], kHighNibble, kNibbleSize, corrected); + setBits(&remote_state[20], 0, 7, corrected >> kNibbleSize); } void IRPanasonicAc::cancelOffTimer(void) { this->setOffTimer(0, false); } bool IRPanasonicAc::isOffTimerEnabled(void) { - return remote_state[13] & kPanasonicAcOffTimer; + return GETBIT8(remote_state[13], kPanasonicAcOffTimerOffset); } // Convert a standard A/C mode into its native mode. uint8_t IRPanasonicAc::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kPanasonicAcCool; - case stdAc::opmode_t::kHeat: - return kPanasonicAcHeat; - case stdAc::opmode_t::kDry: - return kPanasonicAcDry; - case stdAc::opmode_t::kFan: - return kPanasonicAcFan; - default: - return kPanasonicAcAuto; + case stdAc::opmode_t::kCool: return kPanasonicAcCool; + case stdAc::opmode_t::kHeat: return kPanasonicAcHeat; + case stdAc::opmode_t::kDry: return kPanasonicAcDry; + case stdAc::opmode_t::kFan: return kPanasonicAcFan; + default: return kPanasonicAcAuto; } } // Convert a standard A/C Fan speed into its native fan speed. uint8_t IRPanasonicAc::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { - case stdAc::fanspeed_t::kMin: - return kPanasonicAcFanMin; - case stdAc::fanspeed_t::kLow: - return kPanasonicAcFanMin + 1; - case stdAc::fanspeed_t::kMedium: - return kPanasonicAcFanMin + 2; - case stdAc::fanspeed_t::kHigh: - return kPanasonicAcFanMin + 3; - case stdAc::fanspeed_t::kMax: - return kPanasonicAcFanMax; - default: - return kPanasonicAcFanAuto; + case stdAc::fanspeed_t::kMin: return kPanasonicAcFanMin; + case stdAc::fanspeed_t::kLow: return kPanasonicAcFanMin + 1; + case stdAc::fanspeed_t::kMedium: return kPanasonicAcFanMin + 2; + case stdAc::fanspeed_t::kHigh: return kPanasonicAcFanMin + 3; + case stdAc::fanspeed_t::kMax: return kPanasonicAcFanMax; + default: return kPanasonicAcFanAuto; } } @@ -636,30 +617,21 @@ uint8_t IRPanasonicAc::convertSwingV(const stdAc::swingv_t position) { case stdAc::swingv_t::kHighest: case stdAc::swingv_t::kHigh: case stdAc::swingv_t::kMiddle: - return kPanasonicAcSwingVUp; case stdAc::swingv_t::kLow: - case stdAc::swingv_t::kLowest: - return kPanasonicAcSwingVDown; - default: - return kPanasonicAcSwingVAuto; + case stdAc::swingv_t::kLowest: return (uint8_t)position; + default: return kPanasonicAcSwingVAuto; } } // Convert a standard A/C horizontal swing into its native setting. uint8_t IRPanasonicAc::convertSwingH(const stdAc::swingh_t position) { switch (position) { - case stdAc::swingh_t::kLeftMax: - return kPanasonicAcSwingHFullLeft; - case stdAc::swingh_t::kLeft: - return kPanasonicAcSwingHLeft; - case stdAc::swingh_t::kMiddle: - return kPanasonicAcSwingHMiddle; - case stdAc::swingh_t::kRight: - return kPanasonicAcSwingHRight; - case stdAc::swingh_t::kRightMax: - return kPanasonicAcSwingHFullRight; - default: - return kPanasonicAcSwingHAuto; + case stdAc::swingh_t::kLeftMax: return kPanasonicAcSwingHFullLeft; + case stdAc::swingh_t::kLeft: return kPanasonicAcSwingHLeft; + case stdAc::swingh_t::kMiddle: return kPanasonicAcSwingHMiddle; + case stdAc::swingh_t::kRight: return kPanasonicAcSwingHRight; + case stdAc::swingh_t::kRightMax: return kPanasonicAcSwingHFullRight; + default: return kPanasonicAcSwingHAuto; } } @@ -668,43 +640,42 @@ stdAc::opmode_t IRPanasonicAc::toCommonMode(const uint8_t mode) { switch (mode) { case kPanasonicAcCool: return stdAc::opmode_t::kCool; case kPanasonicAcHeat: return stdAc::opmode_t::kHeat; - case kPanasonicAcDry: return stdAc::opmode_t::kDry; - case kPanasonicAcFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kPanasonicAcDry: return stdAc::opmode_t::kDry; + case kPanasonicAcFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } // Convert a native fan speed to it's common equivalent. stdAc::fanspeed_t IRPanasonicAc::toCommonFanSpeed(const uint8_t spd) { switch (spd) { - case kPanasonicAcFanMax: return stdAc::fanspeed_t::kMax; + case kPanasonicAcFanMax: return stdAc::fanspeed_t::kMax; case kPanasonicAcFanMin + 3: return stdAc::fanspeed_t::kHigh; case kPanasonicAcFanMin + 2: return stdAc::fanspeed_t::kMedium; case kPanasonicAcFanMin + 1: return stdAc::fanspeed_t::kLow; - case kPanasonicAcFanMin: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kPanasonicAcFanMin: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } // Convert a native vertical swing to it's common equivalent. stdAc::swingh_t IRPanasonicAc::toCommonSwingH(const uint8_t pos) { switch (pos) { - case kPanasonicAcSwingHFullLeft: return stdAc::swingh_t::kLeftMax; - case kPanasonicAcSwingHLeft: return stdAc::swingh_t::kLeft; - case kPanasonicAcSwingHMiddle: return stdAc::swingh_t::kMiddle; - case kPanasonicAcSwingHRight: return stdAc::swingh_t::kRight; + case kPanasonicAcSwingHFullLeft: return stdAc::swingh_t::kLeftMax; + case kPanasonicAcSwingHLeft: return stdAc::swingh_t::kLeft; + case kPanasonicAcSwingHMiddle: return stdAc::swingh_t::kMiddle; + case kPanasonicAcSwingHRight: return stdAc::swingh_t::kRight; case kPanasonicAcSwingHFullRight: return stdAc::swingh_t::kRightMax; - default: return stdAc::swingh_t::kAuto; + default: return stdAc::swingh_t::kAuto; } } // Convert a native vertical swing to it's common equivalent. stdAc::swingv_t IRPanasonicAc::toCommonSwingV(const uint8_t pos) { - switch (pos) { - case kPanasonicAcSwingVUp: return stdAc::swingv_t::kHighest; - case kPanasonicAcSwingVDown: return stdAc::swingv_t::kLowest; - default: return stdAc::swingv_t::kAuto; - } + if (pos >= kPanasonicAcSwingVHighest && pos <= kPanasonicAcSwingVLowest) + return (stdAc::swingv_t)pos; + else + return stdAc::swingv_t::kAuto; } // Convert the A/C state to it's common equivalent. @@ -736,95 +707,80 @@ stdAc::state_t IRPanasonicAc::toCommon(void) { String IRPanasonicAc::toString(void) { String result = ""; result.reserve(180); // Reserve some heap for the string to reduce fragging. - result += F("Model: "); - result += uint64ToString(getModel()); - switch (getModel()) { - case kPanasonicDke: - result += F(" (DKE)"); - break; - case kPanasonicJke: - result += F(" (JKE)"); - break; - case kPanasonicNke: - result += F(" (NKE)"); - break; - case kPanasonicLke: - result += F(" (LKE)"); - break; - case kPanasonicCkp: - result += F(" (CKP)"); - break; - case kPanasonicRkr: - result += F(" (RKR)"); - break; - default: - result += F(" (UNKNOWN)"); - } - result += addBoolToString(getPower(), F("Power")); + result += addModelToString(decode_type_t::PANASONIC_AC, getModel(), false); + result += addBoolToString(getPower(), kPowerStr); result += addModeToString(getMode(), kPanasonicAcAuto, kPanasonicAcCool, kPanasonicAcHeat, kPanasonicAcDry, kPanasonicAcFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kPanasonicAcFanMax, kPanasonicAcFanMin, kPanasonicAcFanAuto, kPanasonicAcFanAuto, kPanasonicAcFanMed); - result += addIntToString(getSwingVertical(), F("Swing (Vertical)")); + result += addIntToString(getSwingVertical(), kSwingVStr); + result += kSpaceLBraceStr; switch (getSwingVertical()) { case kPanasonicAcSwingVAuto: - result += F(" (AUTO)"); + result += kAutoStr; break; - case kPanasonicAcSwingVUp: - result += F(" (Full Up)"); + case kPanasonicAcSwingVHighest: + result += kHighestStr; break; - case kPanasonicAcSwingVDown: - result += F(" (Full Down)"); + case kPanasonicAcSwingVHigh: + result += kHighStr; break; - case 2: - case 3: - case 4: + case kPanasonicAcSwingVMiddle: + result += kMiddleStr; + break; + case kPanasonicAcSwingVLow: + result += kLowStr; + break; + case kPanasonicAcSwingVLowest: + result += kLowestStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; break; } + result += ')'; switch (getModel()) { case kPanasonicJke: case kPanasonicCkp: break; // No Horizontal Swing support. default: - result += addIntToString(getSwingHorizontal(), F("Swing (Horizontal)")); + result += addIntToString(getSwingHorizontal(), kSwingHStr); + result += kSpaceLBraceStr; switch (getSwingHorizontal()) { case kPanasonicAcSwingHAuto: - result += F(" (AUTO)"); + result += kAutoStr; break; case kPanasonicAcSwingHFullLeft: - result += F(" (Full Left)"); + result += kMaxLeftStr; break; case kPanasonicAcSwingHLeft: - result += F(" (Left)"); + result += kLeftStr; break; case kPanasonicAcSwingHMiddle: - result += F(" (Middle)"); + result += kMiddleStr; break; case kPanasonicAcSwingHFullRight: - result += F(" (Full Right)"); + result += kMaxRightStr; break; case kPanasonicAcSwingHRight: - result += F(" (Right)"); + result += kRightStr; break; default: - result += F(" (UNKNOWN)"); - break; + result += kUnknownStr; } + result += ')'; } - result += addBoolToString(getQuiet(), F("Quiet")); - result += addBoolToString(getPowerful(), F("Powerful")); - result += addLabeledString(minsToString(getClock()), F("Clock")); + result += addBoolToString(getQuiet(), kQuietStr); + result += addBoolToString(getPowerful(), kPowerfulStr); + result += addLabeledString(minsToString(getClock()), kClockStr); result += addLabeledString( - isOnTimerEnabled() ? minsToString(getOnTimer()) : F("Off"), - F("On Timer")); + isOnTimerEnabled() ? minsToString(getOnTimer()) : kOffStr, + kOnTimerStr); result += addLabeledString( - isOffTimerEnabled() ? minsToString(getOffTimer()) : F("Off"), - F("Off Timer")); + isOffTimerEnabled() ? minsToString(getOffTimer()) : kOffStr, + kOffTimerStr); return result; } @@ -894,7 +850,7 @@ bool IRrecv::decodePanasonicAC(decode_results *results, const uint16_t nbits, } // Success - results->decode_type = PANASONIC_AC; + results->decode_type = decode_type_t::PANASONIC_AC; results->bits = nbits; return true; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Panasonic.h b/lib/IRremoteESP8266-2.7.0/src/ir_Panasonic.h old mode 100755 new mode 100644 similarity index 70% rename from lib/IRremoteESP8266-2.6.5/src/ir_Panasonic.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Panasonic.h index 32899db9b..89c2e5395 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Panasonic.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Panasonic.h @@ -42,37 +42,45 @@ const uint16_t kPanasonicAcExcess = 0; // Much higher than usual. See issue #540. const uint16_t kPanasonicAcTolerance = 40; -const uint8_t kPanasonicAcAuto = 0; // 0b0000 -const uint8_t kPanasonicAcDry = 2; // 0b0010 -const uint8_t kPanasonicAcCool = 3; // 0b0011 -const uint8_t kPanasonicAcHeat = 4; // 0b0010 -const uint8_t kPanasonicAcFan = 6; // 0b0110 +const uint8_t kPanasonicAcAuto = 0; // 0b000 +const uint8_t kPanasonicAcDry = 2; // 0b010 +const uint8_t kPanasonicAcCool = 3; // 0b011 +const uint8_t kPanasonicAcHeat = 4; // 0b010 +const uint8_t kPanasonicAcFan = 6; // 0b110 const uint8_t kPanasonicAcFanMin = 0; const uint8_t kPanasonicAcFanMed = 2; const uint8_t kPanasonicAcFanMax = 4; const uint8_t kPanasonicAcFanAuto = 7; -const uint8_t kPanasonicAcFanOffset = 3; -const uint8_t kPanasonicAcPower = 1; // 0b1 +const uint8_t kPanasonicAcFanDelta = 3; +const uint8_t kPanasonicAcPowerOffset = 0; +const uint8_t kPanasonicAcTempOffset = 1; // Bits +const uint8_t kPanasonicAcTempSize = 5; // Bits const uint8_t kPanasonicAcMinTemp = 16; // Celsius const uint8_t kPanasonicAcMaxTemp = 30; // Celsius const uint8_t kPanasonicAcFanModeTemp = 27; // Celsius -const uint8_t kPanasonicAcQuiet = 1; // 0b1 -const uint8_t kPanasonicAcPowerful = 0x20; // 0b100000 +const uint8_t kPanasonicAcQuietOffset = 0; +const uint8_t kPanasonicAcPowerfulOffset = 5; // 0b100000 // CKP & RKR models have Powerful and Quiet bits swapped. -const uint8_t kPanasonicAcQuietCkp = 0x20; // 0b100000 -const uint8_t kPanasonicAcPowerfulCkp = 1; // 0b1 -const uint8_t kPanasonicAcSwingVAuto = 0xF; -const uint8_t kPanasonicAcSwingVUp = 0x1; -const uint8_t kPanasonicAcSwingVDown = 0x5; -const uint8_t kPanasonicAcSwingHAuto = 0xD; -const uint8_t kPanasonicAcSwingHMiddle = 0x6; -const uint8_t kPanasonicAcSwingHFullLeft = 0x9; -const uint8_t kPanasonicAcSwingHLeft = 0xA; -const uint8_t kPanasonicAcSwingHRight = 0xB; -const uint8_t kPanasonicAcSwingHFullRight = 0xC; +const uint8_t kPanasonicAcQuietCkpOffset = kPanasonicAcPowerfulOffset; +const uint8_t kPanasonicAcPowerfulCkpOffset = kPanasonicAcQuietOffset; +const uint8_t kPanasonicAcSwingVHighest = 0x1; // 0b0001 +const uint8_t kPanasonicAcSwingVHigh = 0x2; // 0b0010 +const uint8_t kPanasonicAcSwingVMiddle = 0x3; // 0b0011 +const uint8_t kPanasonicAcSwingVLow = 0x4; // 0b0100 +const uint8_t kPanasonicAcSwingVLowest = 0x5; // 0b0101 +const uint8_t kPanasonicAcSwingVAuto = 0xF; // 0b1111 + +const uint8_t kPanasonicAcSwingHMiddle = 0x6; // 0b0110 +const uint8_t kPanasonicAcSwingHFullLeft = 0x9; // 0b1001 +const uint8_t kPanasonicAcSwingHLeft = 0xA; // 0b1010 +const uint8_t kPanasonicAcSwingHRight = 0xB; // 0b1011 +const uint8_t kPanasonicAcSwingHFullRight = 0xC; // 0b1100 +const uint8_t kPanasonicAcSwingHAuto = 0xD; // 0b1101 const uint8_t kPanasonicAcChecksumInit = 0xF4; -const uint8_t kPanasonicAcOnTimer = 0b00000010; -const uint8_t kPanasonicAcOffTimer = 0b00000100; +const uint8_t kPanasonicAcOnTimerOffset = 1; +const uint8_t kPanasonicAcOffTimerOffset = 2; +const uint8_t kPanasonicAcTimeSize = 11; // Bits +const uint8_t kPanasonicAcTimeOverflowSize = 3; // Bits const uint16_t kPanasonicAcTimeMax = 23 * 60 + 59; // Mins since midnight. const uint16_t kPanasonicAcTimeSpecial = 0x600; @@ -81,15 +89,6 @@ const uint8_t kPanasonicKnownGoodState[kPanasonicAcStateLength] = { 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x0E, 0xE0, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00}; -enum panasonic_ac_remote_model_t { - kPanasonicUnknown = 0, - kPanasonicLke = 1, - kPanasonicNke = 2, - kPanasonicDke = 3, - kPanasonicJke = 4, - kPanasonicCkp = 5, - kPanasonicRkr = 6, -}; class IRPanasonicAc { public: @@ -140,10 +139,10 @@ class IRPanasonicAc { const bool enable = true); void cancelOffTimer(void); bool isOffTimerEnabled(void); - uint8_t convertMode(const stdAc::opmode_t mode); - uint8_t convertFan(const stdAc::fanspeed_t speed); - uint8_t convertSwingV(const stdAc::swingv_t position); - uint8_t convertSwingH(const stdAc::swingh_t position); + 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); @@ -163,6 +162,9 @@ class IRPanasonicAc { void fixChecksum(const uint16_t length = kPanasonicAcStateLength); static uint8_t calcChecksum(const uint8_t *state, const uint16_t length = kPanasonicAcStateLength); + static uint16_t _getTime(const uint8_t ptr[]); + static void _setTime(uint8_t * const ptr, const uint16_t mins_since_midnight, + const bool round_down); }; #endif // IR_PANASONIC_H_ diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Pioneer.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Pioneer.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Pioneer.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Pioneer.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Pronto.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Pronto.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Pronto.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Pronto.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_RC5_RC6.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_RC5_RC6.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_RC5_RC6.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_RC5_RC6.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_RCMM.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_RCMM.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_RCMM.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_RCMM.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Samsung.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Samsung.cpp old mode 100755 new mode 100644 similarity index 80% rename from lib/IRremoteESP8266-2.6.5/src/ir_Samsung.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Samsung.cpp index 77985b1c4..1ca7a2b4a --- a/lib/IRremoteESP8266-2.6.5/src/ir_Samsung.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Samsung.cpp @@ -5,11 +5,13 @@ #include "ir_Samsung.h" #include +#include #ifndef ARDUINO #include #endif #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // Samsung originally added from https://github.com/shirriff/Arduino-IRremote/ @@ -56,6 +58,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_SAMSUNG // Send a Samsung formatted message. @@ -285,7 +289,7 @@ void IRsend::sendSamsungAC(const uint8_t data[], const uint16_t nbytes, 38000, false, 0, 50); // Send in LSBF order } // Complete made up guess at inter-message gap. - space(100000 - kSamsungAcSectionGap); + space(kDefaultMessageGap - kSamsungAcSectionGap); } } #endif // SEND_SAMSUNG_AC @@ -296,20 +300,18 @@ IRSamsungAc::IRSamsungAc(const uint16_t pin, const bool inverted, this->stateReset(); } -void IRSamsungAc::stateReset(void) { - for (uint8_t i = 0; i < kSamsungAcExtendedStateLength; i++) - remote_state[i] = 0x0; - remote_state[0] = 0x02; - remote_state[1] = 0x92; - remote_state[2] = 0x0F; - remote_state[6] = 0xF0; - remote_state[7] = 0x01; - remote_state[8] = 0x02; - remote_state[9] = 0xAE; - remote_state[10] = 0x71; - remote_state[12] = 0x15; - remote_state[13] = 0xF0; - _sendpower = false; +// Reset the internal state of the emulation. +// Args: +// forcepower: A flag indicating if force sending a special power message +// with the first `send()` call. Default: true +void IRSamsungAc::stateReset(const bool forcepower, const bool initialPower) { + static const uint8_t kReset[kSamsungAcExtendedStateLength] = { + 0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x02, 0xAE, 0x71, 0x00, + 0x15, 0xF0}; + memcpy(remote_state, kReset, kSamsungAcExtendedStateLength); + _forcepower = forcepower; + _lastsentpowerstate = initialPower; + setPower(initialPower); } void IRSamsungAc::begin(void) { _irsend.begin(); } @@ -323,10 +325,10 @@ uint8_t IRSamsungAc::calcChecksum(const uint8_t state[], // https://github.com/adafruit/Raw-IR-decoder-for-Arduino/pull/3/files // Count most of the '1' bits after the checksum location. sum += countBits(state[length - 7], 8); - sum -= countBits(state[length - 6] & 0xF, 8); - sum += countBits(state[length - 5] & 0b11111110, 8); + sum -= countBits(GETBITS8(state[length - 6], kLowNibble, kNibbleSize), 8); + sum += countBits(GETBITS8(state[length - 5], 1, 7), 8); sum += countBits(state + length - 4, 3); - return (28 - sum) & 0xF; + return GETBITS8(28 - sum, kLowNibble, kNibbleSize); } bool IRSamsungAc::validChecksum(const uint8_t state[], const uint16_t length) { @@ -334,19 +336,19 @@ bool IRSamsungAc::validChecksum(const uint8_t state[], const uint16_t length) { return true; // No checksum to compare with. Assume okay. uint8_t offset = 0; if (length >= kSamsungAcExtendedStateLength) offset = 7; - return ((state[length - 6] >> 4) == IRSamsungAc::calcChecksum(state, length) - && (state[length - (13 + offset)] >> 4) == IRSamsungAc::calcChecksum( - state, length - (7 + offset))); + return (GETBITS8(state[length - 6], kHighNibble, kNibbleSize) == + IRSamsungAc::calcChecksum(state, length)) && + (GETBITS8(state[length - (13 + offset)], kHighNibble, kNibbleSize) == + IRSamsungAc::calcChecksum(state, length - (7 + offset))); } // Update the checksum for the internal state. void IRSamsungAc::checksum(uint16_t length) { if (length < 13) return; - remote_state[length - 6] &= 0x0F; - remote_state[length - 6] |= (this->calcChecksum(remote_state, length) << 4); - remote_state[length - 13] &= 0x0F; - remote_state[length - 13] |= (this->calcChecksum(remote_state, - length - 7) << 4); + setBits(&remote_state[length - 6], kHighNibble, kNibbleSize, + this->calcChecksum(remote_state, length)); + setBits(&remote_state[length - 13], kHighNibble, kNibbleSize, + this->calcChecksum(remote_state, length - 7)); } #if SEND_SAMSUNG_AC @@ -354,12 +356,13 @@ void IRSamsungAc::checksum(uint16_t length) { // i.e. When the device is already running. void IRSamsungAc::send(const uint16_t repeat, const bool calcchecksum) { if (calcchecksum) this->checksum(); - if (_sendpower) { // Do we need to send a the special power on/off message? - _sendpower = false; // It will now been sent. + // Do we need to send a the special power on/off message? + if (this->getPower() != _lastsentpowerstate || _forcepower) { + _forcepower = false; // It will now been sent, so clear the flag if set. if (this->getPower()) { - this->sendOn(); + this->sendOn(repeat); } else { - this->sendOff(); + this->sendOff(repeat); return; // No point sending anything else if we are turning the unit off. } } @@ -395,6 +398,7 @@ void IRSamsungAc::sendOn(const uint16_t repeat) { 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0xE2, 0xFE, 0x71, 0x80, 0x11, 0xF0}; _irsend.sendSamsungAC(extended_state, kSamsungAcExtendedStateLength, repeat); + _lastsentpowerstate = true; // On } // Send the special extended "Off" message as the library can't seem to @@ -406,6 +410,7 @@ void IRSamsungAc::sendOff(const uint16_t repeat) { 0x01, 0xD2, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0xFF, 0x71, 0x80, 0x11, 0xC0}; _irsend.sendSamsungAC(extended_state, kSamsungAcExtendedStateLength, repeat); + _lastsentpowerstate = false; // Off } #endif // SEND_SAMSUNG_AC @@ -415,9 +420,8 @@ uint8_t *IRSamsungAc::getRaw(void) { } void IRSamsungAc::setRaw(const uint8_t new_code[], const uint16_t length) { - for (uint8_t i = 0; i < length && i < kSamsungAcExtendedStateLength; i++) { - remote_state[i] = new_code[i]; - } + memcpy(remote_state, new_code, std::min(length, + kSamsungAcExtendedStateLength)); // Shrink the extended state into a normal state. if (length > kSamsungAcStateLength) { for (uint8_t i = kSamsungAcStateLength; i < length; i++) @@ -425,48 +429,41 @@ void IRSamsungAc::setRaw(const uint8_t new_code[], const uint16_t length) { } } -void IRSamsungAc::on(void) { - remote_state[1] &= ~kSamsungAcPowerMask1; // Bit needs to be cleared. - remote_state[6] |= kSamsungAcPowerMask6; // Bit needs to be set. - _sendpower = true; // Flag that we need to send the special power message(s). -} +void IRSamsungAc::on(void) { setPower(true); } -void IRSamsungAc::off(void) { - remote_state[1] |= kSamsungAcPowerMask1; // Bit needs to be set. - remote_state[6] &= ~kSamsungAcPowerMask6; // Bit needs to be cleared. - _sendpower = true; // Flag that we need to send the special power message(s). -} +void IRSamsungAc::off(void) { setPower(false); } void IRSamsungAc::setPower(const bool on) { - if (on) - this->on(); - else - this->off(); + setBit(&remote_state[1], kSamsungAcPower1Offset, !on); // Cleared when on. + setBits(&remote_state[6], kSamsungAcPower6Offset, kSamsungAcPower6Size, + on ? 0b11 : 0b00); } bool IRSamsungAc::getPower(void) { - return (remote_state[6] & kSamsungAcPowerMask6) && - !(remote_state[1] & kSamsungAcPowerMask1); + return (GETBITS8(remote_state[6], kSamsungAcPower6Offset, + kSamsungAcPower6Size) == 0b11) && + !GETBIT8(remote_state[1], kSamsungAcPower1Offset); } // Set the temp. in deg C void IRSamsungAc::setTemp(const uint8_t temp) { uint8_t newtemp = std::max(kSamsungAcMinTemp, temp); newtemp = std::min(kSamsungAcMaxTemp, newtemp); - remote_state[11] = (remote_state[11] & ~kSamsungAcTempMask) | - ((newtemp - kSamsungAcMinTemp) << 4); + setBits(&remote_state[11], kHighNibble, kNibbleSize, + newtemp - kSamsungAcMinTemp); } // Return the set temp. in deg C uint8_t IRSamsungAc::getTemp(void) { - return ((remote_state[11] & kSamsungAcTempMask) >> 4) + kSamsungAcMinTemp; + return GETBITS8(remote_state[11], kHighNibble, kNibbleSize) + + kSamsungAcMinTemp; } void IRSamsungAc::setMode(const uint8_t mode) { // If we get an unexpected mode, default to AUTO. uint8_t newmode = mode; if (newmode > kSamsungAcHeat) newmode = kSamsungAcAuto; - remote_state[12] = (remote_state[12] & ~kSamsungAcModeMask) | (newmode << 4); + setBits(&remote_state[12], kSamsungAcModeOffset, kModeBitsSize, newmode); // Auto mode has a special fan setting valid only in auto mode. if (newmode == kSamsungAcAuto) { @@ -479,7 +476,7 @@ void IRSamsungAc::setMode(const uint8_t mode) { } uint8_t IRSamsungAc::getMode(void) { - return (remote_state[12] & kSamsungAcModeMask) >> 4; + return GETBITS8(remote_state[12], kSamsungAcModeOffset, kModeBitsSize); } void IRSamsungAc::setFan(const uint8_t speed) { @@ -497,89 +494,77 @@ void IRSamsungAc::setFan(const uint8_t speed) { default: return; } - remote_state[12] = (remote_state[12] & ~kSamsungAcFanMask) | (speed << 1); + setBits(&remote_state[12], kSamsungAcFanOffest, kSamsungAcFanSize, speed); } uint8_t IRSamsungAc::getFan(void) { - return ((remote_state[12] & kSamsungAcFanMask) >> 1); + return GETBITS8(remote_state[12], kSamsungAcFanOffest, kSamsungAcFanSize); } bool IRSamsungAc::getSwing(void) { // TODO(Hollako): Explain why sometimes the LSB of remote_state[9] is a 1. // e.g. 0xAE or 0XAF for swing move. - return ((remote_state[9] & kSamsungAcSwingMask) >> 4) == kSamsungAcSwingMove; + return GETBITS8(remote_state[9], kSamsungAcSwingOffset, + kSamsungAcSwingSize) == kSamsungAcSwingMove; } void IRSamsungAc::setSwing(const bool on) { // TODO(Hollako): Explain why sometimes the LSB of remote_state[9] is a 1. // e.g. 0xAE or 0XAF for swing move. - remote_state[9] &= ~kSamsungAcSwingMask; // Clear the previous swing state. - if (on) - remote_state[9] |= (kSamsungAcSwingMove << 4); - else - remote_state[9] |= (kSamsungAcSwingStop << 4); + setBits(&remote_state[9], kSamsungAcSwingOffset, kSamsungAcSwingSize, + on ? kSamsungAcSwingMove : kSamsungAcSwingStop); } bool IRSamsungAc::getBeep(void) { - return remote_state[13] & kSamsungAcBeepMask; + return GETBIT8(remote_state[13], kSamsungAcBeepOffset); } void IRSamsungAc::setBeep(const bool on) { - if (on) - remote_state[13] |= kSamsungAcBeepMask; - else - remote_state[13] &= ~kSamsungAcBeepMask; + setBit(&remote_state[13], kSamsungAcBeepOffset, on); } bool IRSamsungAc::getClean(void) { - return (remote_state[10] & kSamsungAcCleanMask10) && - (remote_state[11] & kSamsungAcCleanMask11); + return GETBIT8(remote_state[10], kSamsungAcClean10Offset) && + GETBIT8(remote_state[11], kSamsungAcClean11Offset); } void IRSamsungAc::setClean(const bool on) { - if (on) { - remote_state[10] |= kSamsungAcCleanMask10; - remote_state[11] |= kSamsungAcCleanMask11; - } else { - remote_state[10] &= ~kSamsungAcCleanMask10; - remote_state[11] &= ~kSamsungAcCleanMask11; - } + setBit(&remote_state[10], kSamsungAcClean10Offset, on); + setBit(&remote_state[11], kSamsungAcClean11Offset, on); } bool IRSamsungAc::getQuiet(void) { - return !(remote_state[1] & kSamsungAcQuietMask1) && - (remote_state[5] & kSamsungAcQuietMask5); + return !GETBIT8(remote_state[1], kSamsungAcQuiet1Offset) && + GETBIT8(remote_state[5], kSamsungAcQuiet5Offset); } void IRSamsungAc::setQuiet(const bool on) { + setBit(&remote_state[1], kSamsungAcQuiet1Offset, !on); // Cleared when on. + setBit(&remote_state[5], kSamsungAcQuiet5Offset, on); if (on) { - remote_state[1] &= ~kSamsungAcQuietMask1; // Bit needs to be cleared. - remote_state[5] |= kSamsungAcQuietMask5; // Bit needs to be set. // Quiet mode seems to set fan speed to auto. this->setFan(kSamsungAcFanAuto); this->setPowerful(false); // Quiet 'on' is mutually exclusive to Powerful. - } else { - remote_state[1] |= kSamsungAcQuietMask1; // Bit needs to be set. - remote_state[5] &= ~kSamsungAcQuietMask5; // Bit needs to be cleared. } } bool IRSamsungAc::getPowerful(void) { return !(remote_state[8] & kSamsungAcPowerfulMask8) && - (remote_state[10] & kSamsungAcPowerfulMask10) && - this->getFan() == kSamsungAcFanTurbo; + GETBITS8(remote_state[10], kSamsungAcPowerful10Offset, + kSamsungAcPowerful10Offset) && + (this->getFan() == kSamsungAcFanTurbo); } void IRSamsungAc::setPowerful(const bool on) { + setBits(&remote_state[10], kSamsungAcPowerful10Offset, + kSamsungAcPowerful10Offset, on ? 0b11: 0b00); if (on) { remote_state[8] &= ~kSamsungAcPowerfulMask8; // Bit needs to be cleared. - remote_state[10] |= kSamsungAcPowerfulMask10; // Bit needs to be set. // Powerful mode sets fan speed to Turbo. this->setFan(kSamsungAcFanTurbo); this->setQuiet(false); // Powerful 'on' is mutually exclusive to Quiet. } else { remote_state[8] |= kSamsungAcPowerfulMask8; // Bit needs to be set. - remote_state[10] &= ~kSamsungAcPowerfulMask10; // Bit needs to be cleared. // Turning off Powerful mode sets fan speed to Auto if we were in Turbo mode if (this->getFan() == kSamsungAcFanTurbo) this->setFan(kSamsungAcFanAuto); } @@ -588,16 +573,11 @@ void IRSamsungAc::setPowerful(const bool on) { // Convert a standard A/C mode into its native mode. uint8_t IRSamsungAc::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kSamsungAcCool; - case stdAc::opmode_t::kHeat: - return kSamsungAcHeat; - case stdAc::opmode_t::kDry: - return kSamsungAcDry; - case stdAc::opmode_t::kFan: - return kSamsungAcFan; - default: - return kSamsungAcAuto; + case stdAc::opmode_t::kCool: return kSamsungAcCool; + case stdAc::opmode_t::kHeat: return kSamsungAcHeat; + case stdAc::opmode_t::kDry: return kSamsungAcDry; + case stdAc::opmode_t::kFan: return kSamsungAcFan; + default: return kSamsungAcAuto; } } @@ -605,16 +585,11 @@ uint8_t IRSamsungAc::convertMode(const stdAc::opmode_t mode) { uint8_t IRSamsungAc::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kSamsungAcFanLow; - case stdAc::fanspeed_t::kMedium: - return kSamsungAcFanMed; - case stdAc::fanspeed_t::kHigh: - return kSamsungAcFanHigh; - case stdAc::fanspeed_t::kMax: - return kSamsungAcFanTurbo; - default: - return kSamsungAcFanAuto; + case stdAc::fanspeed_t::kLow: return kSamsungAcFanLow; + case stdAc::fanspeed_t::kMedium: return kSamsungAcFanMed; + case stdAc::fanspeed_t::kHigh: return kSamsungAcFanHigh; + case stdAc::fanspeed_t::kMax: return kSamsungAcFanTurbo; + default: return kSamsungAcFanAuto; } } @@ -623,9 +598,9 @@ stdAc::opmode_t IRSamsungAc::toCommonMode(const uint8_t mode) { switch (mode) { case kSamsungAcCool: return stdAc::opmode_t::kCool; case kSamsungAcHeat: return stdAc::opmode_t::kHeat; - case kSamsungAcDry: return stdAc::opmode_t::kDry; - case kSamsungAcFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kSamsungAcDry: return stdAc::opmode_t::kDry; + case kSamsungAcFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -633,10 +608,10 @@ stdAc::opmode_t IRSamsungAc::toCommonMode(const uint8_t mode) { stdAc::fanspeed_t IRSamsungAc::toCommonFanSpeed(const uint8_t spd) { switch (spd) { case kSamsungAcFanTurbo: return stdAc::fanspeed_t::kMax; - case kSamsungAcFanHigh: return stdAc::fanspeed_t::kHigh; - case kSamsungAcFanMed: return stdAc::fanspeed_t::kMedium; - case kSamsungAcFanLow: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kSamsungAcFanHigh: return stdAc::fanspeed_t::kHigh; + case kSamsungAcFanMed: return stdAc::fanspeed_t::kMedium; + case kSamsungAcFanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } @@ -670,38 +645,40 @@ stdAc::state_t IRSamsungAc::toCommon(void) { String IRSamsungAc::toString(void) { String result = ""; result.reserve(100); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kSamsungAcAuto, kSamsungAcCool, kSamsungAcHeat, kSamsungAcDry, kSamsungAcFan); result += addTempToString(getTemp()); - result += addIntToString(getFan(), F("Fan")); + result += addIntToString(getFan(), kFanStr); + result += kSpaceLBraceStr; switch (getFan()) { case kSamsungAcFanAuto: case kSamsungAcFanAuto2: - result += F(" (Auto)"); + result += kAutoStr; break; case kSamsungAcFanLow: - result += F(" (Low)"); + result += kLowStr; break; case kSamsungAcFanMed: - result += F(" (Medium)"); + result += kMedStr; break; case kSamsungAcFanHigh: - result += F(" (High)"); + result += kHighStr; break; case kSamsungAcFanTurbo: - result += F(" (Turbo)"); + result += kTurboStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; break; } - result += addBoolToString(getSwing(), F("Swing")); - result += addBoolToString(getBeep(), F("Beep")); - result += addBoolToString(getClean(), F("Clean")); - result += addBoolToString(getQuiet(), F("Quiet")); - result += addBoolToString(getPowerful(), F("Powerful")); + result += ')'; + result += addBoolToString(getSwing(), kSwingStr); + result += addBoolToString(getBeep(), kBeepStr); + result += addBoolToString(getClean(), kCleanStr); + result += addBoolToString(getQuiet(), kQuietStr); + result += addBoolToString(getPowerful(), kPowerfulStr); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Samsung.h b/lib/IRremoteESP8266-2.7.0/src/ir_Samsung.h old mode 100755 new mode 100644 similarity index 77% rename from lib/IRremoteESP8266-2.6.5/src/ir_Samsung.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Samsung.h index 1a2be79bb..de2172444 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Samsung.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Samsung.h @@ -31,7 +31,9 @@ const uint8_t kSamsungAcCool = 1; const uint8_t kSamsungAcDry = 2; const uint8_t kSamsungAcFan = 3; const uint8_t kSamsungAcHeat = 4; -const uint8_t kSamsungAcModeMask = 0x70; // 0b01110000 +const uint8_t kSamsungAcModeOffset = 4; // Mask 0b01110000 +const uint8_t kSamsungAcFanOffest = 1; // Mask 0b00001110 +const uint8_t kSamsungAcFanSize = 3; // Bits const uint8_t kSamsungAcFanAuto = 0; const uint8_t kSamsungAcFanLow = 2; const uint8_t kSamsungAcFanMed = 4; @@ -41,20 +43,21 @@ const uint8_t kSamsungAcFanTurbo = 7; const uint8_t kSamsungAcMinTemp = 16; // 16C const uint8_t kSamsungAcMaxTemp = 30; // 30C const uint8_t kSamsungAcAutoTemp = 25; // 25C -const uint8_t kSamsungAcTempMask = 0xF0; // 0b11110000 -const uint8_t kSamsungAcPowerMask1 = 0x20; // 0b00100000 -const uint8_t kSamsungAcPowerMask6 = 0x30; // 0b00110000 -const uint8_t kSamsungAcFanMask = 0x0E; // 0b00001110 -const uint8_t kSamsungAcSwingMask = 0x70; // 0b01110000 +const uint8_t kSamsungAcPower1Offset = 5; +const uint8_t kSamsungAcPower6Offset = 4; // Mask 0b00110000 +const uint8_t kSamsungAcPower6Size = 2; // Bits +const uint8_t kSamsungAcSwingOffset = 4; // Mask 0b01110000 +const uint8_t kSamsungAcSwingSize = 3; // Bits const uint8_t kSamsungAcSwingMove = 0b010; const uint8_t kSamsungAcSwingStop = 0b111; -const uint8_t kSamsungAcBeepMask = 0x02; // 0b00000010 -const uint8_t kSamsungAcCleanMask10 = 0x80; // 0b10000000 -const uint8_t kSamsungAcCleanMask11 = 0x02; // 0b00000010 -const uint8_t kSamsungAcQuietMask1 = 0x10; // 0b00010000 -const uint8_t kSamsungAcQuietMask5 = 0x20; // 0b00100000 -const uint8_t kSamsungAcPowerfulMask8 = 0x50; // 0b01010000 -const uint8_t kSamsungAcPowerfulMask10 = 0x06; // 0b00000110 +const uint8_t kSamsungAcBeepOffset = 1; +const uint8_t kSamsungAcClean10Offset = 7; +const uint8_t kSamsungAcClean11Offset = 1; // 0b00000010 +const uint8_t kSamsungAcQuiet1Offset = 4; +const uint8_t kSamsungAcQuiet5Offset = 5; +const uint8_t kSamsungAcPowerfulMask8 = 0b01010000; +const uint8_t kSamsungAcPowerful10Offset = 1; // Mask 0b00000110 +const uint8_t kSamsungAcPowerful10Size = 1; // Mask 0b00000110 const uint16_t kSamsungACSectionLength = 7; const uint64_t kSamsungAcPowerSection = 0x1D20F00000000; @@ -65,7 +68,7 @@ class IRSamsungAc { explicit IRSamsungAc(const uint16_t pin, const bool inverted = false, const bool use_modulation = true); - void stateReset(void); + void stateReset(const bool forcepower = true, const bool initialPower = true); #if SEND_SAMSUNG_AC void send(const uint16_t repeat = kSamsungAcDefaultRepeat, const bool calcchecksum = true); @@ -118,7 +121,8 @@ class IRSamsungAc { #endif // The state of the IR remote in IR code form. uint8_t remote_state[kSamsungAcExtendedStateLength]; - bool _sendpower; // Hack to know when we need to send a special power mesg. + bool _forcepower; // Hack to know when we need to send a special power mesg. + bool _lastsentpowerstate; void checksum(const uint16_t length = kSamsungAcStateLength); }; diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Sanyo.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Sanyo.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Sanyo.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Sanyo.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Sharp.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Sharp.cpp old mode 100755 new mode 100644 similarity index 85% rename from lib/IRremoteESP8266-2.6.5/src/ir_Sharp.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Sharp.cpp index 250248554..abd93ecf6 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Sharp.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Sharp.cpp @@ -5,11 +5,13 @@ #include "ir_Sharp.h" #include +#include #ifndef ARDUINO #include #endif #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // Equipment it seems compatible with: @@ -43,6 +45,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if (SEND_SHARP || SEND_DENON) // Send a (raw) Sharp message @@ -115,10 +119,10 @@ uint32_t IRsend::encodeSharp(const uint16_t address, const uint16_t command, const uint16_t expansion, const uint16_t check, const bool MSBfirst) { // Mask any unexpected bits. - uint16_t tempaddress = address & ((1 << kSharpAddressBits) - 1); - uint16_t tempcommand = command & ((1 << kSharpCommandBits) - 1); - uint16_t tempexpansion = expansion & 1; - uint16_t tempcheck = check & 1; + uint16_t tempaddress = GETBITS16(address, 0, kSharpAddressBits); + uint16_t tempcommand = GETBITS16(command, 0, kSharpCommandBits); + uint16_t tempexpansion = GETBITS16(expansion, 0, 1); + uint16_t tempcheck = GETBITS16(check, 0, 1); if (!MSBfirst) { // Correct bit order if needed. tempaddress = reverseBits(tempaddress, kSharpAddressBits); @@ -277,8 +281,7 @@ void IRSharpAc::begin(void) { _irsend.begin(); } #if SEND_SHARP_AC void IRSharpAc::send(const uint16_t repeat) { - this->checksum(); - _irsend.sendSharpAc(remote, kSharpAcStateLength, repeat); + _irsend.sendSharpAc(getRaw(), kSharpAcStateLength, repeat); } #endif // SEND_SHARP_AC @@ -290,9 +293,9 @@ void IRSharpAc::send(const uint16_t repeat) { // The 4 bit checksum. uint8_t IRSharpAc::calcChecksum(uint8_t state[], const uint16_t length) { uint8_t xorsum = xorBytes(state, length - 1); - xorsum ^= (state[length - 1] & 0xF); - xorsum ^= xorsum >> 4; - return xorsum & 0xF; + xorsum ^= GETBITS8(state[length - 1], kLowNibble, kNibbleSize); + xorsum ^= GETBITS8(xorsum, kHighNibble, kNibbleSize); + return GETBITS8(xorsum, kLowNibble, kNibbleSize); } // Verify the checksums are valid for a given state. @@ -302,20 +305,21 @@ uint8_t IRSharpAc::calcChecksum(uint8_t state[], const uint16_t length) { // Returns: // A boolean. bool IRSharpAc::validChecksum(uint8_t state[], const uint16_t length) { - return (state[length - 1] >> 4) == IRSharpAc::calcChecksum(state, length); + return GETBITS8(state[length - 1], kHighNibble, kNibbleSize) == + IRSharpAc::calcChecksum(state, length); } // Calculate and set the checksum values for the internal state. void IRSharpAc::checksum(void) { - remote[kSharpAcStateLength - 1] &= 0x0F; - remote[kSharpAcStateLength - 1] |= this->calcChecksum(remote) << 4; + setBits(&remote[kSharpAcStateLength - 1], kHighNibble, kNibbleSize, + this->calcChecksum(remote)); } void IRSharpAc::stateReset(void) { static const uint8_t reset[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0x00, 0x01, 0x00, 0x00, 0x08, 0x80, 0x00, 0xE0, 0x01}; - for (uint8_t i = 0; i < kSharpAcStateLength; i++) remote[i] = reset[i]; + memcpy(remote, reset, kSharpAcStateLength); } uint8_t *IRSharpAc::getRaw(void) { @@ -324,23 +328,19 @@ uint8_t *IRSharpAc::getRaw(void) { } void IRSharpAc::setRaw(const uint8_t new_code[], const uint16_t length) { - for (uint8_t i = 0; i < length && i < kSharpAcStateLength; i++) - remote[i] = new_code[i]; + memcpy(remote, new_code, std::min(length, kSharpAcStateLength)); } -void IRSharpAc::on(void) { remote[kSharpAcBytePower] |= kSharpAcBitPower; } +void IRSharpAc::on(void) { setPower(true); } -void IRSharpAc::off(void) { remote[kSharpAcBytePower] &= ~kSharpAcBitPower; } +void IRSharpAc::off(void) { setPower(false); } void IRSharpAc::setPower(const bool on) { - if (on) - this->on(); - else - this->off(); + setBit(&remote[kSharpAcBytePower], kSharpAcBitPowerOffset, on); } bool IRSharpAc::getPower(void) { - return remote[kSharpAcBytePower] & kSharpAcBitPower; + return GETBIT8(remote[kSharpAcBytePower], kSharpAcBitPowerOffset); } // Set the temp in deg C @@ -354,37 +354,34 @@ void IRSharpAc::setTemp(const uint8_t temp) { return; default: remote[kSharpAcByteTemp] = 0xC0; - remote[kSharpAcByteManual] |= kSharpAcBitTempManual; + setBit(&remote[kSharpAcByteManual], kSharpAcBitTempManualOffset); } uint8_t degrees = std::max(temp, kSharpAcMinTemp); degrees = std::min(degrees, kSharpAcMaxTemp); - remote[kSharpAcByteTemp] &= ~kSharpAcMaskTemp; - remote[kSharpAcByteTemp] |= (degrees - kSharpAcMinTemp); + setBits(&remote[kSharpAcByteTemp], kLowNibble, kNibbleSize, + degrees - kSharpAcMinTemp); } uint8_t IRSharpAc::getTemp(void) { - return (remote[kSharpAcByteTemp] & kSharpAcMaskTemp) + kSharpAcMinTemp; + return GETBITS8(remote[kSharpAcByteTemp], kLowNibble, kNibbleSize) + + kSharpAcMinTemp; } uint8_t IRSharpAc::getMode(void) { - return remote[kSharpAcByteMode] & kSharpAcMaskMode; + return GETBITS8(remote[kSharpAcByteMode], kLowNibble, kSharpAcModeSize); } void IRSharpAc::setMode(const uint8_t mode) { - const uint8_t special = 0x20; // Non-auto modes have this bit set. - remote[kSharpAcBytePower] |= special; + setBit(&remote[kSharpAcBytePower], kSharpAcBitModeNonAutoOffset, + mode != kSharpAcAuto); switch (mode) { case kSharpAcAuto: - remote[kSharpAcBytePower] &= ~special; // Auto has this bit cleared. - // FALLTHRU case kSharpAcDry: this->setTemp(0); // Dry/Auto have no temp setting. // FALLTHRU case kSharpAcCool: case kSharpAcHeat: - remote[kSharpAcByteMode] &= ~kSharpAcMaskMode; - remote[kSharpAcByteMode] |= mode; - + setBits(&remote[kSharpAcByteMode], kLowNibble, kSharpAcModeSize, mode); break; default: this->setMode(kSharpAcAuto); @@ -393,18 +390,16 @@ void IRSharpAc::setMode(const uint8_t mode) { // Set the speed of the fan void IRSharpAc::setFan(const uint8_t speed) { - remote[kSharpAcByteManual] |= kSharpAcBitFanManual; // Manual fan mode. switch (speed) { case kSharpAcFanAuto: - // Clear the manual fan bit. - remote[kSharpAcByteManual] &= ~kSharpAcBitFanManual; - // FALLTHRU case kSharpAcFanMin: case kSharpAcFanMed: case kSharpAcFanHigh: case kSharpAcFanMax: - remote[kSharpAcByteFan] &= ~kSharpAcMaskFan; - remote[kSharpAcByteFan] |= (speed << 4); + setBit(&remote[kSharpAcByteManual], kSharpAcBitFanManualOffset, + speed != kSharpAcFanAuto); + setBits(&remote[kSharpAcByteFan], kSharpAcFanOffset, kSharpAcFanSize, + speed); break; default: this->setFan(kSharpAcFanAuto); @@ -412,21 +407,17 @@ void IRSharpAc::setFan(const uint8_t speed) { } uint8_t IRSharpAc::getFan(void) { - return (remote[kSharpAcByteFan] & kSharpAcMaskFan) >> 4; + return GETBITS8(remote[kSharpAcByteFan], kSharpAcFanOffset, kSharpAcFanSize); } // Convert a standard A/C mode into its native mode. uint8_t IRSharpAc::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kSharpAcCool; - case stdAc::opmode_t::kHeat: - return kSharpAcHeat; - case stdAc::opmode_t::kDry: - return kSharpAcDry; + case stdAc::opmode_t::kCool: return kSharpAcCool; + case stdAc::opmode_t::kHeat: return kSharpAcHeat; + case stdAc::opmode_t::kDry: return kSharpAcDry; // No Fan mode. - default: - return kSharpAcAuto; + default: return kSharpAcAuto; } } @@ -434,16 +425,11 @@ uint8_t IRSharpAc::convertMode(const stdAc::opmode_t mode) { uint8_t IRSharpAc::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kSharpAcFanMin; - case stdAc::fanspeed_t::kMedium: - return kSharpAcFanMed; - case stdAc::fanspeed_t::kHigh: - return kSharpAcFanHigh; - case stdAc::fanspeed_t::kMax: - return kSharpAcFanMax; - default: - return kSharpAcFanAuto; + case stdAc::fanspeed_t::kLow: return kSharpAcFanMin; + case stdAc::fanspeed_t::kMedium: return kSharpAcFanMed; + case stdAc::fanspeed_t::kHigh: return kSharpAcFanHigh; + case stdAc::fanspeed_t::kMax: return kSharpAcFanMax; + default: return kSharpAcFanAuto; } } @@ -452,19 +438,19 @@ stdAc::opmode_t IRSharpAc::toCommonMode(const uint8_t mode) { switch (mode) { case kSharpAcCool: return stdAc::opmode_t::kCool; case kSharpAcHeat: return stdAc::opmode_t::kHeat; - case kSharpAcDry: return stdAc::opmode_t::kDry; - default: return stdAc::opmode_t::kAuto; + case kSharpAcDry: return stdAc::opmode_t::kDry; + default: return stdAc::opmode_t::kAuto; } } // Convert a native fan speed to it's common equivalent. stdAc::fanspeed_t IRSharpAc::toCommonFanSpeed(const uint8_t speed) { switch (speed) { - case kSharpAcFanMax: return stdAc::fanspeed_t::kMax; + case kSharpAcFanMax: return stdAc::fanspeed_t::kMax; case kSharpAcFanHigh: return stdAc::fanspeed_t::kHigh; - case kSharpAcFanMed: return stdAc::fanspeed_t::kMedium; - case kSharpAcFanMin: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kSharpAcFanMed: return stdAc::fanspeed_t::kMedium; + case kSharpAcFanMin: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } @@ -497,7 +483,7 @@ stdAc::state_t IRSharpAc::toCommon(void) { String IRSharpAc::toString(void) { String result = ""; result.reserve(60); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kSharpAcAuto, kSharpAcCool, kSharpAcHeat, kSharpAcDry, kSharpAcAuto); result += addTempToString(getTemp()); diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Sharp.h b/lib/IRremoteESP8266-2.7.0/src/ir_Sharp.h old mode 100755 new mode 100644 similarity index 87% rename from lib/IRremoteESP8266-2.6.5/src/ir_Sharp.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Sharp.h index e80c7cdde..e1c81c3a2 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Sharp.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Sharp.h @@ -37,16 +37,17 @@ const uint8_t kSharpAcFanMed = 0b011; // 3 (FAN2) const uint8_t kSharpAcFanHigh = 0b101; // 5 (FAN3) const uint8_t kSharpAcFanMax = 0b111; // 7 (FAN4) const uint8_t kSharpAcByteTemp = 4; -const uint8_t kSharpAcMaskTemp = 0b00001111; const uint8_t kSharpAcBytePower = 5; -const uint8_t kSharpAcBitPower = 0b00010000; +const uint8_t kSharpAcBitPowerOffset = 4; +const uint8_t kSharpAcBitModeNonAutoOffset = 5; // 0b00100000 const uint8_t kSharpAcByteMode = 6; -const uint8_t kSharpAcMaskMode = 0b00000011; +const uint8_t kSharpAcModeSize = 2; // Mask 0b00000011; const uint8_t kSharpAcByteFan = kSharpAcByteMode; -const uint8_t kSharpAcMaskFan = 0b01110000; +const uint8_t kSharpAcFanOffset = 4; // Mask 0b01110000 +const uint8_t kSharpAcFanSize = 3; // Nr. of Bits const uint8_t kSharpAcByteManual = 10; -const uint8_t kSharpAcBitFanManual = 0b00000001; -const uint8_t kSharpAcBitTempManual = 0b00000100; +const uint8_t kSharpAcBitFanManualOffset = 0; // 0b00000001 +const uint8_t kSharpAcBitTempManualOffset = 2; // 0b00000100 class IRSharpAc { diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Sherwood.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Sherwood.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Sherwood.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Sherwood.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Sony.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Sony.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Sony.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Sony.cpp diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Tcl.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Tcl.cpp old mode 100755 new mode 100644 similarity index 59% rename from lib/IRremoteESP8266-2.6.5/src/ir_Tcl.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Tcl.cpp index 0186f43e5..ff144e9c1 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Tcl.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Tcl.cpp @@ -2,10 +2,12 @@ #include "ir_Tcl.h" #include +#include #ifndef ARDUINO #include #endif #include "IRremoteESP8266.h" +#include "IRtext.h" #include "IRutils.h" // Constants @@ -16,6 +18,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_TCL112AC void IRsend::sendTcl112Ac(const unsigned char data[], const uint16_t nbytes, @@ -36,8 +40,7 @@ void IRTcl112Ac::begin(void) { this->_irsend.begin(); } #if SEND_TCL112AC void IRTcl112Ac::send(const uint16_t repeat) { - this->checksum(); - this->_irsend.sendTcl112Ac(remote_state, kTcl112AcStateLength, repeat); + this->_irsend.sendTcl112Ac(getRaw(), kTcl112AcStateLength, repeat); } #endif // SEND_TCL112AC @@ -47,8 +50,7 @@ void IRTcl112Ac::send(const uint16_t repeat) { // length: The size of the array. // Returns: // The 8 bit checksum value. -uint8_t IRTcl112Ac::calcChecksum(uint8_t state[], - const uint16_t length) { +uint8_t IRTcl112Ac::calcChecksum(uint8_t state[], const uint16_t length) { if (length) return sumBytes(state, length - 1); else @@ -73,18 +75,11 @@ bool IRTcl112Ac::validChecksum(uint8_t state[], const uint16_t length) { } void IRTcl112Ac::stateReset(void) { - for (uint8_t i = 0; i < kTcl112AcStateLength; i++) - remote_state[i] = 0x0; // A known good state. (On, Cool, 24C) - remote_state[0] = 0x23; - remote_state[1] = 0xCB; - remote_state[2] = 0x26; - remote_state[3] = 0x01; - remote_state[5] = 0x24; - remote_state[6] = 0x03; - remote_state[7] = 0x07; - remote_state[8] = 0x40; - remote_state[13] = 0x03; + static const uint8_t reset[kTcl112AcStateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03, 0x07, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x03}; + memcpy(remote_state, reset, kTcl112AcStateLength); } uint8_t* IRTcl112Ac::getRaw(void) { @@ -93,9 +88,7 @@ uint8_t* IRTcl112Ac::getRaw(void) { } void IRTcl112Ac::setRaw(const uint8_t new_code[], const uint16_t length) { - for (uint8_t i = 0; i < length && i < kTcl112AcStateLength; i++) { - remote_state[i] = new_code[i]; - } + memcpy(remote_state, new_code, std::min(length, kTcl112AcStateLength)); } // Set the requested power state of the A/C to on. @@ -106,15 +99,12 @@ void IRTcl112Ac::off(void) { this->setPower(false); } // Set the requested power state of the A/C. void IRTcl112Ac::setPower(const bool on) { - if (on) - remote_state[5] |= kTcl112AcPowerMask; - else - remote_state[5] &= ~kTcl112AcPowerMask; + setBit(&remote_state[5], kTcl112AcPowerOffset, on); } // Return the requested power state of the A/C. bool IRTcl112Ac::getPower(void) { - return remote_state[5] & kTcl112AcPowerMask; + return GETBIT8(remote_state[5], kTcl112AcPowerOffset); } // Get the requested climate operation mode of the a/c unit. @@ -137,8 +127,7 @@ void IRTcl112Ac::setMode(const uint8_t mode) { case kTcl112AcCool: case kTcl112AcHeat: case kTcl112AcDry: - remote_state[6] &= 0xF0; - remote_state[6] |= mode; + setBits(&remote_state[6], kLowNibble, kTcl112AcModeSize, mode); break; default: setMode(kTcl112AcAuto); @@ -151,17 +140,16 @@ void IRTcl112Ac::setTemp(const float celsius) { safecelsius = std::min(safecelsius, kTcl112AcTempMax); // Convert to integer nr. of half degrees. uint8_t nrHalfDegrees = safecelsius * 2; - if (nrHalfDegrees & 1) // Do we have a half degree celsius? - remote_state[12] |= kTcl112AcHalfDegree; // Add 0.5 degrees - else - remote_state[12] &= ~kTcl112AcHalfDegree; // Clear the half degree. - remote_state[7] &= 0xF0; // Clear temp bits. - remote_state[7] |= ((uint8_t)kTcl112AcTempMax - nrHalfDegrees / 2); + // Do we have a half degree celsius? + setBit(&remote_state[12], kTcl112AcHalfDegreeOffset, nrHalfDegrees & 1); + setBits(&remote_state[7], kLowNibble, kNibbleSize, + (uint8_t)kTcl112AcTempMax - nrHalfDegrees / 2); } float IRTcl112Ac::getTemp(void) { - float result = kTcl112AcTempMax - (remote_state[7] & 0xF); - if (remote_state[12] & kTcl112AcHalfDegree) result += 0.5; + float result = kTcl112AcTempMax - GETBITS8(remote_state[7], kLowNibble, + kNibbleSize); + if (GETBIT8(remote_state[12], kTcl112AcHalfDegreeOffset)) result += 0.5; return result; } @@ -173,8 +161,7 @@ void IRTcl112Ac::setFan(const uint8_t speed) { case kTcl112AcFanLow: case kTcl112AcFanMed: case kTcl112AcFanHigh: - remote_state[8] &= ~kTcl112AcFanMask; - remote_state[8] |= speed; + setBits(&remote_state[8], kLowNibble, kTcl112AcFanSize, speed); break; default: this->setFan(kTcl112AcFanAuto); @@ -183,103 +170,82 @@ void IRTcl112Ac::setFan(const uint8_t speed) { // Return the currect fan speed. uint8_t IRTcl112Ac::getFan(void) { - return remote_state[8] & kTcl112AcFanMask; + return GETBITS8(remote_state[8], kLowNibble, kTcl112AcFanSize); } // Control economy mode. void IRTcl112Ac::setEcono(const bool on) { - if (on) - remote_state[5] |= kTcl112AcBitEcono; - else - remote_state[5] &= ~kTcl112AcBitEcono; + setBit(&remote_state[5], kTcl112AcBitEconoOffset, on); } // Return the economy state of the A/C. bool IRTcl112Ac::getEcono(void) { - return remote_state[5] & kTcl112AcBitEcono; + return GETBIT8(remote_state[5], kTcl112AcBitEconoOffset); } // Control Health mode. void IRTcl112Ac::setHealth(const bool on) { - if (on) - remote_state[6] |= kTcl112AcBitHealth; - else - remote_state[6] &= ~kTcl112AcBitHealth; + setBit(&remote_state[6], kTcl112AcBitHealthOffset, on); } // Return the Health mode state of the A/C. bool IRTcl112Ac::getHealth(void) { - return remote_state[6] & kTcl112AcBitHealth; + return GETBIT8(remote_state[6], kTcl112AcBitHealthOffset); } // Control Light/Display mode. void IRTcl112Ac::setLight(const bool on) { - if (on) - remote_state[5] &= ~kTcl112AcBitLight; - else - remote_state[5] |= kTcl112AcBitLight; + setBit(&remote_state[5], kTcl112AcBitLightOffset, !on); // Cleared when on. } // Return the Light/Display mode state of the A/C. bool IRTcl112Ac::getLight(void) { - return !(remote_state[5] & kTcl112AcBitLight); + return !GETBIT8(remote_state[5], kTcl112AcBitLightOffset); } // Control Horizontal Swing. void IRTcl112Ac::setSwingHorizontal(const bool on) { - if (on) - remote_state[12] |= kTcl112AcBitSwingH; - else - remote_state[12] &= ~kTcl112AcBitSwingH; + setBit(&remote_state[12], kTcl112AcBitSwingHOffset, on); } // Return the Horizontal Swing state of the A/C. bool IRTcl112Ac::getSwingHorizontal(void) { - return remote_state[12] & kTcl112AcBitSwingH; + return GETBIT8(remote_state[12], kTcl112AcBitSwingHOffset); } // Control Vertical Swing. void IRTcl112Ac::setSwingVertical(const bool on) { - if (on) - remote_state[8] |= kTcl112AcBitSwingV; - else - remote_state[8] &= ~kTcl112AcBitSwingV; + setBits(&remote_state[8], kTcl112AcSwingVOffset, kTcl112AcSwingVSize, + on ? kTcl112AcSwingVOn : kTcl112AcSwingVOff); } // Return the Vertical Swing state of the A/C. bool IRTcl112Ac::getSwingVertical(void) { - return remote_state[8] & kTcl112AcBitSwingV; + return GETBITS8(remote_state[8], kTcl112AcSwingVOffset, kTcl112AcSwingVSize); } // Control the Turbo setting. void IRTcl112Ac::setTurbo(const bool on) { + setBit(&remote_state[6], kTcl112AcBitTurboOffset, on); if (on) { - remote_state[6] |= kTcl112AcBitTurbo; this->setFan(kTcl112AcFanHigh); this->setSwingVertical(true); - } else { - remote_state[6] &= ~kTcl112AcBitTurbo; } } // Return the Turbo setting state of the A/C. bool IRTcl112Ac::getTurbo(void) { - return remote_state[6] & kTcl112AcBitTurbo; + return GETBIT8(remote_state[6], kTcl112AcBitTurboOffset); } // Convert a standard A/C mode into its native mode. uint8_t IRTcl112Ac::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kTcl112AcCool; - case stdAc::opmode_t::kHeat: - return kTcl112AcHeat; - case stdAc::opmode_t::kDry: - return kTcl112AcDry; - case stdAc::opmode_t::kFan: - return kTcl112AcFan; - default: - return kTcl112AcAuto; + case stdAc::opmode_t::kCool: return kTcl112AcCool; + case stdAc::opmode_t::kHeat: return kTcl112AcHeat; + case stdAc::opmode_t::kDry: return kTcl112AcDry; + case stdAc::opmode_t::kFan: return kTcl112AcFan; + default: return kTcl112AcAuto; } } @@ -287,15 +253,11 @@ uint8_t IRTcl112Ac::convertMode(const stdAc::opmode_t mode) { uint8_t IRTcl112Ac::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kTcl112AcFanLow; - case stdAc::fanspeed_t::kMedium: - return kTcl112AcFanMed; + case stdAc::fanspeed_t::kLow: return kTcl112AcFanLow; + case stdAc::fanspeed_t::kMedium: return kTcl112AcFanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kTcl112AcFanHigh; - default: - return kTcl112AcFanAuto; + case stdAc::fanspeed_t::kMax: return kTcl112AcFanHigh; + default: return kTcl112AcFanAuto; } } @@ -304,9 +266,9 @@ stdAc::opmode_t IRTcl112Ac::toCommonMode(const uint8_t mode) { switch (mode) { case kTcl112AcCool: return stdAc::opmode_t::kCool; case kTcl112AcHeat: return stdAc::opmode_t::kHeat; - case kTcl112AcDry: return stdAc::opmode_t::kDry; - case kTcl112AcFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kTcl112AcDry: return stdAc::opmode_t::kDry; + case kTcl112AcFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -314,9 +276,9 @@ stdAc::opmode_t IRTcl112Ac::toCommonMode(const uint8_t mode) { 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; - default: return stdAc::fanspeed_t::kAuto; + case kTcl112AcFanMed: return stdAc::fanspeed_t::kMedium; + case kTcl112AcFanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } @@ -351,61 +313,26 @@ stdAc::state_t IRTcl112Ac::toCommon(void) { String IRTcl112Ac::toString(void) { String result = ""; result.reserve(140); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kTcl112AcAuto, kTcl112AcCool, kTcl112AcHeat, kTcl112AcDry, kTcl112AcFan); uint16_t nrHalfDegrees = this->getTemp() * 2; - result += F(", Temp: "); - result += uint64ToString(nrHalfDegrees / 2); + result += addIntToString(nrHalfDegrees / 2, kTempStr); if (nrHalfDegrees & 1) result += F(".5"); result += 'C'; result += addFanToString(getFan(), kTcl112AcFanHigh, kTcl112AcFanLow, kTcl112AcFanAuto, kTcl112AcFanAuto, kTcl112AcFanMed); - result += addBoolToString(getEcono(), F("Econo")); - result += addBoolToString(getHealth(), F("Health")); - result += addBoolToString(getLight(), F("Light")); - result += addBoolToString(getTurbo(), F("Turbo")); - result += addBoolToString(getSwingHorizontal(), F("Swing (H)")); - result += addBoolToString(getSwingVertical(), F("Swing (V)")); + result += addBoolToString(getEcono(), kEconoStr); + result += addBoolToString(getHealth(), kHealthStr); + result += addBoolToString(getLight(), kLightStr); + result += addBoolToString(getTurbo(), kTurboStr); + result += addBoolToString(getSwingHorizontal(), kSwingHStr); + result += addBoolToString(getSwingVertical(), kSwingVStr); return result; } #if DECODE_TCL112AC -// Decode the supplied TCL112AC message. -// -// Args: -// results: Ptr to the data to decode and where to store the decode result. -// nbits: The number of data bits to expect. Typically kTcl112AcBits. -// strict: Flag indicating if we should perform strict matching. -// Returns: -// boolean: True if it can decode it, false if it can't. -// -// Status: BETA / Appears to mostly work. -// -// Ref: -// https://github.com/crankyoldgit/IRremoteESP8266/issues/619 -bool IRrecv::decodeTcl112Ac(decode_results *results, const uint16_t nbits, - const bool strict) { - if (strict && nbits != kTcl112AcBits) return false; - - uint16_t offset = kStartOffset; - // Match Header + Data + Footer - if (!matchGeneric(results->rawbuf + offset, results->state, - results->rawlen - offset, nbits, - kTcl112AcHdrMark, kTcl112AcHdrSpace, - kTcl112AcBitMark, kTcl112AcOneSpace, - kTcl112AcBitMark, kTcl112AcZeroSpace, - kTcl112AcBitMark, kTcl112AcGap, true, - _tolerance + kTcl112AcTolerance, 0, false)) return false; - // Compliance - // Verify we got a valid checksum. - if (strict && !IRTcl112Ac::validChecksum(results->state)) return false; - // Success - results->decode_type = TCL112AC; - 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; -} +// NOTE: There is no `decodedecodeTcl112Ac()`. +// It's the same as `decodeMitsubishi112()`. A shared routine is used. +// You can find it in: ir_Mitsubishi.cpp #endif // DECODE_TCL112AC diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Tcl.h b/lib/IRremoteESP8266-2.7.0/src/ir_Tcl.h old mode 100755 new mode 100644 similarity index 73% rename from lib/IRremoteESP8266-2.6.5/src/ir_Tcl.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Tcl.h index 1a1bc1d6b..21e64a55a --- a/lib/IRremoteESP8266-2.6.5/src/ir_Tcl.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Tcl.h @@ -23,30 +23,37 @@ const uint16_t kTcl112AcBitMark = 500; const uint16_t kTcl112AcOneSpace = 1050; const uint16_t kTcl112AcZeroSpace = 325; const uint32_t kTcl112AcGap = kDefaultMessageGap; // Just a guess. -const uint8_t kTcl112AcTolerance = 5; // Extra Percent +// Total tolerance percentage to use for matching the header mark. +const uint8_t kTcl112AcHdrMarkTolerance = 6; +const uint8_t kTcl112AcTolerance = 5; // Extra Percentage for the rest. const uint8_t kTcl112AcHeat = 1; const uint8_t kTcl112AcDry = 2; const uint8_t kTcl112AcCool = 3; const uint8_t kTcl112AcFan = 7; const uint8_t kTcl112AcAuto = 8; -const uint8_t kTcl112AcFanMask = 0b00000111; -const uint8_t kTcl112AcFanAuto = 0b00000000; -const uint8_t kTcl112AcFanLow = 0b00000010; -const uint8_t kTcl112AcFanMed = 0b00000011; -const uint8_t kTcl112AcFanHigh = 0b00000101; +const uint8_t kTcl112AcModeSize = 4; // Nr. of Bits -const uint8_t kTcl112AcHalfDegree = 0b00100000; +const uint8_t kTcl112AcFanSize = 3; // Nr. of Bits. Mask = 0b00000111 +const uint8_t kTcl112AcFanAuto = 0b000; +const uint8_t kTcl112AcFanLow = 0b010; +const uint8_t kTcl112AcFanMed = 0b011; +const uint8_t kTcl112AcFanHigh = 0b101; + +const uint8_t kTcl112AcHalfDegreeOffset = 5; const float kTcl112AcTempMax = 31.0; const float kTcl112AcTempMin = 16.0; -const uint8_t kTcl112AcPowerMask = 0b00000100; -const uint8_t kTcl112AcBitEcono = 0b10000000; -const uint8_t kTcl112AcBitLight = 0b01000000; -const uint8_t kTcl112AcBitHealth = 0b00010000; -const uint8_t kTcl112AcBitSwingH = 0b00001000; -const uint8_t kTcl112AcBitSwingV = 0b00111000; -const uint8_t kTcl112AcBitTurbo = 0b01000000; +const uint8_t kTcl112AcPowerOffset = 2; +const uint8_t kTcl112AcBitEconoOffset = 7; +const uint8_t kTcl112AcBitLightOffset = 6; +const uint8_t kTcl112AcBitHealthOffset = 4; +const uint8_t kTcl112AcBitSwingHOffset = 3; +const uint8_t kTcl112AcSwingVOffset = 3; // Mask 0b00111000 +const uint8_t kTcl112AcSwingVSize = 3; // Nr. of bits. +const uint8_t kTcl112AcSwingVOn = 0b111; +const uint8_t kTcl112AcSwingVOff = 0b000; +const uint8_t kTcl112AcBitTurboOffset = 6; class IRTcl112Ac { diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Teco.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Teco.cpp old mode 100755 new mode 100644 similarity index 60% rename from lib/IRremoteESP8266-2.6.5/src/ir_Teco.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Teco.cpp index 9967ccee1..200f1954d --- a/lib/IRremoteESP8266-2.6.5/src/ir_Teco.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Teco.cpp @@ -6,6 +6,7 @@ Node MCU/ESP8266 Sketch to emulate Teco #include "ir_Teco.h" #include #include "IRremoteESP8266.h" +#include "IRtext.h" #include "IRutils.h" #ifndef ARDUINO #include @@ -26,6 +27,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_TECO // Send a Teco A/C message. @@ -69,26 +72,23 @@ void IRTecoAc::on(void) { setPower(true); } void IRTecoAc::off(void) { setPower(false); } void IRTecoAc::setPower(const bool on) { - if (on) - remote_state |= kTecoPower; - else - remote_state &= ~kTecoPower; + setBit(&remote_state, kTecoPowerOffset, on); } -bool IRTecoAc::getPower(void) { return remote_state & kTecoPower; } +bool IRTecoAc::getPower(void) { + return GETBIT64(remote_state, kTecoPowerOffset); +} void IRTecoAc::setTemp(const uint8_t temp) { uint8_t newtemp = temp; newtemp = std::min(newtemp, kTecoMaxTemp); newtemp = std::max(newtemp, kTecoMinTemp); - newtemp -= kTecoMinTemp; // 16=0b000 - - remote_state &= ~kTecoTempMask; // reinit temp - remote_state |= (newtemp << 8); + setBits(&remote_state, kTecoTempOffset, kTecoTempSize, + newtemp - kTecoMinTemp); } uint8_t IRTecoAc::getTemp(void) { - return ((remote_state & kTecoTempMask) >> 8) + kTecoMinTemp; + return GETBITS64(remote_state, kTecoTempOffset, kTecoTempSize) + kTecoMinTemp; } // Set the speed of the fan @@ -98,16 +98,15 @@ void IRTecoAc::setFan(const uint8_t speed) { case kTecoFanAuto: case kTecoFanHigh: case kTecoFanMed: - case kTecoFanLow: - break; - default: - newspeed = kTecoFanAuto; + case kTecoFanLow: break; + default: newspeed = kTecoFanAuto; } - remote_state &= ~kTecoFanMask; // reinit fan - remote_state |= (newspeed << 4); + setBits(&remote_state, kTecoFanOffset, kTecoFanSize, newspeed); } -uint8_t IRTecoAc::getFan(void) { return (remote_state & kTecoFanMask) >> 4; } +uint8_t IRTecoAc::getFan(void) { + return GETBITS64(remote_state, kTecoFanOffset, kTecoFanSize); +} void IRTecoAc::setMode(const uint8_t mode) { uint8_t newmode = mode; @@ -116,75 +115,99 @@ void IRTecoAc::setMode(const uint8_t mode) { case kTecoCool: case kTecoDry: case kTecoFan: - case kTecoHeat: - break; - default: - newmode = kTecoAuto; + case kTecoHeat: break; + default: newmode = kTecoAuto; } - remote_state &= ~kTecoModeMask; // reinit mode - remote_state |= newmode; + setBits(&remote_state, kTecoModeOffset, kModeBitsSize, newmode); } -uint8_t IRTecoAc::getMode(void) { return remote_state & kTecoModeMask; } +uint8_t IRTecoAc::getMode(void) { + return GETBITS64(remote_state, kTecoModeOffset, kModeBitsSize); +} void IRTecoAc::setSwing(const bool on) { - if (on) - remote_state |= kTecoSwing; - else - remote_state &= ~kTecoSwing; + setBit(&remote_state, kTecoSwingOffset, on); } -bool IRTecoAc::getSwing(void) { return remote_state & kTecoSwing; } +bool IRTecoAc::getSwing(void) { + return GETBIT64(remote_state, kTecoSwingOffset); +} void IRTecoAc::setSleep(const bool on) { - if (on) - remote_state |= kTecoSleep; - else - remote_state &= ~kTecoSleep; + setBit(&remote_state, kTecoSleepOffset, on); } -bool IRTecoAc::getSleep(void) { return remote_state & kTecoSleep; } - -bool IRTecoAc::getLight(void) { return remote_state & kTecoLight; } +bool IRTecoAc::getSleep(void) { + return GETBIT64(remote_state, kTecoSleepOffset); +} void IRTecoAc::setLight(const bool on) { - if (on) - remote_state |= kTecoLight; - else - remote_state &= ~kTecoLight; + setBit(&remote_state, kTecoLightOffset, on); } -bool IRTecoAc::getHumid(void) { return remote_state & kTecoHumid; } +bool IRTecoAc::getLight(void) { + return GETBIT64(remote_state, kTecoLightOffset); +} void IRTecoAc::setHumid(const bool on) { - if (on) - remote_state |= kTecoHumid; - else - remote_state &= ~kTecoHumid; + setBit(&remote_state, kTecoHumidOffset, on); } -bool IRTecoAc::getSave(void) { return remote_state & kTecoSave; } +bool IRTecoAc::getHumid(void) { + return GETBIT64(remote_state, kTecoHumidOffset); +} void IRTecoAc::setSave(const bool on) { - if (on) - remote_state |= kTecoSave; - else - remote_state &= ~kTecoSave; + setBit(&remote_state, kTecoSaveOffset, on); +} + +bool IRTecoAc::getSave(void) { + return GETBIT64(remote_state, kTecoSaveOffset); +} + +bool IRTecoAc::getTimerEnabled(void) { + return GETBIT64(remote_state, kTecoTimerOnOffset); +} + +uint16_t IRTecoAc::getTimer(void) { + uint16_t mins = 0; + if (getTimerEnabled()) { + mins = GETBITS64(remote_state, kTecoTimerTensHoursOffset, + kTecoTimerTensHoursSize) * 60 * 10 + + GETBITS64(remote_state, kTecoTimerUnitHoursOffset, + kTecoTimerUnitHoursSize) * 60; + if (GETBIT64(remote_state, kTecoTimerHalfHourOffset)) mins += 30; + } + return mins; +} + +// Set the timer for when the A/C unit will switch power state. +// Args: +// nr_mins: Number of minutes before power state change. +// `0` will clear the timer. Max is 24 hrs. +// Time is stored internaly in increments of 30 mins. +void IRTecoAc::setTimer(const uint16_t nr_mins) { + uint16_t mins = std::min(nr_mins, (uint16_t)(24 * 60)); // Limit to 24 hrs. + uint8_t hours = mins / 60; + setBit(&remote_state, kTecoTimerOnOffset, mins); // Set the timer flag. + // Set the half hour bit. + setBit(&remote_state, kTecoTimerHalfHourOffset, (mins % 60) >= 30); + // Set the unit hours. + setBits(&remote_state, kTecoTimerUnitHoursOffset, kTecoTimerUnitHoursSize, + hours % 10); + // Set the tens of hours. + setBits(&remote_state, kTecoTimerTensHoursOffset, kTecoTimerTensHoursSize, + hours / 10); } // Convert a standard A/C mode into its native mode. uint8_t IRTecoAc::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kTecoCool; - case stdAc::opmode_t::kHeat: - return kTecoHeat; - case stdAc::opmode_t::kDry: - return kTecoDry; - case stdAc::opmode_t::kFan: - return kTecoFan; - default: - return kTecoAuto; + case stdAc::opmode_t::kCool: return kTecoCool; + case stdAc::opmode_t::kHeat: return kTecoHeat; + case stdAc::opmode_t::kDry: return kTecoDry; + case stdAc::opmode_t::kFan: return kTecoFan; + default: return kTecoAuto; } } @@ -192,15 +215,11 @@ uint8_t IRTecoAc::convertMode(const stdAc::opmode_t mode) { uint8_t IRTecoAc::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kTecoFanLow; - case stdAc::fanspeed_t::kMedium: - return kTecoFanMed; + case stdAc::fanspeed_t::kLow: return kTecoFanLow; + case stdAc::fanspeed_t::kMedium: return kTecoFanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kTecoFanHigh; - default: - return kTecoFanAuto; + case stdAc::fanspeed_t::kMax: return kTecoFanHigh; + default: return kTecoFanAuto; } } @@ -209,9 +228,9 @@ stdAc::opmode_t IRTecoAc::toCommonMode(const uint8_t mode) { switch (mode) { case kTecoCool: return stdAc::opmode_t::kCool; case kTecoHeat: return stdAc::opmode_t::kHeat; - case kTecoDry: return stdAc::opmode_t::kDry; - case kTecoFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kTecoDry: return stdAc::opmode_t::kDry; + case kTecoFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -219,9 +238,9 @@ stdAc::opmode_t IRTecoAc::toCommonMode(const uint8_t mode) { stdAc::fanspeed_t IRTecoAc::toCommonFanSpeed(const uint8_t speed) { switch (speed) { case kTecoFanHigh: return stdAc::fanspeed_t::kMax; - case kTecoFanMed: return stdAc::fanspeed_t::kMedium; - case kTecoFanLow: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kTecoFanMed: return stdAc::fanspeed_t::kMedium; + case kTecoFanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } @@ -255,18 +274,22 @@ stdAc::state_t IRTecoAc::toCommon(void) { String IRTecoAc::toString(void) { String result = ""; result.reserve(100); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kTecoAuto, kTecoCool, kTecoHeat, kTecoDry, kTecoFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kTecoFanHigh, kTecoFanLow, kTecoFanAuto, kTecoFanAuto, kTecoFanMed); - result += addBoolToString(getSleep(), F("Sleep")); - result += addBoolToString(getSwing(), F("Swing")); - result += addBoolToString(getLight(), F("Light")); - result += addBoolToString(getHumid(), F("Humid")); - result += addBoolToString(getSave(), F("Save")); - + result += addBoolToString(getSleep(), kSleepStr); + result += addBoolToString(getSwing(), kSwingStr); + result += addBoolToString(getLight(), kLightStr); + result += addBoolToString(getHumid(), kHumidStr); + result += addBoolToString(getSave(), kSaveStr); + if (getTimerEnabled()) + result += addLabeledString(irutils::minsToString(getTimer()), + kTimerStr); + else + result += addBoolToString(false, kTimerStr); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Teco.h b/lib/IRremoteESP8266-2.7.0/src/ir_Teco.h old mode 100755 new mode 100644 similarity index 70% rename from lib/IRremoteESP8266-2.6.5/src/ir_Teco.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Teco.h index 616fc5dfb..8bee1b72b --- a/lib/IRremoteESP8266-2.6.5/src/ir_Teco.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Teco.h @@ -16,32 +16,36 @@ // Brand: Alaska, Model: SAC9010QC A/C // Brand: Alaska, Model: SAC9010QC remote -// Constants. Using LSB to be able to send only 35bits. -const uint8_t kTecoAuto = 0; // 0b000 -const uint8_t kTecoCool = 1; // 0b001 -const uint8_t kTecoDry = 2; // 0b010 -const uint8_t kTecoFan = 3; // 0b110 -const uint8_t kTecoHeat = 4; // 0b001 +// Constants. +const uint8_t kTecoAuto = 0; +const uint8_t kTecoCool = 1; +const uint8_t kTecoDry = 2; +const uint8_t kTecoFan = 3; +const uint8_t kTecoHeat = 4; const uint8_t kTecoFanAuto = 0; // 0b00 +const uint8_t kTecoFanLow = 1; // 0b01 +const uint8_t kTecoFanMed = 2; // 0b10 const uint8_t kTecoFanHigh = 3; // 0b11 -const uint8_t kTecoFanMed = 2; // 0b10 -const uint8_t kTecoFanLow = 1; // 0b01 const uint8_t kTecoMinTemp = 16; // 16C const uint8_t kTecoMaxTemp = 30; // 30C -const uint64_t kTecoModeMask = 0b00000000000000000000000000000000111; -const uint64_t kTecoPower = 0b00000000000000000000000000000001000; -const uint64_t kTecoFanMask = 0b00000000000000000000000000000110000; -const uint64_t kTecoSwing = 0b00000000000000000000000000001000000; -const uint64_t kTecoSleep = 0b00000000000000000000000000010000000; -const uint64_t kTecoTempMask = 0b00000000000000000000000111100000000; -const uint64_t kTecoTimerHalfH = 0b00000000000000000000001000000000000; -const uint64_t kTecoTimerTenHr = 0b00000000000000000000110000000000000; -const uint64_t kTecoTimerOn = 0b00000000000000000001000000000000000; -const uint64_t kTecoTimerUniHr = 0b00000000000000011110000000000000000; -const uint64_t kTecoHumid = 0b00000000000000100000000000000000000; -const uint64_t kTecoLight = 0b00000000000001000000000000000000000; -const uint64_t kTecoSave = 0b00000000000100000000000000000000000; +const uint8_t kTecoModeOffset = 0; +const uint8_t kTecoPowerOffset = 3; +const uint8_t kTecoFanOffset = 4; +const uint8_t kTecoFanSize = 2; // Nr. of bits +const uint8_t kTecoSwingOffset = 6; +const uint8_t kTecoSleepOffset = 7; +const uint8_t kTecoTempOffset = 8; +const uint8_t kTecoTempSize = 4; // Nr. of bits +const uint8_t kTecoTimerHalfHourOffset = 12; +const uint8_t kTecoTimerTensHoursOffset = 13; +const uint8_t kTecoTimerTensHoursSize = 2; // Nr. of bits +const uint8_t kTecoTimerOnOffset = 15; +const uint8_t kTecoTimerUnitHoursOffset = 16; +const uint8_t kTecoTimerUnitHoursSize = 4; // Nr. of bits +const uint8_t kTecoHumidOffset = 20; +const uint8_t kTecoLightOffset = 21; +const uint8_t kTecoSaveOffset = 23; const uint64_t kTecoReset = 0b01001010000000000000010000000000000; /* (header mark and space) @@ -136,8 +140,8 @@ class IRTecoAc { void setSave(const bool on); bool getSave(void); - // void setTimer(uint8_t time); // To check unit - // uint8_t getTimer(uint8_t); + uint16_t getTimer(void); + void setTimer(const uint16_t mins); uint64_t getRaw(void); void setRaw(const uint64_t new_code); @@ -157,6 +161,7 @@ class IRTecoAc { #endif // The state of the IR remote in IR code form. uint64_t remote_state; + bool getTimerEnabled(void); }; #endif // IR_TECO_H_ diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Toshiba.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Toshiba.cpp old mode 100755 new mode 100644 similarity index 80% rename from lib/IRremoteESP8266-2.6.5/src/ir_Toshiba.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Toshiba.cpp index 4fa4c1075..ba1ca5424 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Toshiba.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Toshiba.cpp @@ -5,11 +5,13 @@ #include "ir_Toshiba.h" #include +#include #ifndef ARDUINO #include #endif #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // @@ -37,6 +39,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_TOSHIBA_AC // Send a Toshiba A/C message. @@ -76,17 +80,10 @@ void IRToshibaAC::stateReset(void) { // The state of the IR remote in IR code form. // Known good state obtained from: // https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266T.ino#L103 - // Note: Can't use the following because it requires -std=c++11 - // uint8_t remote_state[kToshibaACStateLength] = { - // 0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00 }; - remote_state[0] = 0xF2; - remote_state[1] = 0x0D; - remote_state[2] = 0x03; - remote_state[3] = 0xFC; - remote_state[4] = 0x01; - for (uint8_t i = 5; i < kToshibaACStateLength; i++) remote_state[i] = 0; - mode_state = remote_state[6] & 0b00000011; - this->checksum(); // Calculate the checksum + static const uint8_t kReset[kToshibaACStateLength] = { + 0xF2, 0x0D, 0x03, 0xFC, 0x01}; + memcpy(remote_state, kReset, kToshibaACStateLength); + mode_state = getMode(true); } // Configure the pin for output. @@ -95,8 +92,7 @@ void IRToshibaAC::begin(void) { _irsend.begin(); } #if SEND_TOSHIBA_AC // Send the current desired state to the IR LED. void IRToshibaAC::send(const uint16_t repeat) { - this->checksum(); // Ensure correct checksum before sending. - _irsend.sendToshibaAC(remote_state, kToshibaACStateLength, repeat); + _irsend.sendToshibaAC(getRaw(), kToshibaACStateLength, repeat); } #endif // SEND_TOSHIBA_AC @@ -108,9 +104,7 @@ uint8_t* IRToshibaAC::getRaw(void) { // Override the internal state with the new state. void IRToshibaAC::setRaw(const uint8_t newState[]) { - for (uint8_t i = 0; i < kToshibaACStateLength; i++) { - remote_state[i] = newState[i]; - } + memcpy(remote_state, newState, kToshibaACStateLength); mode_state = this->getMode(true); } @@ -149,42 +143,39 @@ void IRToshibaAC::checksum(const uint16_t length) { length); } -// Set the requested power state of the A/C to off. -void IRToshibaAC::on(void) { - // state = ON; - remote_state[6] &= ~kToshibaAcPower; - setMode(mode_state); -} +// Set the requested power state of the A/C to on. +void IRToshibaAC::on(void) { setPower(true); } // Set the requested power state of the A/C to off. -void IRToshibaAC::off(void) { - // state = OFF; - remote_state[6] |= (kToshibaAcPower | 0b00000011); -} +void IRToshibaAC::off(void) { setPower(false); } // Set the requested power state of the A/C. void IRToshibaAC::setPower(const bool on) { + setBit(&remote_state[6], kToshibaAcPowerOffset, !on); // Cleared when on. if (on) - this->on(); + setMode(mode_state); else - this->off(); + setBits(&remote_state[6], kToshibaAcModeOffset, kToshibaAcModeSize, + kToshibaAcHeat); } // Return the requested power state of the A/C. bool IRToshibaAC::getPower(void) { - return ((remote_state[6] & kToshibaAcPower) == 0); + return !GETBIT8(remote_state[6], kToshibaAcPowerOffset); } // Set the temp. in deg C void IRToshibaAC::setTemp(const uint8_t degrees) { uint8_t temp = std::max((uint8_t)kToshibaAcMinTemp, degrees); temp = std::min((uint8_t)kToshibaAcMaxTemp, temp); - remote_state[5] = (temp - kToshibaAcMinTemp) << 4; + setBits(&remote_state[5], kToshibaAcTempOffset, kToshibaAcTempSize, + temp - kToshibaAcMinTemp); } // Return the set temp. in deg C uint8_t IRToshibaAC::getTemp(void) { - return ((remote_state[5] >> 4) + kToshibaAcMinTemp); + return GETBITS8(remote_state[5], kToshibaAcTempOffset, kToshibaAcTempSize) + + kToshibaAcMinTemp; } // Set the speed of the fan, 0-5. @@ -195,13 +186,13 @@ void IRToshibaAC::setFan(const uint8_t speed) { if (fan > kToshibaAcFanMax) fan = kToshibaAcFanMax; // Set the fan to maximum if out of range. if (fan > kToshibaAcFanAuto) fan++; - remote_state[6] &= 0b00011111; // Clear the previous fan state - remote_state[6] |= (fan << 5); + setBits(&remote_state[6], kToshibaAcFanOffset, kToshibaAcFanSize, fan); } // Return the requested state of the unit's fan. uint8_t IRToshibaAC::getFan(void) { - uint8_t fan = remote_state[6] >> 5; + uint8_t fan = GETBITS8(remote_state[6], kToshibaAcFanOffset, + kToshibaAcFanSize); if (fan == kToshibaAcFanAuto) return kToshibaAcFanAuto; return --fan; } @@ -213,7 +204,7 @@ uint8_t IRToshibaAC::getFan(void) { // A uint8_t containing the A/C mode. uint8_t IRToshibaAC::getMode(const bool useRaw) { if (useRaw) - return (remote_state[6] & 0b00000011); + return GETBITS8(remote_state[6], kToshibaAcModeOffset, kToshibaAcModeSize); else return mode_state; } @@ -228,47 +219,34 @@ void IRToshibaAC::setMode(const uint8_t mode) { case kToshibaAcHeat: mode_state = mode; // Only adjust the remote_state if we have power set to on. - if (getPower()) { - remote_state[6] &= 0b11111100; // Clear the previous mode. - remote_state[6] |= mode_state; - } + if (getPower()) + setBits(&remote_state[6], kToshibaAcModeOffset, kToshibaAcModeSize, + mode_state); return; - default: - // THere is no Fan mode. - this->setMode(kToshibaAcAuto); + default: this->setMode(kToshibaAcAuto); // There is no Fan mode. } } // Convert a standard A/C mode into its native mode. uint8_t IRToshibaAC::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kToshibaAcCool; - case stdAc::opmode_t::kHeat: - return kToshibaAcHeat; - case stdAc::opmode_t::kDry: - return kToshibaAcDry; + case stdAc::opmode_t::kCool: return kToshibaAcCool; + case stdAc::opmode_t::kHeat: return kToshibaAcHeat; + case stdAc::opmode_t::kDry: return kToshibaAcDry; // No Fan mode. - default: - return kToshibaAcAuto; + default: return kToshibaAcAuto; } } // Convert a standard A/C Fan speed into its native fan speed. uint8_t IRToshibaAC::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { - case stdAc::fanspeed_t::kMin: - return kToshibaAcFanMax - 4; - case stdAc::fanspeed_t::kLow: - return kToshibaAcFanMax - 3; - case stdAc::fanspeed_t::kMedium: - return kToshibaAcFanMax - 2; - case stdAc::fanspeed_t::kHigh: - return kToshibaAcFanMax - 1; - case stdAc::fanspeed_t::kMax: - return kToshibaAcFanMax; - default: - return kToshibaAcFanAuto; + case stdAc::fanspeed_t::kMin: return kToshibaAcFanMax - 4; + case stdAc::fanspeed_t::kLow: return kToshibaAcFanMax - 3; + case stdAc::fanspeed_t::kMedium: return kToshibaAcFanMax - 2; + case stdAc::fanspeed_t::kHigh: return kToshibaAcFanMax - 1; + case stdAc::fanspeed_t::kMax: return kToshibaAcFanMax; + default: return kToshibaAcFanAuto; } } @@ -277,20 +255,20 @@ stdAc::opmode_t IRToshibaAC::toCommonMode(const uint8_t mode) { switch (mode) { case kToshibaAcCool: return stdAc::opmode_t::kCool; case kToshibaAcHeat: return stdAc::opmode_t::kHeat; - case kToshibaAcDry: return stdAc::opmode_t::kDry; - default: return stdAc::opmode_t::kAuto; + case kToshibaAcDry: return stdAc::opmode_t::kDry; + default: return stdAc::opmode_t::kAuto; } } // Convert a native fan speed to it's common equivalent. stdAc::fanspeed_t IRToshibaAC::toCommonFanSpeed(const uint8_t spd) { switch (spd) { - case kToshibaAcFanMax: return stdAc::fanspeed_t::kMax; + case kToshibaAcFanMax: return stdAc::fanspeed_t::kMax; case kToshibaAcFanMax - 1: return stdAc::fanspeed_t::kHigh; case kToshibaAcFanMax - 2: return stdAc::fanspeed_t::kMedium; case kToshibaAcFanMax - 3: return stdAc::fanspeed_t::kLow; case kToshibaAcFanMax - 4: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + default: return stdAc::fanspeed_t::kAuto; } } @@ -323,7 +301,7 @@ stdAc::state_t IRToshibaAC::toCommon(void) { String IRToshibaAC::toString(void) { String result = ""; result.reserve(40); - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kToshibaAcAuto, kToshibaAcCool, kToshibaAcHeat, kToshibaAcDry, kToshibaAcAuto); result += addTempToString(getTemp()); diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Toshiba.h b/lib/IRremoteESP8266-2.7.0/src/ir_Toshiba.h old mode 100755 new mode 100644 similarity index 84% rename from lib/IRremoteESP8266-2.6.5/src/ir_Toshiba.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Toshiba.h index 6b06855bf..7a679ceda --- a/lib/IRremoteESP8266-2.6.5/src/ir_Toshiba.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Toshiba.h @@ -25,15 +25,21 @@ #endif // Constants +const uint8_t kToshibaAcModeOffset = 0; +const uint8_t kToshibaAcModeSize = 2; // Nr. of bits const uint8_t kToshibaAcAuto = 0; const uint8_t kToshibaAcCool = 1; const uint8_t kToshibaAcDry = 2; const uint8_t kToshibaAcHeat = 3; -const uint8_t kToshibaAcPower = 4; -const uint8_t kToshibaAcFanAuto = 0; -const uint8_t kToshibaAcFanMin = 1; -const uint8_t kToshibaAcFanMed = 3; -const uint8_t kToshibaAcFanMax = 5; +const uint8_t kToshibaAcPowerOffset = 2; +const uint8_t kToshibaAcFanOffset = 5; +const uint8_t kToshibaAcFanSize = 3; // Nr. of bits +const uint8_t kToshibaAcFanAuto = 0b000; +const uint8_t kToshibaAcFanMin = 0b001; +const uint8_t kToshibaAcFanMed = 0b011; +const uint8_t kToshibaAcFanMax = 0b101; +const uint8_t kToshibaAcTempOffset = 4; +const uint8_t kToshibaAcTempSize = 4; // Nr. of bits const uint8_t kToshibaAcMinTemp = 17; // 17C const uint8_t kToshibaAcMaxTemp = 30; // 30C diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Trotec.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Trotec.cpp old mode 100755 new mode 100644 similarity index 78% rename from lib/IRremoteESP8266-2.6.5/src/ir_Trotec.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Trotec.cpp index 281779f62..cb923b5fc --- a/lib/IRremoteESP8266-2.6.5/src/ir_Trotec.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Trotec.cpp @@ -3,10 +3,12 @@ #include "ir_Trotec.h" #include +#include #ifndef UNIT_TEST #include #endif #include "IRremoteESP8266.h" +#include "IRtext.h" #include "IRutils.h" // Constants @@ -24,6 +26,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; #if SEND_TROTEC @@ -31,6 +35,7 @@ void IRsend::sendTrotec(const unsigned char data[], const uint16_t nbytes, const uint16_t repeat) { if (nbytes < kTrotecStateLength) return; + enableIROut(36); for (uint16_t r = 0; r <= repeat; r++) { sendGeneric(kTrotecHdrMark, kTrotecHdrSpace, kTrotecBitMark, kTrotecOneSpace, kTrotecBitMark, kTrotecZeroSpace, @@ -38,7 +43,6 @@ void IRsend::sendTrotec(const unsigned char data[], const uint16_t nbytes, 0, // Repeats handled elsewhere 50); // More footer - enableIROut(36); mark(kTrotecBitMark); space(kTrotecGapEnd); } @@ -90,66 +94,57 @@ uint8_t* IRTrotecESP::getRaw(void) { } void IRTrotecESP::setRaw(const uint8_t state[]) { - for (uint16_t i = 0; i < kTrotecStateLength; i++) remote_state[i] = state[i]; + memcpy(remote_state, state, kTrotecStateLength); } void IRTrotecESP::setPower(const bool on) { - if (on) - remote_state[2] |= kTrotecPowerBit; - else - remote_state[2] &= ~kTrotecPowerBit; + setBit(&remote_state[2], kTrotecPowerBitOffset, on); } -bool IRTrotecESP::getPower(void) { return remote_state[2] & kTrotecPowerBit; } +bool IRTrotecESP::getPower(void) { + return GETBIT8(remote_state[2], kTrotecPowerBitOffset); +} void IRTrotecESP::setSpeed(const uint8_t fan) { uint8_t speed = std::min(fan, kTrotecFanHigh); - remote_state[2] = (remote_state[2] & 0b11001111) | (speed << 4); + setBits(&remote_state[2], kTrotecFanOffset, kTrotecFanSize, speed); } uint8_t IRTrotecESP::getSpeed(void) { - return (remote_state[2] & 0b00110000) >> 4; + return GETBITS8(remote_state[2], kTrotecFanOffset, kTrotecFanSize); } void IRTrotecESP::setMode(const uint8_t mode) { - switch (mode) { - case kTrotecAuto: - case kTrotecCool: - case kTrotecDry: - case kTrotecFan: - remote_state[2] = (remote_state[2] & 0b11111100) | mode; - return; - default: - this->setMode(kTrotecAuto); - } + setBits(&remote_state[2], kTrotecModeOffset, kTrotecModeSize, + (mode > kTrotecFan) ? kTrotecAuto : mode); } -uint8_t IRTrotecESP::getMode(void) { return remote_state[2] & 0b00000011; } +uint8_t IRTrotecESP::getMode(void) { + return GETBITS8(remote_state[2], kTrotecModeOffset, kTrotecModeSize); +} void IRTrotecESP::setTemp(const uint8_t celsius) { uint8_t temp = std::max(celsius, kTrotecMinTemp); temp = std::min(temp, kTrotecMaxTemp); - remote_state[3] = (remote_state[3] & 0x80) | (temp - kTrotecMinTemp); + setBits(&remote_state[3], kTrotecTempOffset, kTrotecTempSize, + temp - kTrotecMinTemp); } uint8_t IRTrotecESP::getTemp(void) { - return (remote_state[3] & 0b01111111) + kTrotecMinTemp; + return GETBITS8(remote_state[3], kTrotecTempOffset, kTrotecTempSize) + + kTrotecMinTemp; } void IRTrotecESP::setSleep(const bool on) { - if (on) - remote_state[3] |= kTrotecSleepBit; - else - remote_state[3] &= ~kTrotecSleepBit; + setBit(&remote_state[3], kTrotecSleepBitOffset, on); } -bool IRTrotecESP::getSleep(void) { return remote_state[3] & kTrotecSleepBit; } +bool IRTrotecESP::getSleep(void) { + return GETBIT8(remote_state[3], kTrotecSleepBitOffset); +} void IRTrotecESP::setTimer(const uint8_t timer) { - if (timer) - remote_state[5] |= kTrotecTimerBit; - else - remote_state[5] &= ~kTrotecTimerBit; + setBit(&remote_state[5], kTrotecTimerBitOffset, timer); remote_state[6] = (timer > kTrotecMaxTimer) ? kTrotecMaxTimer : timer; } @@ -158,15 +153,11 @@ uint8_t IRTrotecESP::getTimer(void) { return remote_state[6]; } // Convert a standard A/C mode into its native mode. uint8_t IRTrotecESP::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kTrotecCool; - case stdAc::opmode_t::kDry: - return kTrotecDry; - case stdAc::opmode_t::kFan: - return kTrotecFan; + case stdAc::opmode_t::kCool: return kTrotecCool; + case stdAc::opmode_t::kDry: return kTrotecDry; + case stdAc::opmode_t::kFan: return kTrotecFan; // Note: No Heat mode. - default: - return kTrotecAuto; + default: return kTrotecAuto; } } @@ -174,15 +165,11 @@ uint8_t IRTrotecESP::convertMode(const stdAc::opmode_t mode) { uint8_t IRTrotecESP::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kTrotecFanLow; - case stdAc::fanspeed_t::kMedium: - return kTrotecFanMed; + case stdAc::fanspeed_t::kLow: return kTrotecFanLow; + case stdAc::fanspeed_t::kMedium: return kTrotecFanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kTrotecFanHigh; - default: - return kTrotecFanMed; + case stdAc::fanspeed_t::kMax: return kTrotecFanHigh; + default: return kTrotecFanMed; } } @@ -191,9 +178,9 @@ uint8_t IRTrotecESP::convertFan(const stdAc::fanspeed_t speed) { stdAc::opmode_t IRTrotecESP::toCommonMode(const uint8_t mode) { switch (mode) { case kTrotecCool: return stdAc::opmode_t::kCool; - case kTrotecDry: return stdAc::opmode_t::kDry; - case kTrotecFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kTrotecDry: return stdAc::opmode_t::kDry; + case kTrotecFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -201,9 +188,9 @@ stdAc::opmode_t IRTrotecESP::toCommonMode(const uint8_t mode) { stdAc::fanspeed_t IRTrotecESP::toCommonFanSpeed(const uint8_t spd) { switch (spd) { case kTrotecFanHigh: return stdAc::fanspeed_t::kMax; - case kTrotecFanMed: return stdAc::fanspeed_t::kMedium; - case kTrotecFanLow: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kTrotecFanMed: return stdAc::fanspeed_t::kMedium; + case kTrotecFanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } @@ -236,13 +223,13 @@ stdAc::state_t IRTrotecESP::toCommon(void) { String IRTrotecESP::toString(void) { String result = ""; result.reserve(100); // Reserve some heap for the string to reduce fragging. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kTrotecAuto, kTrotecCool, kTrotecAuto, kTrotecDry, kTrotecFan); result += addTempToString(getTemp()); result += addFanToString(getSpeed(), kTrotecFanHigh, kTrotecFanLow, kTrotecFanHigh, kTrotecFanHigh, kTrotecFanMed); - result += addBoolToString(getSleep(), F("Sleep")); + result += addBoolToString(getSleep(), kSleepStr); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Trotec.h b/lib/IRremoteESP8266-2.7.0/src/ir_Trotec.h old mode 100755 new mode 100644 similarity index 87% rename from lib/IRremoteESP8266-2.6.5/src/ir_Trotec.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Trotec.h index 98bf3795c..f836b2e5e --- a/lib/IRremoteESP8266-2.6.5/src/ir_Trotec.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Trotec.h @@ -21,26 +21,31 @@ const uint8_t kTrotecIntro1 = 0x12; const uint8_t kTrotecIntro2 = 0x34; // Byte 2 +const uint8_t kTrotecModeOffset = 0; +const uint8_t kTrotecModeSize = 2; // Nr. of bits const uint8_t kTrotecAuto = 0; const uint8_t kTrotecCool = 1; const uint8_t kTrotecDry = 2; const uint8_t kTrotecFan = 3; -const uint8_t kTrotecPowerBit = 0b00001000; +const uint8_t kTrotecPowerBitOffset = 3; +const uint8_t kTrotecFanOffset = 4; +const uint8_t kTrotecFanSize = 2; // Nr. of bits const uint8_t kTrotecFanLow = 1; const uint8_t kTrotecFanMed = 2; const uint8_t kTrotecFanHigh = 3; // Byte 3 +const uint8_t kTrotecTempOffset = 0; +const uint8_t kTrotecTempSize = 4; // Nr. of bits const uint8_t kTrotecMinTemp = 18; const uint8_t kTrotecDefTemp = 25; const uint8_t kTrotecMaxTemp = 32; - -const uint8_t kTrotecSleepBit = 0b10000000; +const uint8_t kTrotecSleepBitOffset = 7; // Byte 5 -const uint8_t kTrotecTimerBit = 0b01000000; +const uint8_t kTrotecTimerBitOffset = 6; // Byte 6 const uint8_t kTrotecMaxTimer = 23; diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Vestel.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Vestel.cpp old mode 100755 new mode 100644 similarity index 64% rename from lib/IRremoteESP8266-2.6.5/src/ir_Vestel.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Vestel.cpp index 1374c6b59..c54a262d7 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Vestel.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Vestel.cpp @@ -11,6 +11,7 @@ #include "IRrecv.h" #include "IRremoteESP8266.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" #include "ir_Haier.h" @@ -27,6 +28,8 @@ using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; using irutils::minsToString; +using irutils::setBit; +using irutils::setBits; #if SEND_VESTEL_AC // Send a Vestel message @@ -71,15 +74,7 @@ void IRVestelAc::begin(void) { #if SEND_VESTEL_AC // Send the current desired state to the IR LED. -void IRVestelAc::send(void) { - this->checksum(); // Ensure correct checksum before sending. - uint64_t code_to_send; - if (use_time_state) - code_to_send = remote_time_state; - else - code_to_send = remote_state; - _irsend.sendVestelAc(code_to_send); -} +void IRVestelAc::send(void) { _irsend.sendVestelAc(getRaw()); } #endif // SEND_VESTEL_AC // Return the internal state date of the remote. @@ -117,37 +112,32 @@ void IRVestelAc::off(void) { setPower(false); } // Set the requested power state of the A/C. void IRVestelAc::setPower(const bool on) { - remote_state &= ~((uint64_t)0xF << kVestelAcPowerOffset); - if (on) - remote_state |= ((uint64_t)0xF << kVestelAcPowerOffset); - else - remote_state |= ((uint64_t)0xC << kVestelAcPowerOffset); + setBits(&remote_state, kVestelAcPowerOffset, kVestelAcPowerSize, + on ? 0b11 : 0b00); use_time_state = false; } // Return the requested power state of the A/C. bool IRVestelAc::getPower(void) { - return (remote_state >> kVestelAcPowerOffset == 0xF); + return GETBITS64(remote_state, kVestelAcPowerOffset, kVestelAcPowerSize); } // Set the temperature in Celsius degrees. void IRVestelAc::setTemp(const uint8_t temp) { - uint8_t new_temp = temp; - new_temp = std::max(kVestelAcMinTempC, new_temp); - // new_temp = std::max(kVestelAcMinTempH, new_temp); Check MODE + uint8_t new_temp = std::max(kVestelAcMinTempC, temp); new_temp = std::min(kVestelAcMaxTemp, new_temp); - remote_state &= ~((uint64_t)0xF << kVestelAcTempOffset); - remote_state |= (uint64_t)(new_temp - 16) << kVestelAcTempOffset; + setBits(&remote_state, kVestelAcTempOffset, kNibbleSize, + new_temp - kVestelAcMinTempH); use_time_state = false; } // Return the set temperature. uint8_t IRVestelAc::getTemp(void) { - return ((remote_state >> kVestelAcTempOffset) & 0xF) + 16; + return GETBITS64(remote_state, kVestelAcTempOffset, kNibbleSize) + + kVestelAcMinTempH; } // Set the speed of the fan, -// 1-3 set the fan speed, 0 or anything else set it to auto. void IRVestelAc::setFan(const uint8_t fan) { switch (fan) { case kVestelAcFanLow: @@ -156,8 +146,7 @@ void IRVestelAc::setFan(const uint8_t fan) { case kVestelAcFanAutoCool: case kVestelAcFanAutoHot: case kVestelAcFanAuto: - remote_state &= ~((uint64_t)0xF << kVestelAcFanOffset); - remote_state |= (uint64_t)fan << kVestelAcFanOffset; + setBits(&remote_state, kVestelAcFanOffset, kVestelAcFanSize, fan); break; default: setFan(kVestelAcFanAuto); @@ -167,14 +156,14 @@ void IRVestelAc::setFan(const uint8_t fan) { // Return the requested state of the unit's fan. uint8_t IRVestelAc::getFan(void) { - return (remote_state >> kVestelAcFanOffset) & 0xF; + return GETBITS64(remote_state, kVestelAcFanOffset, kVestelAcFanSize); } // Get the requested climate operation mode of the a/c unit. // Returns: // A uint8_t containing the A/C mode. uint8_t IRVestelAc::getMode(void) { - return (remote_state >> kVestelAcModeOffset) & 0xF; + return GETBITS64(remote_state, kVestelAcModeOffset, kModeBitsSize); } // Set the requested climate operation mode of the a/c unit. @@ -186,8 +175,7 @@ void IRVestelAc::setMode(const uint8_t mode) { case kVestelAcHeat: case kVestelAcDry: case kVestelAcFan: - remote_state &= ~((uint64_t)0xF << kVestelAcModeOffset); - remote_state |= (uint64_t)mode << kVestelAcModeOffset; + setBits(&remote_state, kVestelAcModeOffset, kModeBitsSize, mode); break; default: setMode(kVestelAcAuto); @@ -213,15 +201,12 @@ void IRVestelAc::setAuto(const int8_t autoLevel) { } void IRVestelAc::setTimerActive(const bool on) { - if (on) // activation - remote_time_state |= ((uint64_t)1 << kVestelAcTimerFlagOffset); - else // deactivate - remote_time_state &= ~((uint64_t)1 << kVestelAcTimerFlagOffset); + setBit(&remote_time_state, kVestelAcTimerFlagOffset, on); use_time_state = true; } bool IRVestelAc::isTimerActive(void) { - return (remote_time_state >> kVestelAcTimerFlagOffset) & 1; + return GETBIT64(remote_time_state, kVestelAcTimerFlagOffset); } // Set Timer option of AC. @@ -244,125 +229,119 @@ uint16_t IRVestelAc::getTimer(void) { return getOffTimer(); } // Set the AC's internal clock void IRVestelAc::setTime(const uint16_t minutes) { - remote_time_state &= ~((uint64_t)0x1F << kVestelAcHourOffset); - remote_time_state |= (uint64_t)((minutes / 60) & 0x1F) - << kVestelAcHourOffset; - remote_time_state &= ~((uint64_t)0xFF << kVestelAcMinuteOffset); - remote_time_state |= (uint64_t)((minutes % 60) & 0xFF) - << kVestelAcMinuteOffset; + setBits(&remote_time_state, kVestelAcHourOffset, kVestelAcHourSize, + minutes / 60); + setBits(&remote_time_state, kVestelAcMinuteOffset, kVestelAcMinuteSize, + minutes % 60); use_time_state = true; } uint16_t IRVestelAc::getTime(void) { - return ((remote_time_state >> kVestelAcHourOffset) & 0x1F) * 60 + - ((remote_time_state >> kVestelAcMinuteOffset) & 0xFF); + return GETBITS64(remote_time_state, kVestelAcHourOffset, kVestelAcHourSize) * + 60 + GETBITS64(remote_time_state, kVestelAcMinuteOffset, + kVestelAcMinuteSize); } void IRVestelAc::setOnTimerActive(const bool on) { - if (on) // activation - remote_time_state |= ((uint64_t)1 << kVestelAcOnTimerFlagOffset); - else // deactivate - remote_time_state &= ~((uint64_t)1 << kVestelAcOnTimerFlagOffset); + setBit(&remote_time_state, kVestelAcOnTimerFlagOffset, on); use_time_state = true; } bool IRVestelAc::isOnTimerActive(void) { - return (remote_time_state >> kVestelAcOnTimerFlagOffset) & 1; + return GETBIT64(remote_time_state, kVestelAcOnTimerFlagOffset); } -// Set AC's wake up time. Takes time in minute. -void IRVestelAc::setOnTimer(const uint16_t minutes) { - remote_time_state &= ~((uint64_t)0xFF << kVestelAcOnTimeOffset); - remote_time_state |= (uint64_t)(((minutes / 60) << 3) + (minutes % 60) / 10) - << kVestelAcOnTimeOffset; - setOnTimerActive(minutes != 0); +// Set a given timer (via offset). Takes time in nr. of minutes. +void IRVestelAc::_setTimer(const uint16_t minutes, const uint8_t offset) { + setBits(&remote_time_state, offset, kVestelAcTimerSize, + ((minutes / 60) << 3) + (minutes % 60) / 10); setTimerActive(false); use_time_state = true; } +// Get the number of mins a timer is set for. +uint16_t IRVestelAc::_getTimer(const uint8_t offset) { + return GETBITS64(remote_time_state, offset + kVestelAcTimerMinsSize, + kVestelAcTimerHourSize) * 60 + // Hrs + GETBITS64(remote_time_state, offset, kVestelAcTimerMinsSize) * 10; // Min +} +// Set AC's wake up time. Takes time in minute. +void IRVestelAc::setOnTimer(const uint16_t minutes) { + setOnTimerActive(minutes); + _setTimer(minutes, kVestelAcOnTimeOffset); +} + uint16_t IRVestelAc::getOnTimer(void) { - uint8_t ontime = (remote_time_state >> kVestelAcOnTimeOffset) & 0xFF; - return (ontime >> 3) * 60 + (ontime & 0x7) * 10; + return _getTimer(kVestelAcOnTimeOffset); } void IRVestelAc::setOffTimerActive(const bool on) { - if (on) // activation - remote_time_state |= ((uint64_t)1 << kVestelAcOffTimerFlagOffset); - else // deactivate - remote_time_state &= ~((uint64_t)1 << kVestelAcOffTimerFlagOffset); + setBit(&remote_time_state, kVestelAcOffTimerFlagOffset, on); use_time_state = true; } bool IRVestelAc::isOffTimerActive(void) { - return (remote_time_state >> kVestelAcOffTimerFlagOffset) & 1; + return GETBIT64(remote_time_state, kVestelAcOffTimerFlagOffset); } // Set AC's turn off time. Takes time in minute. void IRVestelAc::setOffTimer(const uint16_t minutes) { - remote_time_state &= ~((uint64_t)0xFF << kVestelAcOffTimeOffset); - remote_time_state |= - (uint64_t)((((minutes / 60) << 3) + (minutes % 60) / 10) & 0xFF) - << kVestelAcOffTimeOffset; - setOffTimerActive(minutes != 0); - setTimerActive(false); - use_time_state = true; + setOffTimerActive(minutes); + _setTimer(minutes, kVestelAcOffTimeOffset); } uint16_t IRVestelAc::getOffTimer(void) { - uint8_t offtime = (remote_time_state >> kVestelAcOffTimeOffset) & 0xFF; - return (offtime >> 3) * 60 + (offtime & 0x7) * 10; + return _getTimer(kVestelAcOffTimeOffset); } // Set the Sleep state of the A/C. void IRVestelAc::setSleep(const bool on) { - remote_state &= ~((uint64_t)0xF << kVestelAcTurboSleepOffset); - remote_state |= (uint64_t)(on ? kVestelAcSleep : kVestelAcNormal) - << kVestelAcTurboSleepOffset; + setBits(&remote_state, kVestelAcTurboSleepOffset, kNibbleSize, + on ? kVestelAcSleep : kVestelAcNormal); use_time_state = false; } // Return the Sleep state of the A/C. bool IRVestelAc::getSleep(void) { - return ((remote_state >> kVestelAcTurboSleepOffset) & 0xF) == kVestelAcSleep; + return GETBITS64(remote_state, kVestelAcTurboSleepOffset, kNibbleSize) == + kVestelAcSleep; } // Set the Turbo state of the A/C. void IRVestelAc::setTurbo(const bool on) { - remote_state &= ~((uint64_t)0xF << kVestelAcTurboSleepOffset); - remote_state |= (uint64_t)(on ? kVestelAcTurbo : kVestelAcNormal) - << kVestelAcTurboSleepOffset; + setBits(&remote_state, kVestelAcTurboSleepOffset, kNibbleSize, + on ? kVestelAcTurbo : kVestelAcNormal); use_time_state = false; } // Return the Turbo state of the A/C. bool IRVestelAc::getTurbo(void) { - return ((remote_state >> kVestelAcTurboSleepOffset) & 0xF) == kVestelAcTurbo; + return GETBITS64(remote_state, kVestelAcTurboSleepOffset, kNibbleSize) == + kVestelAcTurbo; } // Set the Ion state of the A/C. void IRVestelAc::setIon(const bool on) { - remote_state &= ~((uint64_t)0x1 << kVestelAcIonOffset); - - remote_state |= (uint64_t)(on ? 1 : 0) << kVestelAcIonOffset; + setBit(&remote_state, kVestelAcIonOffset, on); use_time_state = false; } // Return the Ion state of the A/C. bool IRVestelAc::getIon(void) { - return (remote_state >> kVestelAcIonOffset) & 1; + return GETBIT64(remote_state, kVestelAcIonOffset); } // Set the Swing Roaming state of the A/C. void IRVestelAc::setSwing(const bool on) { - remote_state &= ~((uint64_t)0xF << kVestelAcSwingOffset); - - remote_state |= (uint64_t)(on ? kVestelAcSwing : 0xF) << kVestelAcSwingOffset; + setBits(&remote_state, kVestelAcSwingOffset, kNibbleSize, + on ? kVestelAcSwing : 0xF); use_time_state = false; } // Return the Swing Roaming state of the A/C. bool IRVestelAc::getSwing(void) { - return ((remote_state >> kVestelAcSwingOffset) & 0xF) == kVestelAcSwing; + return GETBITS64(remote_state, kVestelAcSwingOffset, kNibbleSize) == + kVestelAcSwing; } // Calculate the checksum for a given array. @@ -372,13 +351,7 @@ bool IRVestelAc::getSwing(void) { // The 8 bit checksum value. uint8_t IRVestelAc::calcChecksum(const uint64_t state) { // Just counts the set bits +1 on stream and take inverse after mask - uint8_t sum = 0; - uint64_t temp_state = state & kVestelAcCRCMask; - for (; temp_state; temp_state >>= 1) - if (temp_state & 1) sum++; - sum += 2; - sum = 0xff - sum; - return sum; + return 0xFF - countBits(GETBITS64(state, 20, 44), 44, true, 2); } // Verify the checksum is valid for a given state. @@ -387,40 +360,32 @@ uint8_t IRVestelAc::calcChecksum(const uint64_t state) { // Returns: // A boolean. bool IRVestelAc::validChecksum(const uint64_t state) { - return (((state >> kVestelAcChecksumOffset) & 0xFF) == - IRVestelAc::calcChecksum(state)); + return GETBITS64(state, kVestelAcChecksumOffset, kVestelAcChecksumSize) == + IRVestelAc::calcChecksum(state); } // Calculate & set the checksum for the current internal state of the remote. void IRVestelAc::checksum(void) { // Stored the checksum value in the last byte. - remote_state &= ~((uint64_t)0xFF << kVestelAcChecksumOffset); - remote_state |= (uint64_t)this->calcChecksum(remote_state) - << kVestelAcChecksumOffset; - - remote_time_state &= ~((uint64_t)0xFF << kVestelAcChecksumOffset); - remote_time_state |= (uint64_t)this->calcChecksum(remote_time_state) - << kVestelAcChecksumOffset; + setBits(&remote_state, kVestelAcChecksumOffset, kVestelAcChecksumSize, + this->calcChecksum(remote_state)); + setBits(&remote_time_state, kVestelAcChecksumOffset, kVestelAcChecksumSize, + this->calcChecksum(remote_time_state)); } bool IRVestelAc::isTimeCommand(void) { - return (remote_state >> kVestelAcPowerOffset == 0x00 || use_time_state); + return !GETBITS64(remote_state, kVestelAcPowerOffset, kNibbleSize) || + use_time_state; } - // Convert a standard A/C mode into its native mode. uint8_t IRVestelAc::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kVestelAcCool; - case stdAc::opmode_t::kHeat: - return kVestelAcHeat; - case stdAc::opmode_t::kDry: - return kVestelAcDry; - case stdAc::opmode_t::kFan: - return kVestelAcFan; - default: - return kVestelAcAuto; + case stdAc::opmode_t::kCool: return kVestelAcCool; + case stdAc::opmode_t::kHeat: return kVestelAcHeat; + case stdAc::opmode_t::kDry: return kVestelAcDry; + case stdAc::opmode_t::kFan: return kVestelAcFan; + default: return kVestelAcAuto; } } @@ -428,15 +393,11 @@ uint8_t IRVestelAc::convertMode(const stdAc::opmode_t mode) { uint8_t IRVestelAc::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kVestelAcFanLow; - case stdAc::fanspeed_t::kMedium: - return kVestelAcFanMed; + case stdAc::fanspeed_t::kLow: return kVestelAcFanLow; + case stdAc::fanspeed_t::kMedium: return kVestelAcFanMed; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kVestelAcFanHigh; - default: - return kVestelAcFanAuto; + case stdAc::fanspeed_t::kMax: return kVestelAcFanHigh; + default: return kVestelAcFanAuto; } } @@ -445,9 +406,9 @@ stdAc::opmode_t IRVestelAc::toCommonMode(const uint8_t mode) { switch (mode) { case kVestelAcCool: return stdAc::opmode_t::kCool; case kVestelAcHeat: return stdAc::opmode_t::kHeat; - case kVestelAcDry: return stdAc::opmode_t::kDry; - case kVestelAcFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kVestelAcDry: return stdAc::opmode_t::kDry; + case kVestelAcFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } @@ -455,9 +416,9 @@ stdAc::opmode_t IRVestelAc::toCommonMode(const uint8_t mode) { stdAc::fanspeed_t IRVestelAc::toCommonFanSpeed(const uint8_t spd) { switch (spd) { case kVestelAcFanHigh: return stdAc::fanspeed_t::kMax; - case kVestelAcFanMed: return stdAc::fanspeed_t::kMedium; - case kVestelAcFanLow: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kVestelAcFanMed: return stdAc::fanspeed_t::kMedium; + case kVestelAcFanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } @@ -492,51 +453,53 @@ String IRVestelAc::toString(void) { String result = ""; result.reserve(100); // Reserve some heap for the string to reduce fragging. if (this->isTimeCommand()) { - result += addLabeledString(minsToString(getTime()), F("Time"), false); + result += addLabeledString(minsToString(getTime()), kClockStr, false); result += addLabeledString( - isTimerActive() ? minsToString(getTimer()) : F("Off"), - F("Timer")); + isTimerActive() ? minsToString(getTimer()) : kOffStr, + kTimerStr); result += addLabeledString( (isOnTimerActive() && !isTimerActive()) ? - minsToString(this->getOnTimer()) : F("Off"), - F("On Timer")); + minsToString(this->getOnTimer()) : kOffStr, + kOnTimerStr); result += addLabeledString( - isOffTimerActive() ? minsToString(getOffTimer()) : F("Off"), - F("Off Timer")); + isOffTimerActive() ? minsToString(getOffTimer()) : kOffStr, + kOffTimerStr); return result; } // Not a time command, it's a normal command. - result += addBoolToString(getPower(), F("Power"), false); + result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kVestelAcAuto, kVestelAcCool, kVestelAcHeat, kVestelAcDry, kVestelAcFan); result += addTempToString(getTemp()); - result += addIntToString(getFan(), F("Fan")); + result += addIntToString(getFan(), kFanStr); + result += kSpaceLBraceStr; switch (this->getFan()) { case kVestelAcFanAuto: - result += F(" (Auto)"); + result += kAutoStr; break; case kVestelAcFanLow: - result += F(" (Low)"); + result += kLowStr; break; case kVestelAcFanMed: - result += F(" (Medium)"); + result += kMedStr; break; case kVestelAcFanHigh: - result += F(" (High)"); + result += kHighStr; break; case kVestelAcFanAutoCool: - result += F(" (Auto Cool)"); + result += kAutoStr + ' ' + kCoolStr; break; case kVestelAcFanAutoHot: - result += F(" (Auto Hot)"); + result += kAutoStr + ' ' + kHeatStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; } - result += addBoolToString(getSleep(), F("Sleep")); - result += addBoolToString(getTurbo(), F("Turbo")); - result += addBoolToString(getIon(), F("Ion")); - result += addBoolToString(getSwing(), F("Swing")); + result += ')'; + result += addBoolToString(getSleep(), kSleepStr); + result += addBoolToString(getTurbo(), kTurboStr); + result += addBoolToString(getIon(), kIonStr); + result += addBoolToString(getSwing(), kSwingStr); return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Vestel.h b/lib/IRremoteESP8266-2.7.0/src/ir_Vestel.h old mode 100755 new mode 100644 similarity index 89% rename from lib/IRremoteESP8266-2.6.5/src/ir_Vestel.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Vestel.h index f60c031aa..38727b805 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Vestel.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Vestel.h @@ -61,8 +61,6 @@ const uint8_t kVestelAcMinTempH = 16; const uint8_t kVestelAcMinTempC = 18; const uint8_t kVestelAcMaxTemp = 30; -const uint64_t kVestelAcCRCMask = 0xFFFFFFFFFFF00000; - const uint8_t kVestelAcAuto = 0; const uint8_t kVestelAcCool = 1; const uint8_t kVestelAcDry = 2; @@ -83,21 +81,30 @@ const uint8_t kVestelAcIon = 4; const uint8_t kVestelAcSwing = 0xA; const uint8_t kVestelAcChecksumOffset = 12; +const uint8_t kVestelAcChecksumSize = 8; // Nr. of bits const uint8_t kVestelAcSwingOffset = 20; const uint8_t kVestelAcTurboSleepOffset = 24; const uint8_t kVestelAcTempOffset = 36; const uint8_t kVestelAcFanOffset = 40; +const uint8_t kVestelAcFanSize = 4; // Nr. of bits const uint8_t kVestelAcModeOffset = 44; const uint8_t kVestelAcIonOffset = 50; const uint8_t kVestelAcPowerOffset = 52; +const uint8_t kVestelAcPowerSize = 2; // Nr. of bits const uint8_t kVestelAcOffTimeOffset = 20; const uint8_t kVestelAcOnTimeOffset = 28; +const uint8_t kVestelAcTimerHourSize = 5; // Nr. of bits +const uint8_t kVestelAcTimerMinsSize = 3; // Nr. of bits +const uint8_t kVestelAcTimerSize = kVestelAcTimerHourSize + + kVestelAcTimerMinsSize; // Nr. of bits const uint8_t kVestelAcHourOffset = 36; // 5 bits +const uint8_t kVestelAcHourSize = 5; // Nr. of bits const uint8_t kVestelAcOnTimerFlagOffset = kVestelAcHourOffset + 5; const uint8_t kVestelAcOffTimerFlagOffset = kVestelAcHourOffset + 6; const uint8_t kVestelAcTimerFlagOffset = kVestelAcHourOffset + 7; const uint8_t kVestelAcMinuteOffset = 44; - +const uint8_t kVestelAcMinuteSize = 8; // Nr. of bits +// Default states const uint64_t kVestelAcStateDefault = 0x0F00D9001FEF201ULL; const uint64_t kVestelAcTimeStateDefault = 0x201ULL; @@ -168,6 +175,8 @@ class IRVestelAc { uint64_t remote_time_state; bool use_time_state; void checksum(void); + void _setTimer(const uint16_t minutes, const uint8_t offset); + uint16_t _getTimer(const uint8_t offset); }; #endif // IR_VESTEL_H_ diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Whirlpool.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Whirlpool.cpp old mode 100755 new mode 100644 similarity index 76% rename from lib/IRremoteESP8266-2.6.5/src/ir_Whirlpool.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Whirlpool.cpp index 92a9b2bb3..b9bef9120 --- a/lib/IRremoteESP8266-2.6.5/src/ir_Whirlpool.cpp +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Whirlpool.cpp @@ -16,12 +16,14 @@ #include "ir_Whirlpool.h" #include +#include #ifndef ARDUINO #include #endif #include "IRrecv.h" #include "IRremoteESP8266.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" // Constants @@ -40,8 +42,11 @@ using irutils::addFanToString; using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; +using irutils::addModelToString; using irutils::addTempToString; using irutils::minsToString; +using irutils::setBit; +using irutils::setBits; #if SEND_WHIRLPOOL_AC // Send a Whirlpool A/C message. @@ -143,12 +148,11 @@ uint8_t *IRWhirlpoolAc::getRaw(const bool calcchecksum) { } void IRWhirlpoolAc::setRaw(const uint8_t new_code[], const uint16_t length) { - for (uint8_t i = 0; i < length && i < kWhirlpoolAcStateLength; i++) - remote_state[i] = new_code[i]; + memcpy(remote_state, new_code, std::min(length, kWhirlpoolAcStateLength)); } whirlpool_ac_remote_model_t IRWhirlpoolAc::getModel(void) { - if (remote_state[kWhirlpoolAcAltTempPos] & kWhirlpoolAcAltTempMask) + if (GETBIT8(remote_state[kWhirlpoolAcAltTempPos], kWhirlpoolAcAltTempOffset)) return DG11J191; else return DG11J13A; @@ -157,12 +161,13 @@ whirlpool_ac_remote_model_t IRWhirlpoolAc::getModel(void) { void IRWhirlpoolAc::setModel(const whirlpool_ac_remote_model_t model) { switch (model) { case DG11J191: - remote_state[kWhirlpoolAcAltTempPos] |= kWhirlpoolAcAltTempMask; + setBit(&remote_state[kWhirlpoolAcAltTempPos], kWhirlpoolAcAltTempOffset); break; case DG11J13A: // FALL THRU default: - remote_state[kWhirlpoolAcAltTempPos] &= ~kWhirlpoolAcAltTempMask; + setBit(&remote_state[kWhirlpoolAcAltTempPos], kWhirlpoolAcAltTempOffset, + false); } this->_setTemp(_desiredtemp); // Different models have different temp values. } @@ -170,11 +175,8 @@ void IRWhirlpoolAc::setModel(const whirlpool_ac_remote_model_t model) { // Return the temp. offset in deg C for the current model. int8_t IRWhirlpoolAc::getTempOffset(void) { switch (this->getModel()) { - case whirlpool_ac_remote_model_t::DG11J191: - return -2; - break; - default: - return 0; + case whirlpool_ac_remote_model_t::DG11J191: return -2; + default: return 0; } } @@ -184,9 +186,8 @@ void IRWhirlpoolAc::_setTemp(const uint8_t temp, const bool remember) { int8_t offset = this->getTempOffset(); // Cache the min temp for the model. uint8_t newtemp = std::max((uint8_t)(kWhirlpoolAcMinTemp + offset), temp); newtemp = std::min((uint8_t)(kWhirlpoolAcMaxTemp + offset), newtemp); - remote_state[kWhirlpoolAcTempPos] = - (remote_state[kWhirlpoolAcTempPos] & ~kWhirlpoolAcTempMask) | - ((newtemp - (kWhirlpoolAcMinTemp + offset)) << 4); + setBits(&remote_state[kWhirlpoolAcTempPos], kHighNibble, kNibbleSize, + newtemp - (kWhirlpoolAcMinTemp + offset)); } // Set the temp. in deg C @@ -198,8 +199,8 @@ void IRWhirlpoolAc::setTemp(const uint8_t temp) { // Return the set temp. in deg C uint8_t IRWhirlpoolAc::getTemp(void) { - return ((remote_state[kWhirlpoolAcTempPos] & kWhirlpoolAcTempMask) >> 4) + - + kWhirlpoolAcMinTemp + this->getTempOffset(); + return GETBITS8(remote_state[kWhirlpoolAcTempPos], kHighNibble, kNibbleSize) + + kWhirlpoolAcMinTemp + this->getTempOffset(); } void IRWhirlpoolAc::_setMode(const uint8_t mode) { @@ -213,8 +214,8 @@ void IRWhirlpoolAc::_setMode(const uint8_t mode) { case kWhirlpoolAcCool: case kWhirlpoolAcDry: case kWhirlpoolAcFan: - remote_state[kWhirlpoolAcModePos] &= ~kWhirlpoolAcModeMask; - remote_state[kWhirlpoolAcModePos] |= mode; + setBits(&remote_state[kWhirlpoolAcModePos], kWhirlpoolAcModeOffset, + kModeBitsSize, mode); this->setCommand(kWhirlpoolAcCommandMode); break; default: @@ -229,7 +230,8 @@ void IRWhirlpoolAc::setMode(const uint8_t mode) { } uint8_t IRWhirlpoolAc::getMode(void) { - return remote_state[kWhirlpoolAcModePos] & kWhirlpoolAcModeMask; + return GETBITS8(remote_state[kWhirlpoolAcModePos], kWhirlpoolAcModeOffset, + kModeBitsSize); } void IRWhirlpoolAc::setFan(const uint8_t speed) { @@ -238,8 +240,8 @@ void IRWhirlpoolAc::setFan(const uint8_t speed) { case kWhirlpoolAcFanLow: case kWhirlpoolAcFanMedium: case kWhirlpoolAcFanHigh: - remote_state[kWhirlpoolAcFanPos] = - (remote_state[kWhirlpoolAcFanPos] & ~kWhirlpoolAcFanMask) | speed; + setBits(&remote_state[kWhirlpoolAcFanPos], kWhirlpoolAcFanOffset, + kWhirlpoolAcFanSize, speed); this->setSuper(false); // Changing fan speed cancels Super/Jet mode. this->setCommand(kWhirlpoolAcCommandFanSpeed); break; @@ -247,60 +249,54 @@ void IRWhirlpoolAc::setFan(const uint8_t speed) { } uint8_t IRWhirlpoolAc::getFan(void) { - return remote_state[kWhirlpoolAcFanPos] & kWhirlpoolAcFanMask; + return GETBITS8(remote_state[kWhirlpoolAcFanPos], kWhirlpoolAcFanOffset, + kWhirlpoolAcFanSize); } void IRWhirlpoolAc::setSwing(const bool on) { - if (on) { - remote_state[kWhirlpoolAcFanPos] |= kWhirlpoolAcSwing1Mask; - remote_state[kWhirlpoolAcOffTimerPos] |= kWhirlpoolAcSwing2Mask; - } else { - remote_state[kWhirlpoolAcFanPos] &= ~kWhirlpoolAcSwing1Mask; - remote_state[kWhirlpoolAcOffTimerPos] &= ~kWhirlpoolAcSwing2Mask; - } + setBit(&remote_state[kWhirlpoolAcFanPos], kWhirlpoolAcSwing1Offset, on); + setBit(&remote_state[kWhirlpoolAcOffTimerPos], kWhirlpoolAcSwing2Offset, on); setCommand(kWhirlpoolAcCommandSwing); } bool IRWhirlpoolAc::getSwing(void) { - return (remote_state[kWhirlpoolAcFanPos] & kWhirlpoolAcSwing1Mask) && - (remote_state[kWhirlpoolAcOffTimerPos] & kWhirlpoolAcSwing2Mask); + return GETBIT8(remote_state[kWhirlpoolAcFanPos], kWhirlpoolAcSwing1Offset) && + GETBIT8(remote_state[kWhirlpoolAcOffTimerPos], + kWhirlpoolAcSwing2Offset); } void IRWhirlpoolAc::setLight(const bool on) { - if (on) - remote_state[kWhirlpoolAcClockPos] &= ~kWhirlpoolAcLightMask; - else - remote_state[kWhirlpoolAcClockPos] |= kWhirlpoolAcLightMask; + // Cleared when on. + setBit(&remote_state[kWhirlpoolAcClockPos], kWhirlpoolAcLightOffset, !on); } bool IRWhirlpoolAc::getLight(void) { - return !(remote_state[kWhirlpoolAcClockPos] & kWhirlpoolAcLightMask); + return !GETBIT8(remote_state[kWhirlpoolAcClockPos], kWhirlpoolAcLightOffset); } void IRWhirlpoolAc::setTime(const uint16_t pos, const uint16_t minspastmidnight) { // Hours - remote_state[pos] &= ~kWhirlpoolAcHourMask; - remote_state[pos] |= (minspastmidnight / 60) % 24; + setBits(&remote_state[pos], kWhirlpoolAcHourOffset, kWhirlpoolAcHourSize, + (minspastmidnight / 60) % 24); // Minutes - remote_state[pos + 1] &= ~kWhirlpoolAcMinuteMask; - remote_state[pos + 1] |= minspastmidnight % 60; + setBits(&remote_state[pos + 1], kWhirlpoolAcMinuteOffset, + kWhirlpoolAcMinuteSize, minspastmidnight % 60); } uint16_t IRWhirlpoolAc::getTime(const uint16_t pos) { - return (remote_state[pos] & kWhirlpoolAcHourMask) * 60 + - (remote_state[pos + 1] & kWhirlpoolAcMinuteMask); + return GETBITS8(remote_state[pos], kWhirlpoolAcHourOffset, + kWhirlpoolAcHourSize) * 60 + + GETBITS8(remote_state[pos + 1], kWhirlpoolAcMinuteOffset, + kWhirlpoolAcMinuteSize); } bool IRWhirlpoolAc::isTimerEnabled(const uint16_t pos) { - return remote_state[pos - 1] & kWhirlpoolAcTimerEnableMask; + return GETBIT8(remote_state[pos - 1], kWhirlpoolAcTimerEnableOffset); } void IRWhirlpoolAc::enableTimer(const uint16_t pos, const bool on) { - if (on) - remote_state[pos - 1] |= kWhirlpoolAcTimerEnableMask; - else - remote_state[pos - 1] &= ~kWhirlpoolAcTimerEnableMask; + setBit(&remote_state[pos - 1], kWhirlpoolAcTimerEnableOffset, on); } void IRWhirlpoolAc::setClock(const uint16_t minspastmidnight) { @@ -346,16 +342,15 @@ void IRWhirlpoolAc::enableOnTimer(const bool on) { } void IRWhirlpoolAc::setPowerToggle(const bool on) { - if (on) - remote_state[kWhirlpoolAcPowerTogglePos] |= kWhirlpoolAcPowerToggleMask; - else - remote_state[kWhirlpoolAcPowerTogglePos] &= ~kWhirlpoolAcPowerToggleMask; + setBit(&remote_state[kWhirlpoolAcPowerTogglePos], + kWhirlpoolAcPowerToggleOffset, on); this->setSuper(false); // Changing power cancels Super/Jet mode. this->setCommand(kWhirlpoolAcCommandPower); } bool IRWhirlpoolAc::getPowerToggle(void) { - return remote_state[kWhirlpoolAcPowerTogglePos] & kWhirlpoolAcPowerToggleMask; + return GETBIT8(remote_state[kWhirlpoolAcPowerTogglePos], + kWhirlpoolAcPowerToggleOffset); } uint8_t IRWhirlpoolAc::getCommand(void) { @@ -363,17 +358,14 @@ uint8_t IRWhirlpoolAc::getCommand(void) { } void IRWhirlpoolAc::setSleep(const bool on) { - if (on) { - remote_state[kWhirlpoolAcSleepPos] |= kWhirlpoolAcSleepMask; - this->setFan(kWhirlpoolAcFanLow); - } else { - remote_state[kWhirlpoolAcSleepPos] &= ~kWhirlpoolAcSleepMask; - } + setBit(&remote_state[kWhirlpoolAcSleepPos], + kWhirlpoolAcSleepOffset, on); + if (on) this->setFan(kWhirlpoolAcFanLow); this->setCommand(kWhirlpoolAcCommandSleep); } bool IRWhirlpoolAc::getSleep(void) { - return remote_state[kWhirlpoolAcSleepPos] & kWhirlpoolAcSleepMask; + return GETBIT8(remote_state[kWhirlpoolAcSleepPos], kWhirlpoolAcSleepOffset); } // AKA Jet/Turbo mode. @@ -408,16 +400,11 @@ void IRWhirlpoolAc::setCommand(const uint8_t code) { // Convert a standard A/C mode into its native mode. uint8_t IRWhirlpoolAc::convertMode(const stdAc::opmode_t mode) { switch (mode) { - case stdAc::opmode_t::kCool: - return kWhirlpoolAcCool; - case stdAc::opmode_t::kHeat: - return kWhirlpoolAcHeat; - case stdAc::opmode_t::kDry: - return kWhirlpoolAcDry; - case stdAc::opmode_t::kFan: - return kWhirlpoolAcFan; - default: - return kWhirlpoolAcAuto; + case stdAc::opmode_t::kCool: return kWhirlpoolAcCool; + case stdAc::opmode_t::kHeat: return kWhirlpoolAcHeat; + case stdAc::opmode_t::kDry: return kWhirlpoolAcDry; + case stdAc::opmode_t::kFan: return kWhirlpoolAcFan; + default: return kWhirlpoolAcAuto; } } @@ -425,15 +412,11 @@ uint8_t IRWhirlpoolAc::convertMode(const stdAc::opmode_t mode) { uint8_t IRWhirlpoolAc::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { case stdAc::fanspeed_t::kMin: - case stdAc::fanspeed_t::kLow: - return kWhirlpoolAcFanLow; - case stdAc::fanspeed_t::kMedium: - return kWhirlpoolAcFanMedium; + case stdAc::fanspeed_t::kLow: return kWhirlpoolAcFanLow; + case stdAc::fanspeed_t::kMedium: return kWhirlpoolAcFanMedium; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: - return kWhirlpoolAcFanHigh; - default: - return kWhirlpoolAcFanAuto; + case stdAc::fanspeed_t::kMax: return kWhirlpoolAcFanHigh; + default: return kWhirlpoolAcFanAuto; } } @@ -442,19 +425,19 @@ stdAc::opmode_t IRWhirlpoolAc::toCommonMode(const uint8_t mode) { switch (mode) { case kWhirlpoolAcCool: return stdAc::opmode_t::kCool; case kWhirlpoolAcHeat: return stdAc::opmode_t::kHeat; - case kWhirlpoolAcDry: return stdAc::opmode_t::kDry; - case kWhirlpoolAcFan: return stdAc::opmode_t::kFan; - default: return stdAc::opmode_t::kAuto; + case kWhirlpoolAcDry: return stdAc::opmode_t::kDry; + case kWhirlpoolAcFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; } } // Convert a native fan speed to it's common equivalent. stdAc::fanspeed_t IRWhirlpoolAc::toCommonFanSpeed(const uint8_t speed) { switch (speed) { - case kWhirlpoolAcFanHigh: return stdAc::fanspeed_t::kMax; + case kWhirlpoolAcFanHigh: return stdAc::fanspeed_t::kMax; case kWhirlpoolAcFanMedium: return stdAc::fanspeed_t::kMedium; - case kWhirlpoolAcFanLow: return stdAc::fanspeed_t::kMin; - default: return stdAc::fanspeed_t::kAuto; + case kWhirlpoolAcFanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; } } @@ -488,78 +471,69 @@ stdAc::state_t IRWhirlpoolAc::toCommon(void) { String IRWhirlpoolAc::toString(void) { String result = ""; result.reserve(200); // Reserve some heap for the string to reduce fragging. - result += F("Model: "); - result += uint64ToString(this->getModel()); - switch (this->getModel()) { - case DG11J191: - result += F(" (DG11J191)"); - break; - case DG11J13A: - result += F(" (DG11J13A)"); - break; - default: - result += F(" (UNKNOWN)"); - } - result += addBoolToString(getPowerToggle(), F("Power toggle")); + result += addModelToString(decode_type_t::WHIRLPOOL_AC, getModel(), false); + result += addBoolToString(getPowerToggle(), kPowerStr + ' ' + kToggleStr); result += addModeToString(getMode(), kWhirlpoolAcAuto, kWhirlpoolAcCool, kWhirlpoolAcHeat, kWhirlpoolAcDry, kWhirlpoolAcFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kWhirlpoolAcFanHigh, kWhirlpoolAcFanLow, kWhirlpoolAcFanAuto, kWhirlpoolAcFanAuto, kWhirlpoolAcFanMedium); - result += addBoolToString(getSwing(), F("Swing")); - result += addBoolToString(getLight(), F("Light")); - result += addLabeledString(minsToString(getClock()), F("Clock")); + result += addBoolToString(getSwing(), kSwingStr); + result += addBoolToString(getLight(), kLightStr); + result += addLabeledString(minsToString(getClock()), kClockStr); result += addLabeledString( - isOnTimerEnabled() ? minsToString(getOnTimer()) : F("Off"), - F("On Timer")); + isOnTimerEnabled() ? minsToString(getOnTimer()) : kOffStr, + kOnTimerStr); result += addLabeledString( - isOffTimerEnabled() ? minsToString(getOffTimer()) : F("Off"), - F("Off Timer")); - result += addBoolToString(getSleep(), F("Sleep")); - result += addBoolToString(getSuper(), F("Super")); - result += addIntToString(getCommand(), F("Command")); + isOffTimerEnabled() ? minsToString(getOffTimer()) : kOffStr, + kOffTimerStr); + result += addBoolToString(getSleep(), kSleepStr); + result += addBoolToString(getSuper(), kSuperStr); + result += addIntToString(getCommand(), kCommandStr); + result += kSpaceLBraceStr; switch (this->getCommand()) { case kWhirlpoolAcCommandLight: - result += F(" (LIGHT)"); + result += kLightStr; break; case kWhirlpoolAcCommandPower: - result += F(" (POWER)"); + result += kPowerStr; break; case kWhirlpoolAcCommandTemp: - result += F(" (TEMP)"); + result += kTempStr; break; case kWhirlpoolAcCommandSleep: - result += F(" (SLEEP)"); + result += kSleepStr; break; case kWhirlpoolAcCommandSuper: - result += F(" (SUPER)"); + result += kSuperStr; break; case kWhirlpoolAcCommandOnTimer: - result += F(" (ONTIMER)"); + result += kOnTimerStr; break; case kWhirlpoolAcCommandMode: - result += F(" (MODE)"); + result += kModeStr; break; case kWhirlpoolAcCommandSwing: - result += F(" (SWING)"); + result += kSwingStr; break; case kWhirlpoolAcCommandIFeel: - result += F(" (IFEEL)"); + result += kIFeelStr; break; case kWhirlpoolAcCommandFanSpeed: - result += F(" (FANSPEED)"); + result += kFanStr; break; case kWhirlpoolAcCommand6thSense: - result += F(" (6THSENSE)"); + result += k6thSenseStr; break; case kWhirlpoolAcCommandOffTimer: - result += F(" (OFFTIMER)"); + result += kOffTimerStr; break; default: - result += F(" (UNKNOWN)"); + result += kUnknownStr; break; } + result += ')'; return result; } diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Whirlpool.h b/lib/IRremoteESP8266-2.7.0/src/ir_Whirlpool.h old mode 100755 new mode 100644 similarity index 87% rename from lib/IRremoteESP8266-2.6.5/src/ir_Whirlpool.h rename to lib/IRremoteESP8266-2.7.0/src/ir_Whirlpool.h index 156c4b631..11fd6949e --- a/lib/IRremoteESP8266-2.6.5/src/ir_Whirlpool.h +++ b/lib/IRremoteESP8266-2.7.0/src/ir_Whirlpool.h @@ -37,31 +37,33 @@ const uint8_t kWhirlpoolAcAuto = 1; const uint8_t kWhirlpoolAcCool = 2; const uint8_t kWhirlpoolAcDry = 3; const uint8_t kWhirlpoolAcFan = 4; -const uint8_t kWhirlpoolAcModeMask = 0b00000111; +const uint8_t kWhirlpoolAcModeOffset = 0; const uint8_t kWhirlpoolAcModePos = 3; +const uint8_t kWhirlpoolAcFanOffset = 0; // Mask 0b00000011 +const uint8_t kWhirlpoolAcFanSize = 2; // Nr. of bits const uint8_t kWhirlpoolAcFanAuto = 0; const uint8_t kWhirlpoolAcFanHigh = 1; const uint8_t kWhirlpoolAcFanMedium = 2; const uint8_t kWhirlpoolAcFanLow = 3; -const uint8_t kWhirlpoolAcFanMask = 0b00000011; const uint8_t kWhirlpoolAcFanPos = 2; const uint8_t kWhirlpoolAcMinTemp = 18; // 18C (DG11J1-3A), 16C (DG11J1-91) const uint8_t kWhirlpoolAcMaxTemp = 32; // 32C (DG11J1-3A), 30C (DG11J1-91) const uint8_t kWhirlpoolAcAutoTemp = 23; // 23C -const uint8_t kWhirlpoolAcTempMask = 0b11110000; const uint8_t kWhirlpoolAcTempPos = 3; -const uint8_t kWhirlpoolAcSwing1Mask = 0b10000000; -const uint8_t kWhirlpoolAcSwing2Mask = 0b01000000; -const uint8_t kWhirlpoolAcLightMask = 0b00100000; -const uint8_t kWhirlpoolAcPowerToggleMask = 0b00000100; +const uint8_t kWhirlpoolAcSwing1Offset = 7; +const uint8_t kWhirlpoolAcSwing2Offset = 6; +const uint8_t kWhirlpoolAcLightOffset = 5; +const uint8_t kWhirlpoolAcPowerToggleOffset = 2; // 0b00000100 const uint8_t kWhirlpoolAcPowerTogglePos = 2; -const uint8_t kWhirlpoolAcSleepMask = 0b00001000; +const uint8_t kWhirlpoolAcSleepOffset = 3; const uint8_t kWhirlpoolAcSleepPos = 2; const uint8_t kWhirlpoolAcSuperMask = 0b10010000; const uint8_t kWhirlpoolAcSuperPos = 5; -const uint8_t kWhirlpoolAcHourMask = 0b00011111; -const uint8_t kWhirlpoolAcMinuteMask = 0b00111111; -const uint8_t kWhirlpoolAcTimerEnableMask = 0b10000000; +const uint8_t kWhirlpoolAcHourOffset = 0; // Mask 0b00011111 +const uint8_t kWhirlpoolAcHourSize = 5; // Nr. of bits +const uint8_t kWhirlpoolAcMinuteOffset = 0; // Mask 0b00111111 +const uint8_t kWhirlpoolAcMinuteSize = 6; // Nr. of bits +const uint8_t kWhirlpoolAcTimerEnableOffset = 7; // 0b10000000 const uint8_t kWhirlpoolAcClockPos = 6; const uint8_t kWhirlpoolAcOffTimerPos = 8; const uint8_t kWhirlpoolAcOnTimerPos = 10; @@ -78,14 +80,9 @@ const uint8_t kWhirlpoolAcCommandIFeel = 0x0D; const uint8_t kWhirlpoolAcCommandFanSpeed = 0x11; const uint8_t kWhirlpoolAcCommand6thSense = 0x17; const uint8_t kWhirlpoolAcCommandOffTimer = 0x1D; -const uint8_t kWhirlpoolAcAltTempMask = 0b00001000; +const uint8_t kWhirlpoolAcAltTempOffset = 3; const uint8_t kWhirlpoolAcAltTempPos = 18; -enum whirlpool_ac_remote_model_t { - DG11J13A = 1, // DG11J1-04 too - DG11J191, -}; - // Classes class IRWhirlpoolAc { public: diff --git a/lib/IRremoteESP8266-2.6.5/src/ir_Whynter.cpp b/lib/IRremoteESP8266-2.7.0/src/ir_Whynter.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/src/ir_Whynter.cpp rename to lib/IRremoteESP8266-2.7.0/src/ir_Whynter.cpp diff --git a/lib/IRremoteESP8266-2.7.0/src/locale/README.md b/lib/IRremoteESP8266-2.7.0/src/locale/README.md new file mode 100644 index 000000000..6b55571bf --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/locale/README.md @@ -0,0 +1,97 @@ +# Internationalisation (I18N) & Locale Files + +This directory contains the files used by the library to store the text it uses. If you want to add support for a language, this is the +correct place. If you are adding text strings to a routine, you should use the ones here. + +## Changing the language/locale used by the library. +There are several ways to change which locale file is used by the library. Use which ever one suits your needs best. +To keep the space used by the library to a minimum, all methods require the change to happen at compile time. +There is _no_ runtime option to change locales. + +### Change `_IR_LOCALE_` in the `src/IRremoteESP8266.h` file. +In the [IRremoteESP8266.h](../IRremoteESP8266.h#L57-L59) file, find and locate the lines that look like: +``` +#ifndef _IR_LOCALE_ +#define _IR_LOCALE_ en-AU +#endif // _IR_LOCALE_ +``` + +Change `en-AU` to the language & country that best suits your needs. e.g. `de-DE` for Germany/German. + +### Use a compile-time build flag. +Use the compiler flag: `-D_IR_LOCALE_=en-AU` when compiling the library. Especially when compiling the `IRtext.cpp` file. +Change `en-AU` to a value which matches one of the file names in this directory. e.g. `de-DE` for Germany/German, which will use +the `de_DE.h` file. + +### Use the appropriate pre-prepared build environment. _(PlatformIO only)_ +If you examine the `platformio.ini` file located in the same directory as the example code you may find pre-setup compile environments +for the different supported locales. +Choose the appropriate one for you language by asking PlatformIO to build or upload using that environment. +e.g. See `IRrecvDumpV2`'s [platformio.ini](../../examples/IRrecvDumpV2/platformio.ini) + +### Use a custom `build_flags`. _(PlatformIO only)_ +Edit the `platformio.ini` file in the directory containing your example/source code. +Either in the default PlatformIO environment (`[env]`), or in which ever PlatformIO environment you using, +change or add the following line: +``` +build_flags = -D_IR_LOCALE_=en-AU ; Or use which ever locale variable you want. +``` + +Every time you change that line, you should do a `pio clean` or choose the `clean` option from the build menu, to ensure a fresh copy +of `IRtext.o` is created. + +## Adding support for a new locale/language. + +Only [ASCII](https://en.wikipedia.org/wiki/ASCII#8-bit_codes)/[UTF-8](https://en.wikipedia.org/wiki/UTF-8) 8-bit characters are supported. +[Unicode](https://en.wikipedia.org/wiki/Unicode) is **not** supported. Unicode may work. It may not. It's just not supported. +i.e. If Arduino's `Serial.print()` can handle it, it will probably work. + +### Copy/create a new locale file in this directory. +Copy [en-AU.h](en-AU.h) or which every is a closer fit for your language to `xx-YY.h` where `xx` is the [ISO code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes) for the language. +e.g. `en` is English. `de` is German etc. and `YY` is the ISO country code. e.g. `AU` is Australia. +Modify the comments and all `LOCALE_EN_AU_H_`s in the file to `LOCALE_XX_YY_H_` for your locale. + + +### Override any `#define` values that reside in `defaults.h` +Go through the [defaults.h](defaults.h) file, and find any `#define` lines that define a macro starting with `D_` that has text +that needs to change for your locale. +Copy or create a corresponding `#define D_STR_HELLOWORLD "Hello World"` in your `xx-YY.h` file, and translate the text appropriately +e.g. `#define D_STR_HELLOWORLD "Bonjour le monde"` (French) + +Any values you `#define` in `xx-YY.h` will override the corresponding value in the [defaults.h](defaults.h) file. + +### Supporting a dialect/regional varient of another _existing_ language/locale. +Similar to the previous step, if you only need to modify a small subset of the strings used in another locale file, then include the +other locale file and then make sure to `#undef` any strings that need to be (re-)changed. +See the [Swiss-German](de-CH.h) for an example of how to do this. i.e. It `#include "locale/de-DE.h"`s the German locale, and +redefines any strings that are not standard [German](de-DE.h). + +## Adding new text strings to the library. +If you need to add an entirely new string to the library to support some feature etc. e.g. _"Widget"_. +You should first understand how the library tries to do this such that it is easy to support different languages for it. + +1. Use a constant named `kWidgetStr` in the appropriate statement in the `.cpp` file. +2. Edit [IRtext.cpp](IRtext.cpp), and add the appropriate line for your new constant. e.g. +``` +String kWidgetStr = D_STR_WIDGET; +``` +The `kWidgetStr` variable will house the sole copy of the string for the entire library. This limits any duplication. +The `D_STR_WIDGET` macro will be what is targeted by the different language / locales files. + +3. Edit [locale/defaults.h](defaults.h), and add the appropriate stanza for your new string. e.g. +``` +#ifndef D_STR_WIDGET +#define D_STR_WIDGET "Turbo" +#endif // D_STR_WIDGET +``` + + +4. _(Manual)_ Update [IRtext.h](../IRtext.h), and add the appropriate line for your new constant. e.g. +``` +extern const String kWidgetStr; +``` +For any file that `#include `s this file, it will tell it that the string is stored elsewhere, +and to look for it elsewhere at the object linking stage of the build. This is what makes the string be referenced from a central location. + +4. _(Automatic)_ Run `tools/generate_irtext_h.sh` to update [IRtext.h](../IRtext.h). +In the [src/locale](../locale) directory. Run the `../../tools/generate_irtext_h.sh` command. It will update the file for you automatically. diff --git a/lib/IRremoteESP8266-2.7.0/src/locale/de-CH.h b/lib/IRremoteESP8266-2.7.0/src/locale/de-CH.h new file mode 100644 index 000000000..2c34ca97b --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/locale/de-CH.h @@ -0,0 +1,158 @@ +// Copyright 2019 - Martin (@finfinack) +// Locale/language file for German / Switzerland. +// This file will override the default values located in `defaults.h`. +#ifndef LOCALE_DE_CH_H_ +#define LOCALE_DE_CH_H_ + +// Import German / Germany as default overrides. +#include "locale/de-DE.h" + +// As we have loaded another language, we need to #undef anything we need +// to update/change. + +#undef D_STR_ON +#define D_STR_ON "Ii" +#undef D_STR_OFF +#define D_STR_OFF "Us" +#undef D_STR_TOGGLE +#define D_STR_TOGGLE "Umschalte" +#undef D_STR_SLEEP +#define D_STR_SLEEP "Schlafe" +#undef D_STR_LIGHT +#define D_STR_LIGHT "Liecht" +#undef D_STR_POWERFUL +#define D_STR_POWERFUL "Starch" +#undef D_STR_QUIET +#define D_STR_QUIET "Liislig" +#undef D_STR_CLEAN +#define D_STR_CLEAN "Reinige" +#undef D_STR_PURIFY +#define D_STR_PURIFY "Frische" +#undef D_STR_HEALTH +#define D_STR_HEALTH "Gsundheit" +#undef D_STR_HUMID +#define D_STR_HUMID "Füecht" +#undef D_STR_SAVE +#define D_STR_SAVE "Speichere" +#undef D_STR_EYE +#define D_STR_EYE "Aug" +#undef D_STR_FOLLOW +#define D_STR_FOLLOW "Folge" +#undef D_STR_HOLD +#define D_STR_HOLD "Halte" +#undef D_STR_BUTTON +#define D_STR_BUTTON "Chnopf" +#undef D_STR_UP +#define D_STR_UP "Ufe" +#undef D_STR_TEMPUP +#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP +#undef D_STR_DOWN +#define D_STR_DOWN "Abe" +#undef D_STR_TEMPDOWN +#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN +#undef D_STR_CHANGE +#define D_STR_CHANGE "Wechsele" +#undef D_STR_MOVE +#define D_STR_MOVE "Verschiebe" +#undef D_STR_SET +#define D_STR_SET "Setze" +#undef D_STR_CANCEL +#define D_STR_CANCEL "Abbreche" +#undef D_STR_WEEKLY +#define D_STR_WEEKLY "Wüchentlich" +#undef D_STR_WEEKLYTIMER +#define D_STR_WEEKLYTIMER D_STR_WEEKLY " " D_STR_TIMER +#undef D_STR_OUTSIDE +#define D_STR_OUTSIDE "Dusse" +#undef D_STR_LOUD +#define D_STR_LOUD "Luut" +#undef D_STR_UPPER +#define D_STR_UPPER "Obe" +#undef D_STR_LOWER +#define D_STR_LOWER "Une" +#undef D_STR_CIRCULATE +#define D_STR_CIRCULATE "Zirkuliere" +#undef D_STR_CEILING +#define D_STR_CEILING "Decki" +#undef D_STR_6THSENSE +#define D_STR_6THSENSE "6te Sinn" + +#undef D_STR_COOL +#define D_STR_COOL "Chüehle" +#undef D_STR_HEAT +#define D_STR_HEAT "Heize" +#undef D_STR_DRY +#define D_STR_DRY "Tröchne" + +#undef D_STR_MED +#define D_STR_MED "Mit" +#undef D_STR_MEDIUM +#define D_STR_MEDIUM "Mittel" + +#undef D_STR_HIGHEST +#define D_STR_HIGHEST "Höchscht" +#undef D_STR_HIGH +#define D_STR_HIGH "Höch" +#undef D_STR_HI +#define D_STR_HI "H" +#undef D_STR_MID +#define D_STR_MID "M" +#undef D_STR_MIDDLE +#define D_STR_MIDDLE "Mittel" +#undef D_STR_LOW +#define D_STR_LOW "Tüüf" +#undef D_STR_LO +#define D_STR_LO "T" +#undef D_STR_LOWEST +#define D_STR_LOWEST "Tüfschte" +#undef D_STR_MAXRIGHT +#define D_STR_MAXRIGHT D_STR_MAX " " D_STR_RIGHT +#undef D_STR_RIGHTMAX_NOSPACE +#define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX +#undef D_STR_MAXLEFT +#define D_STR_MAXLEFT D_STR_MAX " " D_STR_LEFT +#undef D_STR_LEFTMAX_NOSPACE +#define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX +#undef D_STR_CENTRE +#define D_STR_CENTRE "Mitti" +#undef D_STR_TOP +#define D_STR_TOP "Obe" +#undef D_STR_BOTTOM +#define D_STR_BOTTOM "Une" + +#undef D_STR_DAY +#define D_STR_DAY "Tag" +#undef D_STR_DAYS +#define D_STR_DAYS "Täg" +#undef D_STR_HOUR +#define D_STR_HOUR "Stund" +#undef D_STR_HOURS +#define D_STR_HOURS D_STR_HOUR "e" +#undef D_STR_MINUTE +#define D_STR_MINUTE "Minute" +#undef D_STR_MINUTES +#define D_STR_MINUTES D_STR_MINUTE +#undef D_STR_SECONDS +#define D_STR_SECONDS D_STR_SECOND +#undef D_STR_NOW +#define D_STR_NOW "Jetz" + +#undef D_STR_NO +#define D_STR_NO "Nei" + +#undef D_STR_REPEAT +#define D_STR_REPEAT "Wiederhole" + +// IRrecvDumpV2 +#undef D_STR_TIMESTAMP +#define D_STR_TIMESTAMP "Ziitstämpfel" +#undef D_STR_IRRECVDUMP_STARTUP +#define D_STR_IRRECVDUMP_STARTUP \ + "IRrecvDumpV2 lauft und wartet uf IR Iigab ufem Pin %d" +#undef D_WARN_BUFFERFULL +#define D_WARN_BUFFERFULL \ + "WARNUNG: IR Code isch zgross für de Buffer (>= %d). " \ + "Dem Resultat sött mer nöd vertraue bevor das behobe isch. " \ + "Bearbeite & vergrössere `kCaptureBufferSize`." + +#endif // LOCALE_DE_CH_H_ diff --git a/lib/IRremoteESP8266-2.7.0/src/locale/de-DE.h b/lib/IRremoteESP8266-2.7.0/src/locale/de-DE.h new file mode 100644 index 000000000..f366936b0 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/locale/de-DE.h @@ -0,0 +1,126 @@ +// Copyright 2019 - Martin (@finfinack) +// Locale/language file for German / Germany. +// This file will override the default values located in `defaults.h`. +#ifndef LOCALE_DE_DE_H_ +#define LOCALE_DE_DE_H_ + +#define D_STR_UNKNOWN "UNBEKANNT" +#define D_STR_PROTOCOL "Protokoll" +#define D_STR_ON "Ein" +#define D_STR_OFF "Aus" +#define D_STR_MODE "Modus" +#define D_STR_TOGGLE "Umschalten" +#define D_STR_SLEEP "Schlafen" +#define D_STR_LIGHT "Licht" +#define D_STR_POWERFUL "Stark" +#define D_STR_QUIET "Ruhig" +#define D_STR_ECONO "Eco" +#define D_STR_BEEP "Piep" +#define D_STR_MOULD "Schimmel" +#define D_STR_CLEAN "Reinigen" +#define D_STR_PURIFY "Frischen" +#define D_STR_TIMER "Timer" +#define D_STR_ONTIMER D_STR_ON " " D_STR_TIMER +#define D_STR_OFFTIMER D_STR_OFF " " D_STR_TIMER +#define D_STR_CLOCK "Uhr" +#define D_STR_COMMAND "Befehl" +#define D_STR_HEALTH "Gesundheit" +#define D_STR_TEMP "Temp" +#define D_STR_HUMID "Feucht" +#define D_STR_SAVE "Speichern" +#define D_STR_EYE "Auge" +#define D_STR_FOLLOW "Folgen" +#define D_STR_FRESH "Frisch" +#define D_STR_HOLD "Halten" +#define D_STR_BUTTON "Knopf" +#define D_STR_NIGHT "Nacht" +#define D_STR_SILENT "Ruhig" +#define D_STR_UP "Hinauf" +#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP +#define D_STR_DOWN "Hinunter" +#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN +#define D_STR_CHANGE "Wechseln" +#define D_STR_MOVE "Verschieben" +#define D_STR_SET "Setzen" +#define D_STR_CANCEL "Abbrechen" +#define D_STR_COMFORT "Komfort" +#define D_STR_WEEKLY "Wöchentlich" +#define D_STR_WEEKLYTIMER D_STR_WEEKLY " " D_STR_TIMER +#define D_STR_FAST "Schnell" +#define D_STR_SLOW "Langsam" +#define D_STR_AIRFLOW "Luftzug" +#define D_STR_STEP "Schritt" +#define D_STR_NA "N/A" +#define D_STR_OUTSIDE "Draussen" +#define D_STR_LOUD "Laut" +#define D_STR_UPPER "Oben" +#define D_STR_LOWER "Unten" +#define D_STR_BREEZE "Brise" +#define D_STR_CIRCULATE "Zirkulieren" +#define D_STR_CEILING "Decke" +#define D_STR_WALL "Wand" +#define D_STR_ROOM "Raum" +#define D_STR_6THSENSE "6ter Sinn" +#define D_STR_FIXED "Fixiert" + +#define D_STR_AUTOMATIC "Automatisch" +#define D_STR_MANUAL "Manuell" +#define D_STR_COOL "Kühlen" +#define D_STR_HEAT "Heizen" +#define D_STR_FAN "Lüfter" +#define D_STR_FANONLY "nur_lüfter" +#define D_STR_DRY "Trocken" + +#define D_STR_MED "Mit" +#define D_STR_MEDIUM "Mittel" + +#define D_STR_HIGHEST "Höchste" +#define D_STR_HIGH "Hoch" +#define D_STR_HI "H" +#define D_STR_MID "M" +#define D_STR_MIDDLE "Mittel" +#define D_STR_LOW "Tief" +#define D_STR_LO "T" +#define D_STR_LOWEST "Tiefste" +#define D_STR_RIGHT "Rechts" +#define D_STR_MAXRIGHT D_STR_MAX " " D_STR_RIGHT +#define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX +#define D_STR_LEFT "Links" +#define D_STR_MAXLEFT D_STR_MAX " " D_STR_LEFT +#define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX +#define D_STR_WIDE "Breit" +#define D_STR_CENTRE "Mitte" +#define D_STR_TOP "Oben" +#define D_STR_BOTTOM "Unten" + +#define D_STR_DAY "Tag" +#define D_STR_DAYS D_STR_DAY "e" +#define D_STR_HOUR "Stunde" +#define D_STR_HOURS D_STR_HOUR "n" +#define D_STR_MINUTES D_STR_MINUTE "n" +#define D_STR_SECOND "Sekunde" +#define D_STR_SECONDS D_STR_SECOND "n" +#define D_STR_NOW "Jetzt" +// These don't translate well to German as typically only 2 letter +// abbreviations are used. Hence, this is an approximation. +#define D_STR_THREELETTERDAYS "SonMonDieMitDonFreSam" + +#define D_STR_YES "Ja" +#define D_STR_NO "Nein" +#define D_STR_TRUE "Wahr" +#define D_STR_FALSE "Falsch" + +#define D_STR_REPEAT "Wiederholen" + +// IRrecvDumpV2 +#define D_STR_TIMESTAMP "Zeitstempel" +#define D_STR_LIBRARY "Bibliothek" +#define D_STR_MESGDESC "Nachr. Beschr." +#define D_STR_IRRECVDUMP_STARTUP \ + "IRrecvDumpV2 läuft und wartet auf IR Eingabe auf Pin %d" +#define D_WARN_BUFFERFULL \ + "WARNUNG: IR Code ist zu gross für Buffer (>= %d). " \ + "Dem Resultat sollte nicht vertraut werden bevor das behoben ist. " \ + "Bearbeite & vergrössere `kCaptureBufferSize`." + +#endif // LOCALE_DE_DE_H_ diff --git a/lib/IRremoteESP8266-2.7.0/src/locale/defaults.h b/lib/IRremoteESP8266-2.7.0/src/locale/defaults.h new file mode 100644 index 000000000..57d2d9d5b --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/locale/defaults.h @@ -0,0 +1,440 @@ +// Copyright 2019 - David Conran (@crankyoldgit) +// The default text to use throughout the library. +// The library will use this text if no locale (_IR_LOCALE_) is set or if +// the locale doesn't define particular values. +// If they are defined, this file should NOT override them. +// +// This file should contain a #define for every translateable/locale dependant +// string used by the library. Language specific files don't have to include +// everything. +// +// NOTE: ASCII/UTF-8 characters only. Unicode is NOT supported. +// +// The defaults are English (AU) / en-AU. Australia (AU) is pretty much the same +// as English (UK) for this libraries use case. +#ifndef LOCALE_DEFAULTS_H_ +#define LOCALE_DEFAULTS_H_ + +#ifndef D_STR_UNKNOWN +#define D_STR_UNKNOWN "UNKNOWN" +#endif // D_STR_UNKNOWN +#ifndef D_STR_PROTOCOL +#define D_STR_PROTOCOL "Protocol" +#endif // D_STR_PROTOCOL +#ifndef D_STR_POWER +#define D_STR_POWER "Power" +#endif // D_STR_POWER +#ifndef D_STR_ON +#define D_STR_ON "On" +#endif // D_STR_ON +#ifndef D_STR_OFF +#define D_STR_OFF "Off" +#endif // D_STR_OFF +#ifndef D_STR_MODE +#define D_STR_MODE "Mode" +#endif // D_STR_MODE +#ifndef D_STR_TOGGLE +#define D_STR_TOGGLE "Toggle" +#endif // D_STR_TOGGLE +#ifndef D_STR_TURBO +#define D_STR_TURBO "Turbo" +#endif // D_STR_TURBO +#ifndef D_STR_SUPER +#define D_STR_SUPER "Super" +#endif // D_STR_SUPER +#ifndef D_STR_SLEEP +#define D_STR_SLEEP "Sleep" +#endif // D_STR_SLEEP +#ifndef D_STR_LIGHT +#define D_STR_LIGHT "Light" +#endif // D_STR_LIGHT +#ifndef D_STR_POWERFUL +#define D_STR_POWERFUL "Powerful" +#endif // D_STR_POWERFUL +#ifndef D_STR_QUIET +#define D_STR_QUIET "Quiet" +#endif // D_STR_QUIET +#ifndef D_STR_ECONO +#define D_STR_ECONO "Econo" +#endif // D_STR_ECONO +#ifndef D_STR_SWING +#define D_STR_SWING "Swing" +#endif // D_STR_SWING +#ifndef D_STR_SWINGH +#define D_STR_SWINGH D_STR_SWING"(H)" // Set `D_STR_SWING` first! +#endif // D_STR_SWINGH +#ifndef D_STR_SWINGV +#define D_STR_SWINGV D_STR_SWING"(V)" // Set `D_STR_SWING` first! +#endif // D_STR_SWINGV +#ifndef D_STR_BEEP +#define D_STR_BEEP "Beep" +#endif // D_STR_BEEP +#ifndef D_STR_MOULD +#define D_STR_MOULD "Mould" +#endif // D_STR_MOULD +#ifndef D_STR_CLEAN +#define D_STR_CLEAN "Clean" +#endif // D_STR_CLEAN +#ifndef D_STR_PURIFY +#define D_STR_PURIFY "Purify" +#endif // D_STR_PURIFY +#ifndef D_STR_TIMER +#define D_STR_TIMER "Timer" +#endif // D_STR_TIMER +#ifndef D_STR_ONTIMER +#define D_STR_ONTIMER D_STR_ON " " D_STR_TIMER // Set `D_STR_ON` first! +#endif // D_STR_ONTIMER +#ifndef D_STR_OFFTIMER +#define D_STR_OFFTIMER D_STR_OFF " " D_STR_TIMER // Set `D_STR_OFF` first! +#endif // D_STR_OFFTIMER +#ifndef D_STR_CLOCK +#define D_STR_CLOCK "Clock" +#endif // D_STR_CLOCK +#ifndef D_STR_COMMAND +#define D_STR_COMMAND "Command" +#endif // D_STR_COMMAND +#ifndef D_STR_XFAN +#define D_STR_XFAN "XFan" +#endif // D_STR_XFAN +#ifndef D_STR_HEALTH +#define D_STR_HEALTH "Health" +#endif // D_STR_HEALTH +#ifndef D_STR_MODEL +#define D_STR_MODEL "Model" +#endif // D_STR_MODEL +#ifndef D_STR_TEMP +#define D_STR_TEMP "Temp" +#endif // D_STR_TEMP +#ifndef D_STR_IFEEL +#define D_STR_IFEEL "IFeel" +#endif // D_STR_IFEEL +#ifndef D_STR_HUMID +#define D_STR_HUMID "Humid" +#endif // D_STR_HUMID +#ifndef D_STR_SAVE +#define D_STR_SAVE "Save" +#endif // D_STR_SAVE +#ifndef D_STR_EYE +#define D_STR_EYE "Eye" +#endif // D_STR_EYE +#ifndef D_STR_FOLLOW +#define D_STR_FOLLOW "Follow" +#endif // D_STR_FOLLOW +#ifndef D_STR_ION +#define D_STR_ION "Ion" +#endif // D_STR_ION +#ifndef D_STR_FRESH +#define D_STR_FRESH "Fresh" +#endif // D_STR_FRESH +#ifndef D_STR_HOLD +#define D_STR_HOLD "Hold" +#endif // D_STR_HOLD +#ifndef D_STR_8C_HEAT +#define D_STR_8C_HEAT "8C " D_STR_HEAT // Set `D_STR_HEAT` first! +#endif // D_STR_8C_HEAT +#ifndef D_STR_BUTTON +#define D_STR_BUTTON "Button" +#endif // D_STR_BUTTON +#ifndef D_STR_NIGHT +#define D_STR_NIGHT "Night" +#endif // D_STR_NIGHT +#ifndef D_STR_SILENT +#define D_STR_SILENT "Silent" +#endif // D_STR_SILENT +#ifndef D_STR_FILTER +#define D_STR_FILTER "Filter" +#endif // D_STR_FILTER +#ifndef D_STR_3D +#define D_STR_3D "3D" +#endif // D_STR_3D +#ifndef D_STR_CELSIUS +#define D_STR_CELSIUS "Celsius" +#endif // D_STR_CELSIUS +#ifndef D_STR_UP +#define D_STR_UP "Up" +#endif // D_STR_UP +#ifndef D_STR_TEMPUP +#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP // Set `D_STR_TEMP` first! +#endif // D_STR_TEMPUP +#ifndef D_STR_DOWN +#define D_STR_DOWN "Down" +#endif // D_STR_DOWN +#ifndef D_STR_TEMPDOWN +#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN // Set `D_STR_TEMP` first! +#endif // D_STR_TEMPDOWN +#ifndef D_STR_CHANGE +#define D_STR_CHANGE "Change" +#endif // D_STR_CHANGE +#ifndef D_STR_START +#define D_STR_START "Start" +#endif // D_STR_START +#ifndef D_STR_STOP +#define D_STR_STOP "Stop" +#endif // D_STR_STOP +#ifndef D_STR_MOVE +#define D_STR_MOVE "Move" +#endif // D_STR_MOVE +#ifndef D_STR_SET +#define D_STR_SET "Set" +#endif // D_STR_SET +#ifndef D_STR_CANCEL +#define D_STR_CANCEL "Cancel" +#endif // D_STR_CANCEL +#ifndef D_STR_COMFORT +#define D_STR_COMFORT "Comfort" +#endif // D_STR_COMFORT +#ifndef D_STR_SENSOR +#define D_STR_SENSOR "Sensor" +#endif // D_STR_SENSOR +#ifndef D_STR_WEEKLY +#define D_STR_WEEKLY "Weekly" +#endif // D_STR_WEEKLY +#ifndef D_STR_WEEKLYTIMER +#define D_STR_WEEKLYTIMER D_STR_WEEKLY " " D_STR_TIMER // Needs `D_STR_WEEKLY`! +#endif // D_STR_WEEKLYTIMER +#ifndef D_STR_WIFI +#define D_STR_WIFI "WiFi" +#endif // D_STR_WIFI +#ifndef D_STR_LAST +#define D_STR_LAST "Last" +#endif // D_STR_LAST +#ifndef D_STR_FAST +#define D_STR_FAST "Fast" +#endif // D_STR_FAST +#ifndef D_STR_SLOW +#define D_STR_SLOW "Slow" +#endif // D_STR_SLOW +#ifndef D_STR_AIRFLOW +#define D_STR_AIRFLOW "Air Flow" +#endif // D_STR_AIRFLOW +#ifndef D_STR_STEP +#define D_STR_STEP "Step" +#endif // D_STR_STEP +#ifndef D_STR_NA +#define D_STR_NA "N/A" +#endif // D_STR_NA +#ifndef D_STR_OUTSIDE +#define D_STR_OUTSIDE "Outside" +#endif // D_STR_OUTSIDE +#ifndef D_STR_LOUD +#define D_STR_LOUD "Loud" +#endif // D_STR_LOUD +#ifndef D_STR_UPPER +#define D_STR_UPPER "Upper" +#endif // D_STR_UPPER +#ifndef D_STR_LOWER +#define D_STR_LOWER "Lower" +#endif // D_STR_LOWER +#ifndef D_STR_BREEZE +#define D_STR_BREEZE "Breeze" +#endif // D_STR_BREEZE +#ifndef D_STR_CIRCULATE +#define D_STR_CIRCULATE "Circulate" +#endif // D_STR_CIRCULATE +#ifndef D_STR_CEILING +#define D_STR_CEILING "Ceiling" +#endif // D_STR_CEILING +#ifndef D_STR_WALL +#define D_STR_WALL "Wall" +#endif // D_STR_WALL +#ifndef D_STR_ROOM +#define D_STR_ROOM "Room" +#endif // D_STR_ROOM +#ifndef D_STR_6THSENSE +#define D_STR_6THSENSE "6th Sense" +#endif // D_STR_6THSENSE +#ifndef D_STR_ZONEFOLLOW +#define D_STR_ZONEFOLLOW "Zone Follow" +#endif // D_STR_ZONEFOLLOW +#ifndef D_STR_FIXED +#define D_STR_FIXED "Fixed" +#endif // D_STR_FIXED + +#ifndef D_STR_AUTO +#define D_STR_AUTO "Auto" +#endif // D_STR_AUTO +#ifndef D_STR_AUTOMATIC +#define D_STR_AUTOMATIC "Automatic" +#endif // D_STR_AUTOMATIC +#ifndef D_STR_MANUAL +#define D_STR_MANUAL "Manual" +#endif // D_STR_MANUAL +#ifndef D_STR_COOL +#define D_STR_COOL "Cool" +#endif // D_STR_COOL +#ifndef D_STR_HEAT +#define D_STR_HEAT "Heat" +#endif // D_STR_HEAT +#ifndef D_STR_FAN +#define D_STR_FAN "Fan" +#endif // D_STR_FAN +#ifndef D_STR_FANONLY +#define D_STR_FANONLY "fan_only" +#endif // D_STR_FANONLY +#ifndef D_STR_DRY +#define D_STR_DRY "Dry" +#endif // D_STR_DRY + +#ifndef D_STR_MAX +#define D_STR_MAX "Max" +#endif // D_STR_MAX +#ifndef D_STR_MAXIMUM +#define D_STR_MAXIMUM "Maximum" +#endif // D_STR_MAXIMUM +#ifndef D_STR_MIN +#define D_STR_MIN "Min" +#endif // D_STR_MIN +#ifndef D_STR_MINIMUM +#define D_STR_MINIMUM "Minimum" +#endif // D_STR_MINIMUM +#ifndef D_STR_MED +#define D_STR_MED "Med" +#endif // D_STR_MED +#ifndef D_STR_MEDIUM +#define D_STR_MEDIUM "Medium" +#endif // D_STR_MEDIUM + +#ifndef D_STR_HIGHEST +#define D_STR_HIGHEST "Highest" +#endif // D_STR_HIGHEST +#ifndef D_STR_HIGH +#define D_STR_HIGH "High" +#endif // D_STR_HIGH +#ifndef D_STR_HI +#define D_STR_HI "Hi" +#endif // D_STR_HI +#ifndef D_STR_MID +#define D_STR_MID "Mid" +#endif // D_STR_MID +#ifndef D_STR_MIDDLE +#define D_STR_MIDDLE "Middle" +#endif // D_STR_MIDDLE +#ifndef D_STR_LOW +#define D_STR_LOW "Low" +#endif // D_STR_LOW +#ifndef D_STR_LO +#define D_STR_LO "Lo" +#endif // D_STR_LO +#ifndef D_STR_LOWEST +#define D_STR_LOWEST "Lowest" +#endif // D_STR_LOWEST +#ifndef D_STR_RIGHT +#define D_STR_RIGHT "Right" +#endif // D_STR_RIGHT +#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_RIGHTMAX_NOSPACE +#define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX // Set `D_STR_MAX` first! +#endif // D_STR_RIGHTMAX_NOSPACE +#ifndef D_STR_LEFT +#define D_STR_LEFT "Left" +#endif // D_STR_LEFT +#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_LEFTMAX_NOSPACE +#define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX // Set `D_STR_MAX` first! +#endif // D_STR_LEFTMAX_NOSPACE +#ifndef D_STR_WIDE +#define D_STR_WIDE "Wide" +#endif // D_STR_WIDE +#ifndef D_STR_CENTRE +#define D_STR_CENTRE "Centre" +#endif // D_STR_CENTRE +#ifndef D_STR_TOP +#define D_STR_TOP "Top" +#endif // D_STR_TOP +#ifndef D_STR_BOTTOM +#define D_STR_BOTTOM "Bottom" +#endif // D_STR_BOTTOM + +#ifndef D_STR_SPACELBRACE +#define D_STR_SPACELBRACE " (" +#endif // D_STR_SPACELBRACE +#ifndef D_STR_COMMASPACE +#define D_STR_COMMASPACE ", " +#endif // D_STR_COMMASPACE +#ifndef D_STR_COLONSPACE +#define D_STR_COLONSPACE ": " +#endif // D_STR_COLONSPACE + +#ifndef D_CHR_TIME_SEP +#define D_CHR_TIME_SEP ':' +#endif // D_CHR_TIME_SEP +#ifndef D_STR_DAY +#define D_STR_DAY "Day" +#endif // D_STR_DAY +#ifndef D_STR_DAYS +#define D_STR_DAYS D_STR_DAY "s" +#endif // D_STR_DAYS +#ifndef D_STR_HOUR +#define D_STR_HOUR "Hour" +#endif // D_STR_HOUR +#ifndef D_STR_HOURS +#define D_STR_HOURS D_STR_HOUR "s" +#endif // D_STR_HOURS +#ifndef D_STR_MINUTE +#define D_STR_MINUTE "Minute" +#endif // D_STR_MINUTE +#ifndef D_STR_MINUTES +#define D_STR_MINUTES D_STR_MINUTE "s" +#endif // D_STR_MINUTES +#ifndef D_STR_SECOND +#define D_STR_SECOND "Second" +#endif // D_STR_SECOND +#ifndef D_STR_SECONDS +#define D_STR_SECONDS D_STR_SECOND "s" +#endif // D_STR_SECONDS +#ifndef D_STR_NOW +#define D_STR_NOW "Now" +#endif // D_STR_NOW +#ifndef D_STR_THREELETTERDAYS +#define D_STR_THREELETTERDAYS "SunMonTueWedThuFriSat" +#endif // D_STR_THREELETTERDAYS + +#ifndef D_STR_YES +#define D_STR_YES "Yes" +#endif // D_STR_YES +#ifndef D_STR_NO +#define D_STR_NO "No" +#endif // D_STR_NO +#ifndef D_STR_TRUE +#define D_STR_TRUE "True" +#endif // D_STR_TRUE +#ifndef D_STR_FALSE +#define D_STR_FALSE "False" +#endif // D_STR_FALSE + +#ifndef D_STR_REPEAT +#define D_STR_REPEAT "Repeat" +#endif // D_STR_REPEAT +#ifndef D_STR_CODE +#define D_STR_CODE "Code" +#endif // D_STR_CODE +#ifndef D_STR_BITS +#define D_STR_BITS "Bits" +#endif // D_STR_BITS + +// IRrecvDumpV2 +#ifndef D_STR_TIMESTAMP +#define D_STR_TIMESTAMP "Timestamp" +#endif // D_STR_TIMESTAMP +#ifndef D_STR_LIBRARY +#define D_STR_LIBRARY "Library" +#endif // D_STR_LIBRARY +#ifndef D_STR_MESGDESC +#define D_STR_MESGDESC "Mesg Desc." +#endif // D_STR_MESGDESC +#ifndef D_STR_IRRECVDUMP_STARTUP +#define D_STR_IRRECVDUMP_STARTUP \ + "IRrecvDumpV2 is now running and waiting for IR input on Pin %d" +#endif // D_STR_IRRECVDUMP_STARTUP +#ifndef D_WARN_BUFFERFULL +#define D_WARN_BUFFERFULL \ + "WARNING: IR code is too big for buffer (>= %d). " \ + "This result shouldn't be trusted until this is resolved. " \ + "Edit & increase `kCaptureBufferSize`." +#endif // D_WARN_BUFFERFULL + +#endif // LOCALE_DEFAULTS_H_ diff --git a/lib/IRremoteESP8266-2.7.0/src/locale/en-AU.h b/lib/IRremoteESP8266-2.7.0/src/locale/en-AU.h new file mode 100644 index 000000000..63ecf2282 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/locale/en-AU.h @@ -0,0 +1,8 @@ +// Copyright 2019 - David Conran (@crankyoldgit) +// Locale/language file for English / Australia. +// This file will override the default values located in `defaults.h`. +#ifndef LOCALE_EN_AU_H_ +#define LOCALE_EN_AU_H_ +// Nothing should really need to be set here, as en-AU is the default +// locale/language. +#endif // LOCALE_EN_AU_H__ diff --git a/lib/IRremoteESP8266-2.7.0/src/locale/en-IE.h b/lib/IRremoteESP8266-2.7.0/src/locale/en-IE.h new file mode 100644 index 000000000..6a0304bca --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/locale/en-IE.h @@ -0,0 +1,8 @@ +// Copyright 2019 - David Conran (@crankyoldgit) +// Locale/language file for English / Ireland. +// This file will override the default values located in `defaults.h`. +#ifndef LOCALE_EN_IE_H_ +#define LOCALE_EN_IE_H_ +// Nothing should really need to be set here, as en-IE is the same as en-AU, +// which is the default locale/language. +#endif // LOCALE_EN_IE_H__ diff --git a/lib/IRremoteESP8266-2.7.0/src/locale/en-UK.h b/lib/IRremoteESP8266-2.7.0/src/locale/en-UK.h new file mode 100644 index 000000000..2aa57f5ce --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/locale/en-UK.h @@ -0,0 +1,8 @@ +// Copyright 2019 - David Conran (@crankyoldgit) +// Locale/language file for English / United Kingdom. +// This file will override the default values located in `defaults.h`. +#ifndef LOCALE_EN_UK_H_ +#define LOCALE_EN_UK_H_ +// Nothing should really need to be set here, as en-UK is the same as en-AU, +// which is the default locale/language. +#endif // LOCALE_EN_UK_H__ diff --git a/lib/IRremoteESP8266-2.7.0/src/locale/en-US.h b/lib/IRremoteESP8266-2.7.0/src/locale/en-US.h new file mode 100644 index 000000000..7dda393bf --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/locale/en-US.h @@ -0,0 +1,13 @@ +// Copyright 2019 - David Conran (@crankyoldgit) +// Locale/language file for English / United States of America. +// This file will override the default values located in `defaults.h`. +#ifndef LOCALE_EN_US_H_ +#define LOCALE_EN_US_H_ +// Not much should really need to be set here, as English is the default +// locale/language. + +// Overrides to the default. +#define D_STR_CENTRE "Center" +#define D_STR_MOULD "Mold" + +#endif // LOCALE_EN_US_H__ diff --git a/lib/IRremoteESP8266-2.7.0/src/locale/es-ES.h b/lib/IRremoteESP8266-2.7.0/src/locale/es-ES.h new file mode 100644 index 000000000..821186141 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/locale/es-ES.h @@ -0,0 +1,134 @@ +// Copyright 2019 - Carlos (@charlieyv) +// Locale/language file for Spanish / Spain. +// This file will override the default values located in `defaults.h`. +#ifndef LOCALE_ES_ES_H_ +#define LOCALE_ES_ES_H_ + +#define D_STR_UNKNOWN "DESCONOCIDO" +#define D_STR_PROTOCOL "Protocolo" +#define D_STR_POWER "Poder" +#define D_STR_ON "Encendido" +#define D_STR_OFF "Apagado" +#define D_STR_MODE "Modo" +#define D_STR_TOGGLE "Palanca" +#define D_STR_SLEEP "Dormir" +#define D_STR_LIGHT "Luz" +#define D_STR_POWERFUL "Poderoso" +#define D_STR_QUIET "Silencio" +#define D_STR_ECONO "Econo" +#define D_STR_SWING "Oscilar" +#define D_STR_SWINGH D_STR_SWING"(H)" +#define D_STR_SWINGV D_STR_SWING"(V)" +#define D_STR_BEEP "Bip" +#define D_STR_MOULD "Molde" +#define D_STR_CLEAN "Limpiar" +#define D_STR_PURIFY "Purificar" +#define D_STR_TIMER "Temporizador" +#define D_STR_ONTIMER D_STR_ON " " D_STR_TIMER +#define D_STR_OFFTIMER D_STR_OFF " " D_STR_TIMER +#define D_STR_CLOCK "Reloj" +#define D_STR_COMMAND "Comando" +#define D_STR_HEALTH "Salud" +#define D_STR_MODEL "Modelo" +#define D_STR_TEMP "Temperatura" +#define D_STR_HUMID "Humedo" +#define D_STR_SAVE "Guardar" +#define D_STR_EYE "Ojo" +#define D_STR_FOLLOW "Seguir" +#define D_STR_FRESH "Fresco" +#define D_STR_HOLD "Mantener" +#define D_STR_8C_HEAT "8C " D_STR_HEAT +#define D_STR_BUTTON "Boton" +#define D_STR_NIGHT "Noche" +#define D_STR_SILENT "Silencio" +#define D_STR_FILTER "Filtro" +#define D_STR_UP "Arriba" +#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP +#define D_STR_DOWN "Abajo" +#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN +#define D_STR_CHANGE "Cambiar" +#define D_STR_START "Comenzar" +#define D_STR_STOP "Parar" +#define D_STR_MOVE "Mover" +#define D_STR_SET "Fijar" +#define D_STR_CANCEL "Cancelar" +#define D_STR_COMFORT "Comodo" +#define D_STR_WEEKLY "Semanal" +#define D_STR_WEEKLYTIMER D_STR_WEEKLY " " D_STR_TIMER +#define D_STR_LAST "Ultimo" +#define D_STR_FAST "Rapido" +#define D_STR_SLOW "Lento" +#define D_STR_AIRFLOW "Flujo de Aire" +#define D_STR_STEP "Paso" +#define D_STR_OUTSIDE "Afuera" +#define D_STR_LOUD "Ruidoso" +#define D_STR_UPPER "Superior" +#define D_STR_LOWER "Inferior" +#define D_STR_BREEZE "Brisa" +#define D_STR_CIRCULATE "Circular" +#define D_STR_CEILING "Techo" +#define D_STR_WALL "Pared" +#define D_STR_ROOM "Cuarto" +#define D_STR_6THSENSE "6to. Sentido" +#define D_STR_ZONEFOLLOW "Zona Seguir" +#define D_STR_FIXED "Fijo" +#define D_STR_AUTOMATIC "Automatico" +#define D_STR_COOL "Frio" +#define D_STR_HEAT "Calor" +#define D_STR_FAN "Ventilador" +#define D_STR_FANONLY "ventilador_solamente" +#define D_STR_DRY "Seco" +#define D_STR_MAX "Max" +#define D_STR_MAXIMUM "Maximo" +#define D_STR_MIN "Min" +#define D_STR_MINIMUM "Minimo" +#define D_STR_MED "Med" +#define D_STR_MEDIUM "Medio" +#define D_STR_HIGHEST "Mas Alto" +#define D_STR_HIGH "Alto" +#define D_STR_HI D_STR_HIGH +#define D_STR_MIDDLE "Medio" +#define D_STR_MID D_STR_MIDDLE +#define D_STR_LOW "Bajo" +#define D_STR_LO D_STR_LOW +#define D_STR_LOWEST "Mas Bajo" +#define D_STR_RIGHT "Derecha" +#define D_STR_MAXRIGHT D_STR_MAX " " D_STR_RIGHT +#define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX +#define D_STR_LEFT "Izquierda" +#define D_STR_MAXLEFT D_STR_MAX " " D_STR_LEFT +#define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX +#define D_STR_WIDE "Ancho" +#define D_STR_CENTRE "Centro" +#define D_STR_TOP "Tope" +#define D_STR_BOTTOM "Fondo" +#define D_STR_DAY "Dia" +#define D_STR_DAYS D_STR_DAY "s" +#define D_STR_HOUR "Hora" +#define D_STR_HOURS D_STR_HOUR "s" +#define D_STR_MINUTE "Minuto" +#define D_STR_MINUTES D_STR_MINUTE "s" +#define D_STR_SECOND "Segundo" +#define D_STR_SECONDS D_STR_SECOND "s" +#define D_STR_NOW "Ahora" +#define D_STR_THREELETTERDAYS "DomLunMarMieJueVieSab" +#define D_STR_YES "Si" +#define D_STR_NO "No" +#define D_STR_TRUE "Cierto" +#define D_STR_FALSE "Falso" +#define D_STR_REPEAT "Repetir" +#define D_STR_CODE "Codigo" + +// IRrecvDumpV2 +#define D_STR_TIMESTAMP "marca de tiempo" +#define D_STR_LIBRARY "Libreria" +#define D_STR_IRRECVDUMP_STARTUP \ + "IRrecvDumpV2 esta ahora corriendo y esperando por comando IR en Pin %d" +#ifndef D_WARN_BUFFERFULL +#define D_WARN_BUFFERFULL \ + "WARNING: Codigo IR es muy grande para el buffer (>= %d). "\ + "Este resultando no debe ser reconocido hasta que esto sea resuelto." \ + "Edite & incremente `kCaptureBufferSize`." +#endif // D_WARN_BUFFERFULL + +#endif // LOCALE_ES_ES_H_ diff --git a/lib/IRremoteESP8266-2.7.0/src/locale/fr-FR.h b/lib/IRremoteESP8266-2.7.0/src/locale/fr-FR.h new file mode 100644 index 000000000..5ab10cb62 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/src/locale/fr-FR.h @@ -0,0 +1,115 @@ +// Copyright 2019 - Mathieu D(@Knackie) +// Locale/language file for French / Quebec. +// This file will override the default values located in `defaults.h`. +#ifndef LOCALE_FR_FR_H_ +#define LOCALE_FR_FR_H_ + +#define D_STR_UNKNOWN "INCONNU" +#define D_STR_PROTOCOL "Protocole" +#define D_STR_TOGGLE "Bascule" +#define D_STR_SLEEP "Pause" +#define D_STR_LIGHT "Lumière" +#define D_STR_POWERFUL "Puissance" +#define D_STR_QUIET "Silence" +#define D_STR_ECONO "Economie" +#define D_STR_BEEP "Bip" +#define D_STR_MOULD "Moule" +#define D_STR_CLEAN "Nettoyer" +#define D_STR_PURIFY "Purifier" +#define D_STR_ON "On" +#define D_STR_OFF "Off" +#define D_STR_ONTIMER D_STR_ON " " D_STR_TIMER +#define D_STR_OFFTIMER D_STR_OFF " " D_STR_TIMER +#define D_STR_CLOCK "Heure" +#define D_STR_COMMAND "Commandement" +#define D_STR_HEALTH "Santé" +#define D_STR_TEMP "Temporaire" +#define D_STR_HUMID "Humidité" +#define D_STR_SAVE "Sauvegarder" +#define D_STR_EYE "Oeil" +#define D_STR_FOLLOW "Suivre" +#define D_STR_FRESH "Frais" +#define D_STR_HOLD "Maintenir" +#define D_STR_BUTTON "Bouton" +#define D_STR_NIGHT "Nuit" +#define D_STR_SILENT "Silence" +#define D_STR_UP "En haut" +#define D_STR_TEMPUP D_STR_TEMP " " D_STR_UP +#define D_STR_DOWN "En bas" +#define D_STR_TEMPDOWN D_STR_TEMP " " D_STR_DOWN +#define D_STR_CHANGE "Changement" +#define D_STR_SET "Mettre" +#define D_STR_CANCEL "Annuler" +#define D_STR_COMFORT "Confort" +#define D_STR_WEEKLY "Chaque semaine" +#define D_STR_WEEKLYTIMER D_STR_WEEKLY " " D_STR_TIMER +#define D_STR_FAST "Rapide" +#define D_STR_SLOW "Lent" +#define D_STR_AIRFLOW "Ebauche" +#define D_STR_STEP "Etape" +#define D_STR_OUTSIDE "Plein air" +#define D_STR_LOUD "Fort" +#define D_STR_UPPER "Au dessus" +#define D_STR_LOWER "En dessous" +#define D_STR_BREEZE "Brise" +#define D_STR_CIRCULATE "Faire circuler" +#define D_STR_CEILING "Plafond" +#define D_STR_WALL "Mur" +#define D_STR_ROOM "Pièce" +#define D_STR_6THSENSE "6ter Sens" +#define D_STR_FIXED "Fixer" + +#define D_STR_AUTOMATIC "Automatique" +#define D_STR_MANUAL "Manuel" +#define D_STR_COOL "Frais" +#define D_STR_HEAT "Chaleur" +#define D_STR_FAN "Ventillateur" +#define D_STR_FANONLY "Seul_fan" +#define D_STR_DRY "Sec" + +#define D_STR_MEDIUM "Moyen" + +#define D_STR_HIGHEST "Le plus haut" +#define D_STR_HIGH "Haut" +#define D_STR_HI "H" +#define D_STR_MID "M" +#define D_STR_MIDDLE "Moitié" +#define D_STR_LOW "Bas" +#define D_STR_LO "B" +#define D_STR_LOWEST "Le plus bas" +#define D_STR_RIGHT "Droite" +#define D_STR_MAX "Max" +#define D_STR_MAXRIGHT D_STR_MAX " " D_STR_RIGHT +#define D_STR_RIGHTMAX_NOSPACE D_STR_RIGHT D_STR_MAX +#define D_STR_LEFT "Gauche" +#define D_STR_MAXLEFT D_STR_MAX " " D_STR_LEFT +#define D_STR_LEFTMAX_NOSPACE D_STR_LEFT D_STR_MAX +#define D_STR_WIDE "Large" +#define D_STR_TOP "Au-dessus" +#define D_STR_BOTTOM "En-dessous" + +#define D_STR_DAY "Jour" +#define D_STR_HOUR "Heure" +#define D_STR_SECOND "Seconde" +#define D_STR_NOW "Maintenant" +#define D_STR_THREELETTERDAYS "LunMarMerJeuVenSamDim" + +#define D_STR_YES "Oui" +#define D_STR_NO "Non" +#define D_STR_TRUE "Vrai" +#define D_STR_FALSE "Faux" + +#define D_STR_REPEAT "Répetition" + +// IRrecvDumpV2 +#define D_STR_TIMESTAMP "Horodatage" +#define D_STR_LIBRARY "Bibliothèque" +#define D_STR_MESGDESC "Rèférence" +#define D_STR_IRRECVDUMP_STARTUP \ + "IRrecvDumpV2 fonctionne et attend l’entrée IR sur la broche %d" +#define D_WARN_BUFFERFULL \ + "ATTENTION: IR Code est trop gros pour le buffer (>= %d). " \ + "Le résultat ne doit pas être approuvé avant que cela soit résolu. " \ + "Modifier et agrandir `kCaptureBufferSize`." + +#endif // LOCALE_FR_FR_H_ diff --git a/lib/IRremoteESP8266-2.6.5/test/IRac_test.cpp b/lib/IRremoteESP8266-2.7.0/test/IRac_test.cpp old mode 100755 new mode 100644 similarity index 83% rename from lib/IRremoteESP8266-2.6.5/test/IRac_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/IRac_test.cpp index 3afc89c6e..dfe808db4 --- a/lib/IRremoteESP8266-2.6.5/test/IRac_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/IRac_test.cpp @@ -39,7 +39,7 @@ TEST(TestIRac, Amcor) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 5 (AUTO), Fan: 3 (High), Temp: 19C, Max: Off"; + "Power: On, Mode: 5 (Auto), Fan: 3 (High), Temp: 19C, Max: Off"; ac.begin(); irac.amcor(&ac, @@ -81,8 +81,8 @@ TEST(TestIRac, Coolix) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 3 (HEAT), Fan: 1 (MAX), Temp: 21C, Zone Follow: Off, " - "Sensor Temp: Ignored"; + "Power: On, Mode: 3 (Heat), Fan: 1 (Max), Temp: 21C, Zone Follow: Off, " + "Sensor Temp: Off"; ac.begin(); irac.coolix(&ac, @@ -140,11 +140,11 @@ TEST(TestIRac, Daikin) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 3 (COOL), Temp: 19C, Fan: 5 (High), Powerful: Off, " - "Quiet: Off, Sensor: Off, Mold: On, Comfort: Off, " - "Swing (Horizontal): Off, Swing (Vertical): Off, " - "Current Time: 00:00, Current Day: (UNKNOWN), On Time: Off, " - "Off Time: Off, Weekly Timer: On"; + "Power: On, Mode: 3 (Cool), Temp: 19C, Fan: 5 (High), Powerful: Off, " + "Quiet: Off, Sensor: Off, Mould: On, Comfort: Off, " + "Swing(H): Off, Swing(V): Off, " + "Clock: 00:00, Day: 0 (UNKNOWN), On Timer: Off, " + "Off Timer: Off, Weekly Timer: On"; ac.begin(); irac.daikin(&ac, @@ -171,10 +171,10 @@ TEST(TestIRac, Daikin128) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power Toggle: On, Mode: 8 (HEAT), Temp: 27C, Fan: 9 (Quiet), " - "Powerful: Off, Quiet: On, Swing (V): On, Sleep: On, " - "Econo: Off, Clock: 21:57, On Timer: Off, On Time: 00:00, " - "Off Timer: Off, Off Time: 00:00, Light Toggle: 8 (Wall)"; + "Power Toggle: On, Mode: 8 (Heat), Temp: 27C, Fan: 9 (Quiet), " + "Powerful: Off, Quiet: On, Swing(V): On, Sleep: On, " + "Econo: Off, Clock: 21:57, On Timer: Off, On Timer: 00:00, " + "Off Timer: Off, Off Timer: 00:00, Light Toggle: 8 (Wall)"; ac.begin(); irac.daikin128(&ac, @@ -197,13 +197,39 @@ TEST(TestIRac, Daikin128) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); } +TEST(TestIRac, Daikin152) { + IRDaikin152 ac(0); + IRac irac(0); + IRrecv capture(0); + char expected[] = + "Power: On, Mode: 3 (Cool), Temp: 27C, Fan: 3 (Medium), Swing(V): On, " + "Powerful: Off, Quiet: Off, Econo: On, Sensor: Off, Comfort: Off"; + + ac.begin(); + irac.daikin152(&ac, + true, // Power + stdAc::opmode_t::kCool, // Mode + 27, // Celsius + stdAc::fanspeed_t::kMedium, // Fan speed + stdAc::swingv_t::kAuto, // Veritcal swing + false, // Quiet + false, // Turbo + true); // Econo + ASSERT_EQ(expected, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(DAIKIN152, ac._irsend.capture.decode_type); + ASSERT_EQ(kDaikin152Bits, ac._irsend.capture.bits); + ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); +} + TEST(TestIRac, Daikin160) { IRDaikin160 ac(0); IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 2 (DRY), Temp: 23C, Fan: 1 (Low), " - "Vent Position (V): 3 (Middle)"; + "Power: On, Mode: 2 (Dry), Temp: 23C, Fan: 1 (Low), " + "Swing(V): 3 (Middle)"; ac.begin(); irac.daikin160(&ac, @@ -225,7 +251,7 @@ TEST(TestIRac, Daikin176) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 7 (COOL), Temp: 26C, Fan: 1 (Low), Swing (H): 5 (Auto)"; + "Power: On, Mode: 7 (Cool), Temp: 26C, Fan: 1 (Low), Swing(H): 5 (Auto)"; ac.begin(); irac.daikin176(&ac, @@ -247,11 +273,11 @@ TEST(TestIRac, Daikin2) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 3 (COOL), Temp: 19C, Fan: 1 (Low), " - "Swing (V): 14 (Auto), Swing (H): 0, Clock: 00:00, On Time: Off, " - "Off Time: Off, Sleep Time: Off, Beep: 1 (Quiet), Light: 1 (Bright), " - "Mold: On, Clean: Off, Fresh Air: Off, Eye: Off, Eye Auto: Off, " - "Quiet: Off, Powerful: Off, Purify: On, Econo: Off"; + "Power: On, Mode: 3 (Cool), Temp: 19C, Fan: 1 (Low), " + "Swing(V): 14 (Auto), Swing(H): 170 (UNKNOWN), Clock: 00:00, " + "On Timer: Off, Off Timer: Off, Sleep Timer: Off, Beep: 2 (Loud), " + "Light: 1 (High), Mould: On, Clean: On, Fresh: Off, Eye: Off, " + "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off"; ac.begin(); irac.daikin2(&ac, @@ -260,13 +286,14 @@ TEST(TestIRac, Daikin2) { 19, // Celsius stdAc::fanspeed_t::kLow, // Fan speed stdAc::swingv_t::kOff, // Veritcal swing - stdAc::swingh_t::kOff, // Horizontal swing + stdAc::swingh_t::kMiddle, // Horizontal swing false, // Quiet false, // Turbo true, // Light false, // Econo - true, // Filter + true, // Filter (aka Purify) true, // Clean (aka Mold) + true, // Beep (Loud) -1, // Sleep time -1); // Current time ASSERT_EQ(expected, ac.toString()); @@ -282,8 +309,8 @@ TEST(TestIRac, Daikin216) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 4 (HEAT), Temp: 31C, Fan: 11 (Quiet), " - "Swing (Horizontal): On, Swing (Vertical): On, Quiet: On, Powerful: Off"; + "Power: On, Mode: 4 (Heat), Temp: 31C, Fan: 11 (Quiet), " + "Swing(H): On, Swing(V): On, Quiet: On, Powerful: Off"; ac.begin(); irac.daikin216(&ac, @@ -308,7 +335,7 @@ TEST(TestIRac, Electra) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 6 (FAN), Temp: 26C, Fan: 1 (High), " + "Power: On, Mode: 6 (Fan), Temp: 26C, Fan: 1 (High), " "Swing(V): On, Swing(H): On"; ac.begin(); @@ -333,12 +360,14 @@ TEST(TestIRac, Fujitsu) { IRac irac(0); IRrecv capture(0); std::string ardb1_expected = - "Model: 2 (ARDB1), Power: On, Mode: 1 (COOL), Temp: 19C, " + "Model: 2 (ARDB1), Power: On, Mode: 1 (Cool), Temp: 19C, " "Fan: 2 (Medium), Command: N/A"; std::string arrah2e_expected = - "Model: 1 (ARRAH2E), Power: On, Mode: 1 (COOL), Temp: 19C, " - "Fan: 2 (Medium), Swing: Off, Command: N/A"; - + "Model: 1 (ARRAH2E), Power: On, Mode: 1 (Cool), Temp: 19C, " + "Fan: 2 (Medium), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A"; + std::string arry4_expected = + "Model: 5 (ARRY4), Power: On, Mode: 1 (Cool), Temp: 19C, " + "Fan: 2 (Medium), Clean: On, Filter: On, Swing: 0 (Off), Command: N/A"; ac.begin(); irac.fujitsu(&ac, ARDB1, // Model @@ -350,7 +379,9 @@ TEST(TestIRac, Fujitsu) { stdAc::swingh_t::kOff, // Horizontal swing false, // Quiet false, // Turbo (Powerful) - false); // Econo + false, // Econo + true, // Filter + true); // Clean ASSERT_EQ(ardb1_expected, ac.toString()); ac._irsend.makeDecodeResult(); EXPECT_TRUE(capture.decode(&ac._irsend.capture)); @@ -369,13 +400,35 @@ TEST(TestIRac, Fujitsu) { stdAc::swingh_t::kOff, // Horizontal swing false, // Quiet false, // Turbo (Powerful) - false); // Econo + false, // Econo + true, // Filter + true); // Clean ASSERT_EQ(arrah2e_expected, ac.toString()); ac._irsend.makeDecodeResult(); EXPECT_TRUE(capture.decode(&ac._irsend.capture)); ASSERT_EQ(FUJITSU_AC, ac._irsend.capture.decode_type); ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits); ASSERT_EQ(arrah2e_expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); + ac._irsend.reset(); + irac.fujitsu(&ac, + fujitsu_ac_remote_model_t::ARRY4, // Model + true, // Power + stdAc::opmode_t::kCool, // Mode + 19, // Celsius + stdAc::fanspeed_t::kMedium, // Fan speed + stdAc::swingv_t::kOff, // Veritcal swing + stdAc::swingh_t::kOff, // Horizontal swing + false, // Quiet + false, // Turbo (Powerful) + false, // Econo + true, // Filter + true); // Clean + ASSERT_EQ(arry4_expected, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(FUJITSU_AC, ac._irsend.capture.decode_type); + ASSERT_EQ(kFujitsuAcBits, ac._irsend.capture.bits); + ASSERT_EQ(arry4_expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); } TEST(TestIRac, Goodweather) { @@ -383,7 +436,7 @@ TEST(TestIRac, Goodweather) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 1 (COOL), Temp: 19C, Fan: 2 (Medium), Turbo: Toggle, " + "Power: On, Mode: 1 (Cool), Temp: 19C, Fan: 2 (Medium), Turbo: Toggle, " "Light: Toggle, Sleep: Toggle, Swing: 1 (Slow), Command: 0 (Power)"; ac.begin(); @@ -409,10 +462,10 @@ TEST(TestIRac, Gree) { IRac irac(0); IRrecv capture(0); char expected[] = - "Model: 1 (YAW1F), Power: On, Mode: 1 (COOL), Temp: 22C, " + "Model: 1 (YAW1F), Power: On, Mode: 1 (Cool), Temp: 22C, " "Fan: 2 (Medium), Turbo: Off, IFeel: Off, WiFi: Off, XFan: On, " - "Light: On, Sleep: On, Swing Vertical Mode: Manual, " - "Swing Vertical Pos: 3, Timer: Off"; + "Light: On, Sleep: On, Swing(V) Mode: Manual, " + "Swing(V): 3 (UNKNOWN), Timer: Off"; ac.begin(); irac.gree(&ac, @@ -439,8 +492,8 @@ TEST(TestIRac, Haier) { IRac irac(0); IRrecv capture(0); char expected[] = - "Command: 1 (On), Mode: 1 (COOL), Temp: 24C, Fan: 2 (Medium), " - "Swing: 1 (Up), Sleep: On, Health: On, Current Time: 13:45, " + "Command: 1 (On), Mode: 1 (Cool), Temp: 24C, Fan: 2 (Medium), " + "Swing: 1 (Up), Sleep: On, Health: On, Clock: 13:45, " "On Timer: Off, Off Timer: Off"; ac.begin(); @@ -467,8 +520,9 @@ TEST(TestIRac, HaierYrwo2) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Button: 5 (Power), Mode: 2 (COOL), Temp: 23C, " - "Fan: 4 (Medium), Turbo: 1 (High), Swing: 1 (Top), Sleep: On, Health: On"; + "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 23C, " + "Fan: 2 (Medium), Turbo: 1 (High), Swing: 1 (Highest), Sleep: On, " + "Health: On"; ac.begin(); irac.haierYrwo2(&ac, @@ -493,8 +547,8 @@ TEST(TestIRac, Hitachi) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 2 (AUTO), Temp: 22C, Fan: 3 (Medium), " - "Swing (Vertical): Off, Swing (Horizontal): On"; + "Power: On, Mode: 2 (Auto), Temp: 22C, Fan: 3 (Medium), " + "Swing(V): Off, Swing(H): On"; ac.begin(); irac.hitachi(&ac, @@ -513,14 +567,36 @@ TEST(TestIRac, Hitachi) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); } +TEST(TestIRac, Hitachi424) { + IRHitachiAc424 ac(0); + IRac irac(0); + IRrecv capture(0); + char expected[] = + "Power: On, Mode: 6 (Heat), Temp: 25C, Fan: 6 (Max)"; + + ac.begin(); + irac.hitachi424(&ac, + true, // Power + stdAc::opmode_t::kHeat, // Mode + 25, // Celsius + stdAc::fanspeed_t::kMax); // Fan speed + + ASSERT_EQ(expected, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(HITACHI_AC424, ac._irsend.capture.decode_type); + ASSERT_EQ(kHitachiAc424Bits, ac._irsend.capture.bits); + ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); +} + TEST(TestIRac, Kelvinator) { IRKelvinatorAC ac(0); IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 1 (COOL), Temp: 19C, Fan: 3 (Medium), Turbo: Off, " - "Quiet: Off, XFan: On, IonFilter: On, Light: On, " - "Swing (Horizontal): Off, Swing (Vertical): Off"; + "Power: On, Mode: 1 (Cool), Temp: 19C, Fan: 3 (Medium), Turbo: Off, " + "Quiet: Off, XFan: On, Ion: On, Light: On, " + "Swing(H): Off, Swing(V): Off"; ac.begin(); irac.kelvinator(&ac, @@ -549,7 +625,7 @@ TEST(TestIRac, Midea) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 1 (DRY), Celsius: On, Temp: 27C/80F, Fan: 2 (Medium), " + "Power: On, Mode: 1 (Dry), Celsius: On, Temp: 27C/80F, Fan: 2 (Medium), " "Sleep: On, Swing(V) Toggle: Off"; ac.begin(); @@ -559,7 +635,7 @@ TEST(TestIRac, Midea) { true, // Celsius 27, // Degrees stdAc::fanspeed_t::kMedium, // Fan speed - stdAc::swingv_t::kOff, // Swing (V) + stdAc::swingv_t::kOff, // Swing(V) 8 * 60 + 0); // Sleep time ASSERT_EQ(expected, ac.toString()); @@ -575,8 +651,9 @@ TEST(TestIRac, Mitsubishi) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 24 (COOL), Temp: 20C, Fan: 2 (Medium), Vane: AUTO, " - "Wide Vane: 3, Time: 14:30, On timer: 00:00, Off timer: 00:00, Timer: -"; + "Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 2 (Medium), " + "Swing(V): 0 (Auto), Swing(H): 3 (UNKNOWN), " + "Clock: 14:30, On Timer: 00:00, Off Timer: 00:00, Timer: -"; ac.begin(); irac.mitsubishi(&ac, @@ -596,13 +673,37 @@ TEST(TestIRac, Mitsubishi) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); } +TEST(TestIRac, Mitsubishi136) { + IRMitsubishi136 ac(0); + IRac irac(0); + IRrecv capture(0); + char expected[] = + "Power: On, Mode: 5 (Dry), Temp: 22C, Fan: 3 (High), " + "Swing(V): 3 (Highest), Quiet: Off"; + + ac.begin(); + irac.mitsubishi136(&ac, + true, // Power + stdAc::opmode_t::kDry, // Mode + 22, // Celsius + stdAc::fanspeed_t::kMax, // Fan speed + stdAc::swingv_t::kHighest, // Veritcal swing + false); // Quiet + ASSERT_EQ(expected, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(MITSUBISHI136, ac._irsend.capture.decode_type); + ASSERT_EQ(kMitsubishi136Bits, ac._irsend.capture.bits); + ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); +} + TEST(TestIRac, MitsubishiHeavy88) { IRMitsubishiHeavy88Ac ac(0); IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 3 (Medium), " - "Swing (V): 16 (Auto), Swing (H): 0 (Off), Turbo: Off, Econo: Off, " + "Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 3 (Med), " + "Swing(V): 4 (Auto), Swing(H): 0 (Off), Turbo: Off, Econo: Off, " "3D: Off, Clean: On"; ac.begin(); @@ -629,8 +730,8 @@ TEST(TestIRac, MitsubishiHeavy152) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 1 (COOL), Temp: 20C, Fan: 6 (Econo), " - "Swing (V): 6 (Off), Swing (H): 0 (Auto), Silent: On, Turbo: Off, " + "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 6 (Econo), " + "Swing(V): 6 (Off), Swing(H): 0 (Auto), Silent: On, Turbo: Off, " "Econo: On, Night: On, Filter: On, 3D: Off, Clean: Off"; ac.begin(); @@ -660,7 +761,7 @@ TEST(TestIRac, Neoclima) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 1 (COOL), Temp: 20C, Fan: 3 (Low), " + "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 3 (Low), " "Swing(V): Off, Swing(H): On, Sleep: On, Turbo: Off, Hold: Off, Ion: On, " "Eye: Off, Light: On, Follow: Off, 8C Heat: Off, Fresh: Off, " "Button: 0 (Power)"; @@ -690,8 +791,8 @@ TEST(TestIRac, Panasonic) { IRac irac(0); IRrecv capture(0); char expected_nke[] = - "Model: 2 (NKE), Power: On, Mode: 4 (HEAT), Temp: 28C, Fan: 2 (Medium), " - "Swing (Vertical): 15 (AUTO), Swing (Horizontal): 6 (Middle), Quiet: On, " + "Model: 2 (NKE), Power: On, Mode: 4 (Heat), Temp: 28C, Fan: 2 (Medium), " + "Swing(V): 15 (Auto), Swing(H): 6 (Middle), Quiet: On, " "Powerful: Off, Clock: 19:17, On Timer: Off, Off Timer: Off"; ac.begin(); @@ -714,8 +815,8 @@ TEST(TestIRac, Panasonic) { ASSERT_EQ(expected_nke, IRAcUtils::resultAcToString(&ac._irsend.capture)); char expected_dke[] = - "Model: 3 (DKE), Power: On, Mode: 3 (COOL), Temp: 18C, Fan: 4 (High), " - "Swing (Vertical): 1 (Full Up), Swing (Horizontal): 6 (Middle), " + "Model: 3 (DKE), Power: On, Mode: 3 (Cool), Temp: 18C, Fan: 4 (High), " + "Swing(V): 2 (High), Swing(H): 6 (Middle), " "Quiet: Off, Powerful: On, Clock: 19:17, On Timer: Off, Off Timer: Off"; ac._irsend.reset(); irac.panasonic(&ac, @@ -742,7 +843,7 @@ TEST(TestIRac, Samsung) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 0 (AUTO), Temp: 28C, Fan: 6 (Auto), Swing: On, " + "Power: On, Mode: 0 (Auto), Temp: 28C, Fan: 6 (Auto), Swing: On, " "Beep: On, Clean: On, Quiet: On, Powerful: Off"; ac.begin(); @@ -756,6 +857,7 @@ TEST(TestIRac, Samsung) { false, // Turbo true, // Clean true, // Beep + true, // Previous power state false); // with dopower Off ASSERT_EQ(expected, ac.toString()); ac._irsend.makeDecodeResult(); @@ -775,6 +877,7 @@ TEST(TestIRac, Samsung) { false, // Turbo true, // Clean true, // Beep + true, // Previous power state true); // with dopower On ASSERT_EQ(expected, ac.toString()); // Class should be in the desired mode. ac._irsend.makeDecodeResult(); @@ -784,7 +887,7 @@ TEST(TestIRac, Samsung) { // However, we expect a plain "on" state as it should be sent before the // desired state. char expected_on[] = - "Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 0 (Auto), Swing: Off, " + "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off"; ASSERT_EQ(expected_on, IRAcUtils::resultAcToString(&ac._irsend.capture)); } @@ -794,7 +897,7 @@ TEST(TestIRac, Sharp) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 2 (COOL), Temp: 28C, Fan: 3 (Medium)"; + "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium)"; ac.begin(); irac.sharp(&ac, @@ -815,8 +918,8 @@ TEST(TestIRac, Tcl112) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 3 (Medium), Econo: On, " - "Health: On, Light: On, Turbo: Off, Swing (H): On, Swing (V): Off"; + "Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 3 (Medium), Econo: On, " + "Health: On, Light: On, Turbo: Off, Swing(H): On, Swing(V): Off"; ac.begin(); irac.tcl112(&ac, @@ -843,8 +946,8 @@ TEST(TestIRac, Teco) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 0 (AUTO), Temp: 21C, Fan: 2 (Medium), Sleep: On, " - "Swing: On, Light: On, Humid: Off, Save: Off"; + "Power: On, Mode: 0 (Auto), Temp: 21C, Fan: 2 (Medium), Sleep: On, " + "Swing: On, Light: On, Humid: Off, Save: Off, Timer: Off"; ac.begin(); irac.teco(&ac, @@ -867,7 +970,7 @@ TEST(TestIRac, Toshiba) { IRToshibaAC ac(0); IRac irac(0); IRrecv capture(0); - char expected[] = "Power: On, Mode: 2 (DRY), Temp: 29C, Fan: 2 (UNKNOWN)"; + char expected[] = "Power: On, Mode: 2 (Dry), Temp: 29C, Fan: 2 (UNKNOWN)"; ac.begin(); irac.toshiba(&ac, @@ -888,7 +991,7 @@ TEST(TestIRac, Trotec) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 1 (COOL), Temp: 18C, Fan: 3 (High), Sleep: On"; + "Power: On, Mode: 1 (Cool), Temp: 18C, Fan: 3 (High), Sleep: On"; ac.begin(); irac.trotec(&ac, @@ -915,7 +1018,7 @@ TEST(TestIRac, Vestel) { IRac irac(0); IRrecv capture(0); char expected[] = - "Power: On, Mode: 0 (AUTO), Temp: 22C, Fan: 5 (Low), Sleep: On, " + "Power: On, Mode: 0 (Auto), Temp: 22C, Fan: 5 (Low), Sleep: On, " "Turbo: Off, Ion: On, Swing: On"; ac.begin(); @@ -938,7 +1041,7 @@ TEST(TestIRac, Vestel) { ac._irsend.reset(); char expected_clocks[] = - "Time: 13:45, Timer: Off, On Timer: Off, Off Timer: Off"; + "Clock: 13:45, Timer: Off, On Timer: Off, Off Timer: Off"; ac.begin(); irac.vestel(&ac, @@ -1003,9 +1106,9 @@ TEST(TestIRac, Whirlpool) { IRac irac(0); IRrecv capture(0); char expected[] = - "Model: 1 (DG11J13A), Power toggle: On, Mode: 1 (AUTO), Temp: 21C, " + "Model: 1 (DG11J13A), Power Toggle: On, Mode: 1 (Auto), Temp: 21C, " "Fan: 3 (Low), Swing: On, Light: On, Clock: 23:58, On Timer: Off, " - "Off Timer: Off, Sleep: On, Super: Off, Command: 1 (POWER)"; + "Off Timer: Off, Sleep: On, Super: Off, Command: 1 (Power)"; ac.begin(); irac.whirlpool(&ac, @@ -1215,36 +1318,36 @@ TEST(TestIRac, strToModel) { } TEST(TestIRac, boolToString) { - EXPECT_EQ("on", IRac::boolToString(true)); - EXPECT_EQ("off", IRac::boolToString(false)); + EXPECT_EQ("On", IRac::boolToString(true)); + EXPECT_EQ("Off", IRac::boolToString(false)); } TEST(TestIRac, opmodeToString) { - EXPECT_EQ("off", IRac::opmodeToString(stdAc::opmode_t::kOff)); - 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)); + EXPECT_EQ("Off", IRac::opmodeToString(stdAc::opmode_t::kOff)); + 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)); } TEST(TestIRac, fanspeedToString) { - EXPECT_EQ("low", IRac::fanspeedToString(stdAc::fanspeed_t::kLow)); - EXPECT_EQ("auto", IRac::fanspeedToString(stdAc::fanspeed_t::kAuto)); - EXPECT_EQ("unknown", IRac::fanspeedToString((stdAc::fanspeed_t)500)); + EXPECT_EQ("Low", IRac::fanspeedToString(stdAc::fanspeed_t::kLow)); + EXPECT_EQ("Auto", IRac::fanspeedToString(stdAc::fanspeed_t::kAuto)); + EXPECT_EQ("UNKNOWN", IRac::fanspeedToString((stdAc::fanspeed_t)500)); } TEST(TestIRac, swingvToString) { - EXPECT_EQ("off", IRac::swingvToString(stdAc::swingv_t::kOff)); - EXPECT_EQ("low", IRac::swingvToString(stdAc::swingv_t::kLow)); - EXPECT_EQ("auto", IRac::swingvToString(stdAc::swingv_t::kAuto)); - EXPECT_EQ("unknown", IRac::swingvToString((stdAc::swingv_t)500)); + EXPECT_EQ("Off", IRac::swingvToString(stdAc::swingv_t::kOff)); + EXPECT_EQ("Low", IRac::swingvToString(stdAc::swingv_t::kLow)); + EXPECT_EQ("Auto", IRac::swingvToString(stdAc::swingv_t::kAuto)); + EXPECT_EQ("UNKNOWN", IRac::swingvToString((stdAc::swingv_t)500)); } TEST(TestIRac, swinghToString) { - EXPECT_EQ("off", IRac::swinghToString(stdAc::swingh_t::kOff)); - EXPECT_EQ("left", IRac::swinghToString(stdAc::swingh_t::kLeft)); - EXPECT_EQ("auto", IRac::swinghToString(stdAc::swingh_t::kAuto)); - EXPECT_EQ("wide", IRac::swinghToString(stdAc::swingh_t::kWide)); - EXPECT_EQ("unknown", IRac::swinghToString((stdAc::swingh_t)500)); + EXPECT_EQ("Off", IRac::swinghToString(stdAc::swingh_t::kOff)); + EXPECT_EQ("Left", IRac::swinghToString(stdAc::swingh_t::kLeft)); + EXPECT_EQ("Auto", IRac::swinghToString(stdAc::swingh_t::kAuto)); + EXPECT_EQ("Wide", IRac::swinghToString(stdAc::swingh_t::kWide)); + EXPECT_EQ("UNKNOWN", IRac::swinghToString((stdAc::swingh_t)500)); } // Check that we keep the previous state info if the message is a special @@ -1324,7 +1427,7 @@ TEST(TestIRac, Issue821) { EXPECT_TRUE(capture.decode(&ac._irsend.capture)); ASSERT_EQ(COOLIX, ac._irsend.capture.decode_type); ASSERT_EQ(kCoolixBits, ac._irsend.capture.bits); - ASSERT_EQ("Power: On, Led: Toggle", + ASSERT_EQ("Power: On, Light: Toggle", IRAcUtils::resultAcToString(&ac._irsend.capture)); EXPECT_EQ( "f38000d50m" diff --git a/lib/IRremoteESP8266-2.6.5/test/IRrecv_test.cpp b/lib/IRremoteESP8266-2.7.0/test/IRrecv_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/IRrecv_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/IRrecv_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/IRrecv_test.h b/lib/IRremoteESP8266-2.7.0/test/IRrecv_test.h old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/IRrecv_test.h rename to lib/IRremoteESP8266-2.7.0/test/IRrecv_test.h diff --git a/lib/IRremoteESP8266-2.6.5/test/IRsend_test.cpp b/lib/IRremoteESP8266-2.7.0/test/IRsend_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/IRsend_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/IRsend_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/IRsend_test.h b/lib/IRremoteESP8266-2.7.0/test/IRsend_test.h old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/IRsend_test.h rename to lib/IRremoteESP8266-2.7.0/test/IRsend_test.h diff --git a/lib/IRremoteESP8266-2.6.5/test/IRutils_test.cpp b/lib/IRremoteESP8266-2.7.0/test/IRutils_test.cpp old mode 100755 new mode 100644 similarity index 77% rename from lib/IRremoteESP8266-2.6.5/test/IRutils_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/IRutils_test.cpp index 366deba32..b079893cd --- a/lib/IRremoteESP8266-2.6.5/test/IRutils_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/IRutils_test.cpp @@ -308,8 +308,8 @@ TEST(TestResultToHumanReadableBasic, SimpleCodes) { ASSERT_EQ(NEC, irsend.capture.decode_type); ASSERT_EQ(kNECBits, irsend.capture.bits); EXPECT_EQ( - "Encoding : NEC\n" - "Code : 8F704FB (32 bits)\n", + "Protocol : NEC\n" + "Code : 0x8F704FB (32 Bits)\n", resultToHumanReadableBasic(&irsend.capture)); } @@ -328,8 +328,8 @@ TEST(TestResultToHumanReadableBasic, ComplexCodes) { ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); ASSERT_EQ(kToshibaACBits, irsend.capture.bits); EXPECT_EQ( - "Encoding : TOSHIBA_AC\n" - "Code : F20D03FC0100000001 (72 bits)\n", + "Protocol : TOSHIBA_AC\n" + "Code : 0xF20D03FC0100000001 (72 Bits)\n", resultToHumanReadableBasic(&irsend.capture)); } @@ -540,3 +540,182 @@ TEST(TestUtils, BCD) { EXPECT_EQ(255, irutils::bcdToUint8(0x9A)); EXPECT_EQ(255, irutils::uint8ToBcd(100)); } + +TEST(TestUtils, getBit) { + // uint8_t method. + EXPECT_FALSE(irutils::getBit((uint8_t)0, 0)); + EXPECT_TRUE(irutils::getBit((uint8_t)1, 0)); + EXPECT_FALSE(irutils::getBit((uint8_t)0b01, 1)); + EXPECT_TRUE(irutils::getBit((uint8_t)0b10, 1)); + EXPECT_FALSE(irutils::getBit((uint8_t)0b01111111, 7)); + EXPECT_TRUE(irutils::getBit((uint8_t)0b10000000, 7)); + // 8-bit macro method + EXPECT_FALSE(GETBIT8((uint8_t)0, 0)); + EXPECT_TRUE(GETBIT8((uint8_t)1, 0)); + EXPECT_FALSE(GETBIT8((uint8_t)0b01, 1)); + EXPECT_TRUE(GETBIT8((uint8_t)0b10, 1)); + EXPECT_FALSE(GETBIT8((uint8_t)0b01111111, 7)); + EXPECT_TRUE(GETBIT8((uint8_t)0b10000000, 7)); + // uint64_t method. + EXPECT_FALSE(irutils::getBit((uint64_t)0, 0)); + EXPECT_TRUE(irutils::getBit((uint64_t)1, 0)); + EXPECT_FALSE(irutils::getBit((uint64_t)0b01, 1)); + EXPECT_TRUE(irutils::getBit((uint64_t)0b10, 1)); + EXPECT_FALSE(irutils::getBit((uint64_t)0b01111111, 7)); + EXPECT_TRUE(irutils::getBit((uint64_t)0b10000000, 7)); +} + +TEST(TestUtils, setBit) { + // uint8_t method. + EXPECT_EQ(0, irutils::setBit((uint8_t)0, 0, false)); + EXPECT_EQ(0, irutils::setBit((uint8_t)1, 0, false)); + EXPECT_EQ(1, irutils::setBit((uint8_t)0, 0, true)); + EXPECT_EQ(1, irutils::setBit((uint8_t)1, 0, true)); + EXPECT_EQ(0b101, irutils::setBit((uint8_t)0b101, 1, false)); + EXPECT_EQ(0b100, irutils::setBit((uint8_t)0b110, 1, false)); + EXPECT_EQ(0b111, irutils::setBit((uint8_t)0b101, 1, true)); + EXPECT_EQ(0b110, irutils::setBit((uint8_t)0b110, 1, true)); + EXPECT_EQ(0b11111111, irutils::setBit((uint8_t)0b01111111, 7, true)); + EXPECT_EQ(0, irutils::setBit((uint8_t)0b10000000, 7, false)); + // uint64_t method. + EXPECT_EQ(0, irutils::setBit((uint64_t)0, 0, false)); + EXPECT_EQ(0, irutils::setBit((uint64_t)1, 0, false)); + EXPECT_EQ(1, irutils::setBit((uint64_t)0, 0, true)); + EXPECT_EQ(1, irutils::setBit((uint64_t)1, 0, true)); + EXPECT_EQ(0b101, irutils::setBit((uint64_t)0b101, 1, false)); + EXPECT_EQ(0b100, irutils::setBit((uint64_t)0b110, 1, false)); + EXPECT_EQ(0b111, irutils::setBit((uint64_t)0b101, 1, true)); + EXPECT_EQ(0b110, irutils::setBit((uint64_t)0b110, 1, true)); + EXPECT_EQ(0b11111111, irutils::setBit((uint64_t)0b01111111, 7, true)); + EXPECT_EQ(0, irutils::setBit((uint64_t)0b10000000, 7, false)); + // uint8_t Pointer method. + uint8_t data = 0; + irutils::setBit(&data, 0, false); + EXPECT_EQ(0, data); + data = 1; + irutils::setBit(&data, 0, false); + ASSERT_EQ(0, data); + irutils::setBit(&data, 0, true); + ASSERT_EQ(1, data); + irutils::setBit(&data, 0, true); + ASSERT_EQ(1, data); + // uint64_t Pointer method. + uint64_t data64 = 0; + irutils::setBit(&data64, 38, true); + ASSERT_EQ(1ULL << 38, data64); + irutils::setBit(&data64, 38, true); + ASSERT_EQ(1ULL << 38, data64); +} + +TEST(TestUtils, setBits8Bit) { + uint8_t data = 0b00000001; + // Trivial/corner cases. + irutils::setBits(&data, 0, 0, 0); + EXPECT_EQ(1, data); + irutils::setBits(&data, 0, 0, 17); + EXPECT_EQ(1, data); + irutils::setBits(&data, 22, 0, 22); + EXPECT_EQ(1, data); + irutils::setBits(&data, 8, 23, 3); + EXPECT_EQ(1, data); + irutils::setBits(&data, 8, 0, 3); + EXPECT_EQ(1, data); + // Single bit. + irutils::setBits(&data, 0, 1, 0); + EXPECT_EQ(0, data); + irutils::setBits(&data, 0, 1, 1); + EXPECT_EQ(0b1, data); + irutils::setBits(&data, 1, 1, 0); + EXPECT_EQ(0b1, data); + irutils::setBits(&data, 1, 1, 1); + EXPECT_EQ(0b11, data); + irutils::setBits(&data, 1, 1, 0); + EXPECT_EQ(0b1, data); + irutils::setBits(&data, 2, 1, 1); + EXPECT_EQ(0b101, data); + irutils::setBits(&data, 7, 1, 1); + EXPECT_EQ(0b10000101, data); + // Larger value than bits desired to be set. + irutils::setBits(&data, 5, 1, 255); + EXPECT_EQ(0b10100101, data); + // Set multiple bits + data = 0; + irutils::setBits(&data, 0, 8, 255); + EXPECT_EQ(0b11111111, data); + irutils::setBits(&data, 0, 8, 0); + EXPECT_EQ(0, data); + irutils::setBits(&data, 0, 4, 0xF); + EXPECT_EQ(0xF, data); + irutils::setBits(&data, 4, 4, 0xF); + EXPECT_EQ(0xFF, data); + irutils::setBits(&data, 4, 4, 0x3); + EXPECT_EQ(0x3F, data); + irutils::setBits(&data, 3, 4, 0x3); + EXPECT_EQ(0x1F, data); + irutils::setBits(&data, 1, 4, 0x3); + EXPECT_EQ(0b00000111, data); + irutils::setBits(&data, 1, 4, 0b1001); + EXPECT_EQ(0b00010011, data); + // Partial overrun. + irutils::setBits(&data, 6, 4, 0b1001); + EXPECT_EQ(0b01010011, data); + irutils::setBits(&data, 7, 4, 0b1001); + EXPECT_EQ(0b11010011, data); +} + +TEST(TestUtils, setBits64Bit) { + uint64_t data = 1; + // Trivial/corner cases. + irutils::setBits(&data, 0, 0, 0); + EXPECT_EQ(1, data); + irutils::setBits(&data, 0, 0, 17); + EXPECT_EQ(1, data); + irutils::setBits(&data, 100, 0, 22); + EXPECT_EQ(1, data); + irutils::setBits(&data, 64, 23, 3); + EXPECT_EQ(1, data); + irutils::setBits(&data, 64, 0, 3); + EXPECT_EQ(1, data); + // Single bit. + irutils::setBits(&data, 0, 1, 0); + EXPECT_EQ(0, data); + irutils::setBits(&data, 0, 1, 1); + EXPECT_EQ(0b1, data); + irutils::setBits(&data, 1, 1, 0); + EXPECT_EQ(0b1, data); + irutils::setBits(&data, 1, 1, 1); + EXPECT_EQ(0b11, data); + irutils::setBits(&data, 1, 1, 0); + EXPECT_EQ(0b1, data); + irutils::setBits(&data, 2, 1, 1); + EXPECT_EQ(0b101, data); + irutils::setBits(&data, 7, 1, 1); + EXPECT_EQ(0b10000101, data); + // Larger value than bits desired to be set. + irutils::setBits(&data, 5, 1, 255); + EXPECT_EQ(0b10100101, data); + // Set multiple bits + data = 0; + irutils::setBits(&data, 0, 8, 255); + EXPECT_EQ(0b11111111, data); + irutils::setBits(&data, 0, 8, 0); + EXPECT_EQ(0, data); + irutils::setBits(&data, 0, 4, 0xF); + EXPECT_EQ(0xF, data); + irutils::setBits(&data, 4, 4, 0xF); + EXPECT_EQ(0xFF, data); + irutils::setBits(&data, 4, 4, 0x3); + EXPECT_EQ(0x3F, data); + irutils::setBits(&data, 3, 4, 0x3); + EXPECT_EQ(0x1F, data); + irutils::setBits(&data, 1, 4, 0x3); + EXPECT_EQ(0b00000111, data); + irutils::setBits(&data, 1, 4, 0b1001); + EXPECT_EQ(0b00010011, data); + // Partial overrun. + irutils::setBits(&data, 62, 4, 0b1001); + EXPECT_EQ(0x4000000000000013, data); + // General + irutils::setBits(&data, 32, 4, 0b1001); + EXPECT_EQ(0x4000000900000013, data); +} diff --git a/lib/IRremoteESP8266-2.6.5/test/Makefile b/lib/IRremoteESP8266-2.7.0/test/Makefile old mode 100755 new mode 100644 similarity index 96% rename from lib/IRremoteESP8266-2.6.5/test/Makefile rename to lib/IRremoteESP8266-2.7.0/test/Makefile index 0e721d58c..0235042f7 --- a/lib/IRremoteESP8266-2.6.5/test/Makefile +++ b/lib/IRremoteESP8266-2.7.0/test/Makefile @@ -21,7 +21,7 @@ INCLUDES = -I$(USER_DIR) -I. # Flags passed to the preprocessor. # Set Google Test's header directory as a system directory, such that # the compiler doesn't generate warnings in Google Test headers. -CPPFLAGS += -isystem $(GTEST_DIR)/include -DUNIT_TEST +CPPFLAGS += -isystem $(GTEST_DIR)/include -DUNIT_TEST -D_IR_LOCALE_=en-AU # Flags passed to the C++ compiler. CXXFLAGS += -g -Wall -Wextra -pthread -std=gnu++11 @@ -95,6 +95,7 @@ PROTOCOLS_H = $(USER_DIR)/ir_Amcor.h \ $(USER_DIR)/ir_Coolix.h \ $(USER_DIR)/ir_Electra.h \ $(USER_DIR)/ir_Haier.h \ + $(USER_DIR)/ir_Hitachi.h \ $(USER_DIR)/ir_Midea.h \ $(USER_DIR)/ir_Toshiba.h \ $(USER_DIR)/ir_Daikin.h \ @@ -117,11 +118,12 @@ PROTOCOLS_H = $(USER_DIR)/ir_Amcor.h \ $(USER_DIR)/ir_Trotec.h # Common object files COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o IRac.o ir_GlobalCache.o \ - $(PROTOCOLS) gtest_main.a + IRtext.o $(PROTOCOLS) gtest_main.a # Common dependencies COMMON_DEPS = $(USER_DIR)/IRrecv.h $(USER_DIR)/IRsend.h $(USER_DIR)/IRtimer.h \ $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h \ - $(USER_DIR)/IRac.h $(PROTOCOLS_H) + $(USER_DIR)/IRac.h $(USER_DIR)/i18n.h $(USER_DIR)/IRtext.h \ + $(PROTOCOLS_H) # Common test dependencies COMMON_TEST_DEPS = $(COMMON_DEPS) IRrecv_test.h IRsend_test.h @@ -148,8 +150,11 @@ gtest_main.a : gtest-all.o gtest_main.o # gtest_main.a, depending on whether it defines its own main() # function. -IRutils.o : $(USER_DIR)/IRutils.cpp $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRutils.cpp +IRtext.o : $(USER_DIR)/IRtext.cpp $(USER_DIR)/IRtext.h $(USER_DIR)/IRremoteESP8266.h $(USER_DIR)/i18n.h $(USER_DIR)/locale/*.h + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/IRtext.cpp + +IRutils.o : $(USER_DIR)/IRutils.cpp $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h $(USER_DIR)/i18n.h + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/IRutils.cpp IRutils_test.o : IRutils_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c IRutils_test.cpp @@ -421,7 +426,7 @@ ir_Toshiba_test.o : ir_Toshiba_test.cpp $(USER_DIR)/ir_Toshiba.h $(COMMON_TEST_D ir_Toshiba_test : $(COMMON_OBJ) ir_Toshiba_test.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ -ir_Midea.o : $(USER_DIR)/ir_Midea.cpp $(GTEST_HEADERS) +ir_Midea.o : $(USER_DIR)/ir_Midea.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Midea.cpp ir_Midea_test.o : ir_Midea_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) @@ -430,7 +435,7 @@ ir_Midea_test.o : ir_Midea_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) ir_Midea_test : $(COMMON_OBJ) ir_Midea_test.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ -ir_Magiquest.o : $(USER_DIR)/ir_Magiquest.cpp $(GTEST_HEADERS) +ir_Magiquest.o : $(USER_DIR)/ir_Magiquest.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_Magiquest.cpp ir_Magiquest_test.o : ir_Magiquest_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) @@ -466,7 +471,7 @@ ir_Haier_test.o : ir_Haier_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) ir_Haier_test : $(COMMON_OBJ) ir_Haier_test.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ -ir_Hitachi.o : $(USER_DIR)/ir_Hitachi.cpp $(COMMON_DEPS) $(GTEST_HEADERS) +ir_Hitachi.o : $(USER_DIR)/ir_Hitachi.cpp $(USER_DIR)/ir_Hitachi.h $(COMMON_DEPS) $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Hitachi.cpp ir_Hitachi_test.o : ir_Hitachi_test.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Aiwa_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Aiwa_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Aiwa_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Aiwa_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Amcor_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Amcor_test.cpp old mode 100755 new mode 100644 similarity index 98% rename from lib/IRremoteESP8266-2.6.5/test/ir_Amcor_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Amcor_test.cpp index 265c61500..787769516 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Amcor_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Amcor_test.cpp @@ -69,7 +69,7 @@ TEST(TestDecodeAmcor, SyntheticSelfDecode) { EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Fan: 4 (Auto), Temp: 24C, Max: Off", + "Power: On, Mode: 1 (Cool), Fan: 4 (Auto), Temp: 24C, Max: Off", ac.toString()); } @@ -343,9 +343,9 @@ TEST(TestAmcorAcClass, Max) { uint8_t hi[kAmcorStateLength] = { 0x01, 0x12, 0x40, 0x00, 0x00, 0x30, 0x03, 0x0E}; ac.setRaw(lo); - EXPECT_EQ("Power: On, Mode: 1 (COOL), Fan: 4 (Auto), Temp: 12C, Max: On", + EXPECT_EQ("Power: On, Mode: 1 (Cool), Fan: 4 (Auto), Temp: 12C, Max: On", ac.toString()); ac.setRaw(hi); - EXPECT_EQ("Power: On, Mode: 2 (HEAT), Fan: 1 (Low), Temp: 32C, Max: On", + EXPECT_EQ("Power: On, Mode: 2 (Heat), Fan: 1 (Low), Temp: 32C, Max: On", ac.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Argo_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Argo_test.cpp old mode 100755 new mode 100644 similarity index 95% rename from lib/IRremoteESP8266-2.6.5/test/ir_Argo_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Argo_test.cpp index 7932416e0..d5a5d17ad --- a/lib/IRremoteESP8266-2.6.5/test/ir_Argo_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Argo_test.cpp @@ -53,8 +53,8 @@ TEST(TestArgoACClass, MessageConstructon) { 0xAC, 0xF5, 0x00, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xD6, 0x01}; EXPECT_STATE_EQ(expected, ac.getRaw(), kArgoBits); EXPECT_EQ( - "Power: On, Mode: 0 (COOL), Fan: 0 (AUTO), Temp: 20C, Room Temp: 21C, " - "Max: On, iFeel: On, Night: On", + "Power: On, Mode: 0 (Cool), Fan: 0 (Auto), Temp: 20C, Room Temp: 21C, " + "Max: On, IFeel: On, Night: On", ac.toString()); } @@ -128,12 +128,12 @@ TEST(TestArgoACClass, SetAndGetRoomTemp) { ac.setRoomTemp(25); EXPECT_EQ(25, ac.getRoomTemp()); - ac.setRoomTemp(kArgoTempOffset); - EXPECT_EQ(kArgoTempOffset, ac.getRoomTemp()); + ac.setRoomTemp(kArgoTempDelta); + EXPECT_EQ(kArgoTempDelta, ac.getRoomTemp()); ac.setRoomTemp(kArgoMaxRoomTemp); EXPECT_EQ(kArgoMaxRoomTemp, ac.getRoomTemp()); - ac.setRoomTemp(kArgoTempOffset - 1); - EXPECT_EQ(kArgoTempOffset, ac.getRoomTemp()); + ac.setRoomTemp(kArgoTempDelta - 1); + EXPECT_EQ(kArgoTempDelta, ac.getRoomTemp()); ac.setRoomTemp(kArgoMaxRoomTemp + 1); EXPECT_EQ(kArgoMaxRoomTemp, ac.getRoomTemp()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Carrier_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Carrier_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Carrier_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Carrier_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Coolix_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Coolix_test.cpp old mode 100755 new mode 100644 similarity index 96% rename from lib/IRremoteESP8266-2.6.5/test/ir_Coolix_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Coolix_test.cpp index 618d825a0..2a3367765 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Coolix_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Coolix_test.cpp @@ -352,12 +352,11 @@ TEST(TestDecodeCoolix, FailToDecodeNonCoolixExample) { } // Tests for the IRCoolixAC class. - TEST(TestCoolixACClass, SetAndGetRaw) { IRCoolixAC ircoolix(0); - ircoolix.setRaw(kCoolixOff); - EXPECT_EQ(kCoolixOff, ircoolix.getRaw()); + ircoolix.setRaw(0xB21F28); + EXPECT_EQ(0xB21F28, ircoolix.getRaw()); ircoolix.setRaw(kCoolixDefaultState); EXPECT_EQ(kCoolixDefaultState, ircoolix.getRaw()); } @@ -480,19 +479,20 @@ TEST(TestCoolixACClass, SpecialModesAndReset) { TEST(TestCoolixACClass, HumanReadable) { IRCoolixAC ircoolix(0); + ircoolix.begin(); + ircoolix.setPower(true); // Initial starting point. EXPECT_EQ( - "Power: On, Mode: 2 (AUTO), Fan: 5 (AUTO), Temp: 25C, " - "Zone Follow: Off, Sensor Temp: Ignored", + "Power: On, Mode: 2 (Auto), Fan: 0 (Auto0), Temp: 25C, " + "Zone Follow: Off, Sensor Temp: Off", ircoolix.toString()); - ircoolix.setSensorTemp(24); ircoolix.setTemp(22); ircoolix.setMode(kCoolixCool); ircoolix.setFan(kCoolixFanMin); EXPECT_EQ( - "Power: On, Mode: 0 (COOL), Fan: 4 (MIN), Temp: 22C, " + "Power: On, Mode: 0 (Cool), Fan: 4 (Min), Temp: 22C, " "Zone Follow: On, Sensor Temp: 24C", ircoolix.toString()); ircoolix.setSwing(); @@ -503,26 +503,28 @@ TEST(TestCoolixACClass, HumanReadable) { TEST(TestCoolixACClass, KnownExamples) { IRCoolixAC ircoolix(0); - + ircoolix.begin(); + ircoolix.setPower(true); ircoolix.setRaw(0b101100101011111111100100); EXPECT_EQ( - "Power: On, Mode: 4 (FAN), Fan: 5 (AUTO), Zone Follow: Off, " - "Sensor Temp: Ignored", + "Power: On, Mode: 4 (Fan), Fan: 5 (Auto), Zone Follow: Off, " + "Sensor Temp: Off", ircoolix.toString()); ircoolix.setRaw(0b101100101001111100000000); EXPECT_EQ( - "Power: On, Mode: 0 (COOL), Fan: 4 (MIN), Temp: 17C, " - "Zone Follow: Off, Sensor Temp: Ignored", + "Power: On, Mode: 0 (Cool), Fan: 4 (Min), Temp: 17C, " + "Zone Follow: Off, Sensor Temp: Off", ircoolix.toString()); } TEST(TestCoolixACClass, Issue579FanAuto0) { IRCoolixAC ircoolix(0); - + ircoolix.begin(); + ircoolix.setPower(true); ircoolix.setRaw(0xB21F28); EXPECT_EQ( - "Power: On, Mode: 2 (AUTO), Fan: 0 (AUTO0), Temp: 20C, " - "Zone Follow: Off, Sensor Temp: Ignored", + "Power: On, Mode: 2 (Auto), Fan: 0 (Auto0), Temp: 20C, " + "Zone Follow: Off, Sensor Temp: Off", ircoolix.toString()); } @@ -570,20 +572,20 @@ TEST(TestCoolixACClass, RealCaptureExample) { TEST(TestCoolixACClass, Issue624HandleSpecialStatesBetter) { IRCoolixAC ac(0); ac.begin(); + ac.setPower(true); // Default EXPECT_EQ( - "Power: On, Mode: 2 (AUTO), Fan: 5 (AUTO), Temp: 25C, Zone Follow: Off, " - "Sensor Temp: Ignored", + "Power: On, Mode: 2 (Auto), Fan: 0 (Auto0), Temp: 25C, Zone Follow: Off, " + "Sensor Temp: Off", ac.toString()); - EXPECT_EQ(0xB2BFC8, ac.getRaw()); + EXPECT_EQ(0xB21FC8, ac.getRaw()); // Change of settings. - ac.setPower(true); ac.setTemp(24); ac.setMode(kCoolixCool); ac.setFan(kCoolixFanAuto); EXPECT_EQ( - "Power: On, Mode: 0 (COOL), Fan: 5 (AUTO), Temp: 24C, Zone Follow: Off, " - "Sensor Temp: Ignored", + "Power: On, Mode: 0 (Cool), Fan: 5 (Auto), Temp: 24C, Zone Follow: Off, " + "Sensor Temp: Off", ac.toString()); EXPECT_EQ(0xB2BF40, ac.getRaw()); // Turn the unit off. @@ -598,27 +600,25 @@ TEST(TestCoolixACClass, Issue624HandleSpecialStatesBetter) { ac.setMode(kCoolixCool); ac.setFan(kCoolixFanAuto); EXPECT_EQ( - "Power: On, Mode: 0 (COOL), Fan: 5 (AUTO), Temp: 24C, Zone Follow: Off, " - "Sensor Temp: Ignored", + "Power: On, Mode: 0 (Cool), Fan: 5 (Auto), Temp: 24C, Zone Follow: Off, " + "Sensor Temp: Off", ac.toString()); EXPECT_EQ(0xB2BF40, ac.getRaw()); - // Now test if we setRaw() a special state first. - ac.setRaw(kCoolixSwing); // Repeat change of settings. - ac.setPower(true); ac.setTemp(24); ac.setMode(kCoolixCool); ac.setFan(kCoolixFanAuto); EXPECT_EQ( - "Power: On, Mode: 0 (COOL), Fan: 5 (AUTO), Temp: 24C, Zone Follow: Off, " - "Sensor Temp: Ignored", + "Power: On, Mode: 0 (Cool), Fan: 5 (Auto), Temp: 24C, Zone Follow: Off, " + "Sensor Temp: Off", ac.toString()); EXPECT_EQ(0xB2BF40, ac.getRaw()); } TEST(TestCoolixACClass, toCommon) { IRCoolixAC ac(0); + ac.begin(); ac.setPower(true); ac.setMode(kCoolixCool); ac.setTemp(20); @@ -666,6 +666,7 @@ TEST(TestCoolixACClass, Issue722) { // ON Auto Temp 18C uint32_t on_auto_18c_fan_auto0 = 0xB21F18; + ac.on(); ac.setTemp(18); EXPECT_EQ(on_auto_18c_fan_auto0, ac.getRaw()); diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Daikin_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Daikin_test.cpp old mode 100755 new mode 100644 similarity index 85% rename from lib/IRremoteESP8266-2.6.5/test/ir_Daikin_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Daikin_test.cpp index 774109c3a..9fcaabcb0 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Daikin_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Daikin_test.cpp @@ -691,11 +691,11 @@ TEST(TestDaikinClass, HumanReadable) { IRDaikinESP ac(0); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 15C, Fan: 11 (Quiet), " - "Powerful: Off, Quiet: Off, Sensor: Off, Mold: Off, " - "Comfort: Off, Swing (Horizontal): Off, Swing (Vertical): Off, " - "Current Time: 00:00, Current Day: (UNKNOWN), On Time: Off, " - "Off Time: Off, Weekly Timer: On", + "Power: On, Mode: 4 (Heat), Temp: 15C, Fan: 11 (Quiet), " + "Powerful: Off, Quiet: Off, Sensor: Off, Mould: Off, " + "Comfort: Off, Swing(H): Off, Swing(V): Off, " + "Clock: 00:00, Day: 0 (UNKNOWN), On Timer: Off, " + "Off Timer: Off, Weekly Timer: On", ac.toString()); ac.setMode(kDaikinAuto); ac.setTemp(25); @@ -713,10 +713,10 @@ TEST(TestDaikinClass, HumanReadable) { ac.setWeeklyTimerEnable(false); ac.off(); EXPECT_EQ( - "Power: Off, Mode: 0 (AUTO), Temp: 25C, Fan: 10 (Auto), " - "Powerful: Off, Quiet: On, Sensor: On, Mold: On, Comfort: On, " - "Swing (Horizontal): On, Swing (Vertical): On, " - "Current Time: 09:15, Current Day: WED, On Time: 08:00, Off Time: 17:30, " + "Power: Off, Mode: 0 (Auto), Temp: 25C, Fan: 10 (Auto), " + "Powerful: Off, Quiet: On, Sensor: On, Mould: On, Comfort: On, " + "Swing(H): On, Swing(V): On, " + "Clock: 09:15, Day: 4 (Wed), On Timer: 08:00, Off Timer: 17:30, " "Weekly Timer: Off", ac.toString()); } @@ -866,11 +866,11 @@ TEST(TestDecodeDaikin, RealExample) { EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 29C, Fan: 10 (Auto), Powerful: On, " - "Quiet: Off, Sensor: Off, Mold: Off, Comfort: Off, " - "Swing (Horizontal): Off, Swing (Vertical): Off, " - "Current Time: 22:18, Current Day: (UNKNOWN), " - "On Time: 21:30, Off Time: 06:10, Weekly Timer: On", ac.toString()); + "Power: On, Mode: 3 (Cool), Temp: 29C, Fan: 10 (Auto), Powerful: On, " + "Quiet: Off, Sensor: Off, Mould: Off, Comfort: Off, " + "Swing(H): Off, Swing(V): Off, " + "Clock: 22:18, Day: 0 (UNKNOWN), " + "On Timer: 21:30, Off Timer: 06:10, Weekly Timer: On", ac.toString()); } // Decoding a message we entirely constructed based solely on a given state. @@ -899,11 +899,11 @@ TEST(TestDecodeDaikin, ShortSyntheticExample) { EXPECT_STATE_EQ(longState, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 29C, Fan: 10 (Auto), Powerful: On, " - "Quiet: Off, Sensor: Off, Mold: Off, Comfort: Off, " - "Swing (Horizontal): Off, Swing (Vertical): Off, " - "Current Time: 22:18, Current Day: (UNKNOWN), " - "On Time: 21:30, Off Time: 06:10, Weekly Timer: On", ac.toString()); + "Power: On, Mode: 3 (Cool), Temp: 29C, Fan: 10 (Auto), Powerful: On, " + "Quiet: Off, Sensor: Off, Mould: Off, Comfort: Off, " + "Swing(H): Off, Swing(V): Off, " + "Clock: 22:18, Day: 0 (UNKNOWN), " + "On Timer: 21:30, Off Timer: 06:10, Weekly Timer: On", ac.toString()); } // Decoding a message we entirely constructed based solely on a given state. @@ -928,11 +928,11 @@ TEST(TestDecodeDaikin, LongSyntheticExample) { EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 29C, Fan: 10 (Auto), Powerful: On, " - "Quiet: Off, Sensor: Off, Mold: Off, Comfort: Off, " - "Swing (Horizontal): Off, Swing (Vertical): Off, " - "Current Time: 22:18, Current Day: (UNKNOWN), " - "On Time: 21:30, Off Time: 06:10, Weekly Timer: On", ac.toString()); + "Power: On, Mode: 3 (Cool), Temp: 29C, Fan: 10 (Auto), Powerful: On, " + "Quiet: Off, Sensor: Off, Mould: Off, Comfort: Off, " + "Swing(H): Off, Swing(V): Off, " + "Clock: 22:18, Day: 0 (UNKNOWN), " + "On Timer: 21:30, Off Timer: 06:10, Weekly Timer: On", ac.toString()); } // Test decoding a message captured from a real IR remote. @@ -1032,10 +1032,10 @@ TEST(TestDecodeDaikin2, SyntheticExample) { EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (Auto), " - "Swing (V): 5, Swing (H): 190 (Auto), " - "Clock: 14:50, On Time: Off, Off Time: Off, Sleep Time: Off, " - "Beep: 1 (Quiet), Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, " + "Power: Off, Mode: 0 (Auto), Temp: 19C, Fan: 10 (Auto), " + "Swing(V): 5 (Low), Swing(H): 190 (Auto), " + "Clock: 14:50, On Timer: Off, Off Timer: Off, Sleep Timer: Off, " + "Beep: 1 (Quiet), Light: 3 (Off), Mould: On, Clean: On, Fresh: Off, " "Eye: Off, Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: Off, " "Econo: Off", ac.toString()); @@ -1348,11 +1348,13 @@ TEST(TestDaikin2Class, Swing) { ASSERT_EQ(kDaikin2SwingVBreeze, ac.getSwingVertical()); ac.setSwingVertical(kDaikin2SwingVCirculate); ASSERT_EQ(kDaikin2SwingVCirculate, ac.getSwingVertical()); + ac.setSwingVertical(kDaikin2SwingVSwing); + ASSERT_EQ(kDaikin2SwingVSwing, ac.getSwingVertical()); ac.setSwingVertical(kDaikin2SwingVAuto); ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical()); ac.setSwingVertical(0); ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical()); - ac.setSwingVertical(7); + ac.setSwingVertical(20); ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical()); ac.setSwingVertical(255); ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical()); @@ -1442,10 +1444,10 @@ TEST(TestDaikin2Class, HumanReadable) { ac.setPurify(true); ac.setEcono(false); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 21C, Fan: 5 (High), " - "Swing (V): 14 (Auto), Swing (H): 191 (Swing), Clock: 12:34, " - "On Time: Off, Off Time: 20:00, Sleep Time: 04:00, Beep: 2 (Loud), " - "Light: 2 (Dim), Mold: On, Clean: Off, Fresh Air: On, Eye: On, " + "Power: On, Mode: 3 (Cool), Temp: 21C, Fan: 5 (High), " + "Swing(V): 14 (Auto), Swing(H): 191 (Swing), Clock: 12:34, " + "On Timer: Off, Off Timer: 20:00, Sleep Timer: 04:00, Beep: 2 (Loud), " + "Light: 2 (Low), Mould: On, Clean: Off, Fresh: On, Eye: On, " "Eye Auto: On, Quiet: Off, Powerful: On, Purify: On, Econo: Off", ac.toString()); ac.setQuiet(true); @@ -1457,10 +1459,10 @@ TEST(TestDaikin2Class, HumanReadable) { ac.setCurrentTime(23 * 60 + 45); // 23:45 ac.enableOnTimer(9 * 60 + 11); // 9:11 EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 32C, Fan: 1 (Low), " - "Swing (V): 14 (Auto), Swing (H): 191 (Swing), Clock: 23:45, " - "On Time: 09:11, Off Time: 20:00, Sleep Time: Off, Beep: 1 (Quiet), " - "Light: 1 (Bright), Mold: On, Clean: Off, Fresh Air: On, Eye: On, " + "Power: On, Mode: 4 (Heat), Temp: 32C, Fan: 1 (Low), " + "Swing(V): 14 (Auto), Swing(H): 191 (Swing), Clock: 23:45, " + "On Timer: 09:11, Off Timer: 20:00, Sleep Timer: Off, Beep: 1 (Quiet), " + "Light: 1 (High), Mould: On, Clean: Off, Fresh: On, Eye: On, " "Eye Auto: On, Quiet: On, Powerful: Off, Purify: On, Econo: Off", ac.toString()); } @@ -1498,10 +1500,10 @@ TEST(TestDaikin2Class, KnownConstruction) { ac.setPurify(false); ac.setEcono(false); EXPECT_EQ( - "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (Auto), " - "Swing (V): 5, Swing (H): 190 (Auto), " - "Clock: 14:50, On Time: Off, Off Time: Off, Sleep Time: Off, " - "Beep: 1 (Quiet), Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, " + "Power: Off, Mode: 0 (Auto), Temp: 19C, Fan: 10 (Auto), " + "Swing(V): 5 (Low), Swing(H): 190 (Auto), " + "Clock: 14:50, On Timer: Off, Off Timer: Off, Sleep Timer: Off, " + "Beep: 1 (Quiet), Light: 3 (Off), Mould: On, Clean: On, Fresh: Off, " "Eye: Off, Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: Off, " "Econo: Off", ac.toString()); @@ -1522,7 +1524,7 @@ TEST(TestUtils, Housekeeping) { ASSERT_EQ("DAIKIN152", typeToString(decode_type_t::DAIKIN152)); ASSERT_EQ(decode_type_t::DAIKIN152, strToDecodeType("DAIKIN152")); ASSERT_TRUE(hasACState(decode_type_t::DAIKIN152)); - ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::DAIKIN152)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::DAIKIN152)); ASSERT_EQ("DAIKIN160", typeToString(decode_type_t::DAIKIN160)); ASSERT_EQ(decode_type_t::DAIKIN160, strToDecodeType("DAIKIN160")); @@ -1560,10 +1562,10 @@ TEST(TestDecodeDaikin2, Issue582DeepDecodeExample) { ASSERT_TRUE(ac.getEye()); ASSERT_TRUE(ac.getPurify()); EXPECT_EQ( - "Power: On, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (Auto), " - "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 09:20, " - "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), " - "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: On, " + "Power: On, Mode: 0 (Auto), Temp: 19C, Fan: 10 (Auto), " + "Swing(V): 14 (Auto), Swing(H): 190 (Auto), Clock: 09:20, " + "On Timer: Off, Off Timer: Off, Sleep Timer: Off, Beep: 3 (Off), " + "Light: 3 (Off), Mould: On, Clean: On, Fresh: Off, Eye: On, " "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off", ac.toString()); } @@ -1585,19 +1587,19 @@ TEST(TestDecodeDaikin2, Issue582PowerfulEconoFix) { ac.setRaw(PowerfulOn); ASSERT_TRUE(ac.getPowerful()); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), " - "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:46, " - "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), " - "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, " + "Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 10 (Auto), " + "Swing(V): 14 (Auto), Swing(H): 190 (Auto), Clock: 13:46, " + "On Timer: Off, Off Timer: Off, Sleep Timer: Off, Beep: 3 (Off), " + "Light: 3 (Off), Mould: On, Clean: On, Fresh: Off, Eye: Off, " "Eye Auto: Off, Quiet: Off, Powerful: On, Purify: On, Econo: Off", ac.toString()); ac.setRaw(PowerfulOff); ASSERT_FALSE(ac.getPowerful()); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), " - "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:46, " - "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), " - "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, " + "Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 10 (Auto), " + "Swing(V): 14 (Auto), Swing(H): 190 (Auto), Clock: 13:46, " + "On Timer: Off, Off Timer: Off, Sleep Timer: Off, Beep: 3 (Off), " + "Light: 3 (Off), Mould: On, Clean: On, Fresh: Off, Eye: Off, " "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off", ac.toString()); @@ -1614,19 +1616,19 @@ TEST(TestDecodeDaikin2, Issue582PowerfulEconoFix) { ac.setRaw(EconoOn); ASSERT_TRUE(ac.getEcono()); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), " - "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:47, " - "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), " - "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, " + "Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 10 (Auto), " + "Swing(V): 14 (Auto), Swing(H): 190 (Auto), Clock: 13:47, " + "On Timer: Off, Off Timer: Off, Sleep Timer: Off, Beep: 3 (Off), " + "Light: 3 (Off), Mould: On, Clean: On, Fresh: Off, Eye: Off, " "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: On", ac.toString()); ac.setRaw(EconoOff); ASSERT_FALSE(ac.getEcono()); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 20C, Fan: 10 (Auto), " - "Swing (V): 14 (Auto), Swing (H): 190 (Auto), Clock: 13:47, " - "On Time: Off, Off Time: Off, Sleep Time: Off, Beep: 3 (Off), " - "Light: 3 (Off), Mold: On, Clean: On, Fresh Air: Off, Eye: Off, " + "Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 10 (Auto), " + "Swing(V): 14 (Auto), Swing(H): 190 (Auto), Clock: 13:47, " + "On Timer: Off, Off Timer: Off, Sleep Timer: Off, Beep: 3 (Off), " + "Light: 3 (Off), Mould: On, Clean: On, Fresh: Off, Eye: Off, " "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off", ac.toString()); } @@ -1823,8 +1825,8 @@ TEST(TestDaikin216Class, ExampleStates) { 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x53}; ac.setRaw(state); EXPECT_EQ( - "Power: On, Mode: 2 (DRY), Temp: 32C, Fan: 10 (Auto), " - "Swing (Horizontal): Off, Swing (Vertical): Off, " + "Power: On, Mode: 2 (Dry), Temp: 32C, Fan: 10 (Auto), " + "Swing(H): Off, Swing(V): Off, " "Quiet: Off, Powerful: Off", ac.toString()); } @@ -1845,8 +1847,8 @@ TEST(TestDaikin216Class, ReconstructKnownState) { ac.setSwingVertical(false); ac.setQuiet(false); EXPECT_EQ( - "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (Auto), " - "Swing (Horizontal): Off, Swing (Vertical): Off, " + "Power: Off, Mode: 0 (Auto), Temp: 19C, Fan: 10 (Auto), " + "Swing(H): Off, Swing(V): Off, " "Quiet: Off, Powerful: Off", ac.toString()); @@ -1909,8 +1911,8 @@ TEST(TestDecodeDaikin216, RealExample) { IRDaikin216 ac(0); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: Off, Mode: 0 (AUTO), Temp: 19C, Fan: 10 (Auto), " - "Swing (Horizontal): Off, Swing (Vertical): Off, " + "Power: Off, Mode: 0 (Auto), Temp: 19C, Fan: 10 (Auto), " + "Swing(H): Off, Swing(V): Off, " "Quiet: Off, Powerful: Off", ac.toString()); } @@ -2003,7 +2005,7 @@ TEST(TestDaikin2Class, toCommon) { ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon().mode); ASSERT_EQ(stdAc::fanspeed_t::kMax, ac.toCommon().fanspeed); ASSERT_EQ(stdAc::swingv_t::kMiddle, ac.toCommon().swingv); - ASSERT_EQ(stdAc::swingh_t::kAuto, ac.toCommon().swingh); + ASSERT_EQ(stdAc::swingh_t::kOff, ac.toCommon().swingh); ASSERT_EQ(6 * 60, ac.toCommon().sleep); // Unsupported. ASSERT_EQ(-1, ac.toCommon().clock); @@ -2088,8 +2090,8 @@ TEST(TestDecodeDaikin160, RealExample) { EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); IRDaikin160 ac(0); ac.setRaw(irsend.capture.state); - EXPECT_EQ("Power: Off, Mode: 3 (COOL), Temp: 25C, Fan: 10 (Auto), " - "Vent Position (V): 1 (Lowest)", ac.toString()); + EXPECT_EQ("Power: Off, Mode: 3 (Cool), Temp: 25C, Fan: 10 (Auto), " + "Swing(V): 1 (Lowest)", ac.toString()); } TEST(TestDecodeDaikin160, SyntheticExample) { @@ -2290,8 +2292,8 @@ TEST(TestDaikin160Class, HumanReadable) { IRDaikin160 ac(0); EXPECT_EQ( - "Power: Off, Mode: 3 (COOL), Temp: 25C, Fan: 10 (Auto), " - "Vent Position (V): 1 (Lowest)", + "Power: Off, Mode: 3 (Cool), Temp: 25C, Fan: 10 (Auto), " + "Swing(V): 1 (Lowest)", ac.toString()); ac.setMode(kDaikinAuto); ac.setTemp(19); @@ -2299,8 +2301,8 @@ TEST(TestDaikin160Class, HumanReadable) { ac.setSwingVertical(kDaikin160SwingVAuto); ac.setPower(true); EXPECT_EQ( - "Power: On, Mode: 0 (AUTO), Temp: 19C, Fan: 1 (Low), " - "Vent Position (V): 15 (Auto)", + "Power: On, Mode: 0 (Auto), Temp: 19C, Fan: 1 (Low), " + "Swing(V): 15 (Auto)", ac.toString()); } @@ -2308,20 +2310,20 @@ TEST(TestDaikin176Class, FanControl) { IRDaikin176 ac(0); EXPECT_EQ( - "Power: Off, Mode: 7 (COOL), Temp: 9C, Fan: 1 (Low), Swing (H): 6 (Off)", + "Power: Off, Mode: 7 (Cool), Temp: 9C, Fan: 1 (Low), Swing(H): 6 (Off)", ac.toString()); ac.setFan(kDaikinFanMin); ac.setPower(true); EXPECT_EQ( - "Power: On, Mode: 7 (COOL), Temp: 9C, Fan: 1 (Low), Swing (H): 6 (Off)", + "Power: On, Mode: 7 (Cool), Temp: 9C, Fan: 1 (Low), Swing(H): 6 (Off)", ac.toString()); ac.setFan(kDaikinFanMin + 1); EXPECT_EQ( - "Power: On, Mode: 7 (COOL), Temp: 9C, Fan: 3 (High), Swing (H): 6 (Off)", + "Power: On, Mode: 7 (Cool), Temp: 9C, Fan: 3 (High), Swing(H): 6 (Off)", ac.toString()); ac.setFan(kDaikin176FanMax); EXPECT_EQ( - "Power: On, Mode: 7 (COOL), Temp: 9C, Fan: 3 (High), Swing (H): 6 (Off)", + "Power: On, Mode: 7 (Cool), Temp: 9C, Fan: 3 (High), Swing(H): 6 (Off)", ac.toString()); // Real state from remote @@ -2332,8 +2334,8 @@ TEST(TestDaikin176Class, FanControl) { 0x00, 0x20, 0x25}; ac.setRaw(state); EXPECT_EQ( - "Power: On, Mode: 7 (COOL), Temp: 26C, Fan: 3 (High), " - "Swing (H): 5 (Auto)", + "Power: On, Mode: 7 (Cool), Temp: 26C, Fan: 3 (High), " + "Swing(H): 5 (Auto)", ac.toString()); } @@ -2358,12 +2360,12 @@ TEST(TestDaikin176Class, SimulateIRacDaikin176) { ac.setFan(ac.convertFan(stdAc::fanspeed_t::kMax)); ac.setSwingHorizontal(kDaikin176SwingHOff); EXPECT_EQ( - "Power: On, Mode: 7 (COOL), Temp: 26C, Fan: 3 (High), Swing (H): 6 (Off)", + "Power: On, Mode: 7 (Cool), Temp: 26C, Fan: 3 (High), Swing(H): 6 (Off)", ac.toString()); ac.setSwingHorizontal(ac.convertSwingH(stdAc::swingh_t::kAuto)); EXPECT_EQ( - "Power: On, Mode: 7 (COOL), Temp: 26C, Fan: 3 (High), " - "Swing (H): 5 (Auto)", + "Power: On, Mode: 7 (Cool), Temp: 26C, Fan: 3 (High), " + "Swing(H): 5 (Auto)", ac.toString()); } @@ -2494,25 +2496,25 @@ TEST(TestDaikin176Class, ReconstructKnownStates) { // Data from: // https://github.com/crankyoldgit/IRremoteESP8266/pull/826#issuecomment-513531138 - // Power: On, Mode: 7 (COOL), Temp: 25C, Fan: 3 (MAX), Swing (H): 5 (Auto) + // Power: On, Mode: 7 (Cool), Temp: 25C, Fan: 3 (Max), Swing(H): 5 (Auto) // 11DA171804001E11DA17180073002100002035002023 uint8_t on_cool_25_max_auto[22] = { 0x11, 0xDA, 0x17, 0x18, 0x04, 0x00, 0x1E, 0x11, 0xDA, 0x17, 0x18, 0x00, 0x73, 0x00, 0x21, 0x00, 0x00, 0x20, 0x35, 0x00, 0x20, 0x23}; - // Power: On, Mode: 6 (FAN), Temp: 17C, Fan: 3 (MAX), Swing (H): 5 (Auto) + // Power: On, Mode: 6 (Fan), Temp: 17C, Fan: 3 (Max), Swing(H): 5 (Auto) // 11DA171804001E11DA171800630401000010350020E7 uint8_t on_fan_17_max_auto[22] = { 0x11, 0xDA, 0x17, 0x18, 0x04, 0x00, 0x1E, 0x11, 0xDA, 0x17, 0x18, 0x00, 0x63, 0x04, 0x01, 0x00, 0x00, 0x10, 0x35, 0x00, 0x20, 0xE7}; - // Power: On, Mode: 2 (DRY), Temp: 17C, Fan: 3 (MAX), Swing (H): 5 (Auto) + // Power: On, Mode: 2 (Dry), Temp: 17C, Fan: 3 (Max), Swing(H): 5 (Auto) // 11DA171804001E11DA17180023047100001035002017 uint8_t on_dry_17_max_auto[22] = { 0x11, 0xDA, 0x17, 0x18, 0x04, 0x00, 0x1E, 0x11, 0xDA, 0x17, 0x18, 0x00, 0x23, 0x04, 0x71, 0x00, 0x00, 0x10, 0x35, 0x00, 0x20, 0x17}; - // Power: On, Mode: 7 (COOL), Temp: 25C, Fan: 3 (MAX), Swing (H): 5 (Auto) + // Power: On, Mode: 7 (Cool), Temp: 25C, Fan: 3 (Max), Swing(H): 5 (Auto) // 11DA171804001E11DA17180073042100002035002027 uint8_t on_cool_25_max_auto_v2[22] = { 0x11, 0xDA, 0x17, 0x18, 0x04, 0x00, 0x1E, @@ -2573,10 +2575,10 @@ TEST(TestDecodeDaikin128, RealExample) { ASSERT_EQ(kDaikin128Bits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Power Toggle: On, Mode: 2 (COOL), Temp: 26C, Fan: 1 (Auto), " - "Powerful: Off, Quiet: Off, Swing (V): On, Sleep: Off, " + "Power Toggle: On, Mode: 2 (Cool), Temp: 26C, Fan: 1 (Auto), " + "Powerful: Off, Quiet: Off, Swing(V): On, Sleep: Off, " "Econo: Off, Clock: 19:20, " - "On Timer: Off, On Time: 07:30, Off Timer: Off, Off Time: 22:00, " + "On Timer: Off, On Timer: 07:30, Off Timer: Off, Off Timer: 22:00, " "Light Toggle: 0 (Off)", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -2821,10 +2823,10 @@ TEST(TestDaikin128Class, HumanReadable) { ac.setEcono(false); ac.setSwingVertical(true); EXPECT_EQ( - "Power Toggle: Off, Mode: 10 (AUTO), Temp: 25C, Fan: 1 (Auto), " - "Powerful: Off, Quiet: Off, Swing (V): On, " + "Power Toggle: Off, Mode: 10 (Auto), Temp: 25C, Fan: 1 (Auto), " + "Powerful: Off, Quiet: Off, Swing(V): On, " "Sleep: Off, Econo: Off, Clock: 00:00, " - "On Timer: Off, On Time: 00:00, Off Timer: Off, Off Time: 00:00, " + "On Timer: Off, On Timer: 00:00, Off Timer: Off, Off Timer: 00:00, " "Light Toggle: 0 (Off)", ac.toString()); ac.setMode(kDaikin128Cool); @@ -2841,10 +2843,10 @@ TEST(TestDaikin128Class, HumanReadable) { ac.setOffTimerEnabled(true); ac.setLightToggle(kDaikin128BitWall); EXPECT_EQ( - "Power Toggle: On, Mode: 2 (COOL), Temp: 16C, Fan: 9 (Quiet), " - "Powerful: Off, Quiet: On, Swing (V): Off, " + "Power Toggle: On, Mode: 2 (Cool), Temp: 16C, Fan: 9 (Quiet), " + "Powerful: Off, Quiet: On, Swing(V): Off, " "Sleep: On, Econo: On, Clock: 18:33, " - "On Timer: On, On Time: 10:00, Off Timer: On, Off Time: 21:30, " + "On Timer: On, On Timer: 10:00, Off Timer: On, Off Timer: 21:30, " "Light Toggle: 8 (Wall)", ac.toString()); } @@ -2965,6 +2967,10 @@ TEST(TestDecodeDaikin152, RealExample) { ASSERT_EQ(DAIKIN152, irsend.capture.decode_type); ASSERT_EQ(kDaikin152Bits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Power: Off, Mode: 0 (Auto), Temp: 26C, Fan: 2 (UNKNOWN), Swing(V): Off, " + "Powerful: Off, Quiet: On, Econo: Off, Sensor: Off, Comfort: Off", + IRAcUtils::resultAcToString(&irsend.capture)); } // https://github.com/crankyoldgit/IRremoteESP8266/issues/873 @@ -2983,4 +2989,378 @@ TEST(TestDecodeDaikin152, SyntheticExample) { ASSERT_EQ(DAIKIN152, irsend.capture.decode_type); ASSERT_EQ(kDaikin152Bits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + + irsend.reset(); + // Data from: + // https://github.com/crankyoldgit/IRremoteESP8266/issues/873#issuecomment-525166905 + uint8_t expectedState2[kDaikin152StateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x31, 0x28, 0x00, 0x3F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x6F}; + irsend.sendDaikin152(expectedState2); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(DAIKIN152, irsend.capture.decode_type); + ASSERT_EQ(kDaikin152Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState2, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 1 (Low), Swing(V): On, " + "Powerful: Off, Quiet: Off, Econo: Off, Sensor: Off, Comfort: Off", + IRAcUtils::resultAcToString(&irsend.capture)); +} + +TEST(TestDaikin2ClassNew, Issue908) { + IRDaikin2 ac(0); + // https://docs.google.com/spreadsheets/d/1f8EGfIbBUo2B-CzUFdrgKQprWakoYNKM80IKZN4KXQE/edit#gid=236366525&range=I8 + uint8_t fanMedium[kDaikin2StateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x01, 0x4A, 0x42, 0xB0, 0x28, 0x0C, 0x80, 0x04, + 0xB0, 0x16, 0x24, 0x00, 0x00, 0xAA, 0xC3, 0x5E, 0x11, 0xDA, 0x27, 0x00, + 0x00, 0x09, 0x3C, 0x00, 0x50, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, + 0x90, 0x60, 0xBE}; + ac.setRaw(fanMedium); + EXPECT_EQ( + "Power: On, Mode: 0 (Auto), Temp: 30C, Fan: 3 (Medium), " + "Swing(V): 3 (UpperMiddle), Swing(H): 170 (UNKNOWN), Clock: 09:46, " + "On Timer: Off, Off Timer: Off, Sleep Timer: Off, Beep: 2 (Loud), " + "Light: 3 (Off), Mould: On, Clean: On, Fresh: Off, Eye: Off, " + "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off", + ac.toString()); + ASSERT_EQ(kDaikinFanMed, ac.getFan()); + ASSERT_EQ(stdAc::fanspeed_t::kMedium, ac.toCommon().fanspeed); + ASSERT_EQ(kDaikinFanMed, ac.convertFan(stdAc::fanspeed_t::kMedium)); + + // https://docs.google.com/spreadsheets/d/1f8EGfIbBUo2B-CzUFdrgKQprWakoYNKM80IKZN4KXQE/edit#gid=236366525&range=I17 + uint8_t swingvMiddle[kDaikin2StateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x01, 0x55, 0x42, 0xB0, 0x28, 0x0C, 0x80, 0x04, + 0xB0, 0x16, 0x24, 0x00, 0x00, 0xAA, 0xC3, 0x69, 0x11, 0xDA, 0x27, 0x00, + 0x00, 0x09, 0x3C, 0x00, 0xB0, 0x00, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, + 0x90, 0x60, 0x1E}; + ac.setRaw(swingvMiddle); + EXPECT_EQ( + "Power: On, Mode: 0 (Auto), Temp: 30C, Fan: 11 (Quiet), " + "Swing(V): 3 (UpperMiddle), Swing(H): 170 (UNKNOWN), Clock: 09:57, " + "On Timer: Off, Off Timer: Off, Sleep Timer: Off, Beep: 2 (Loud), " + "Light: 3 (Off), Mould: On, Clean: On, Fresh: Off, Eye: Off, " + "Eye Auto: Off, Quiet: Off, Powerful: Off, Purify: On, Econo: Off", + ac.toString()); + ASSERT_EQ(3, ac.getSwingVertical()); + ASSERT_EQ(stdAc::swingv_t::kMiddle, ac.toCommon().swingv); + ac.setSwingVertical(4); + ASSERT_EQ(4, ac.getSwingVertical()); + ASSERT_EQ(stdAc::swingv_t::kMiddle, ac.toCommon().swingv); + // Either 3 or 4 is fine as they both map to stdAc::swingv_t::kMiddle. + ASSERT_EQ(4, ac.convertSwingV(stdAc::swingv_t::kMiddle)); + // Native "swing" should convert to common's "auto". + ac.setSwingVertical(kDaikin2SwingVSwing); + ASSERT_EQ(kDaikin2SwingVSwing, ac.getSwingVertical()); + ASSERT_EQ(stdAc::swingv_t::kAuto, ac.toCommon().swingv); + ASSERT_EQ(kDaikin2SwingVSwing, ac.convertSwingV(stdAc::swingv_t::kAuto)); + // Native "auto" should convert to common's "off". + ac.setSwingVertical(kDaikin2SwingVAuto); + ASSERT_EQ(kDaikin2SwingVAuto, ac.getSwingVertical()); + ASSERT_EQ(stdAc::swingv_t::kOff, ac.toCommon().swingv); + ASSERT_EQ(kDaikin2SwingVAuto, ac.convertSwingV(stdAc::swingv_t::kOff)); +} + +// Tests for IRDaikin152 class. + +TEST(TestDaikin152Class, Power) { + IRDaikin152 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(TestDaikin152Class, Temperature) { + IRDaikin152 ac(0); + ac.begin(); + ac.setMode(kDaikinHeat); // Heat has the widest temp range. + ac.setTemp(0); + EXPECT_EQ(kDaikinMinTemp, ac.getTemp()); + + ac.setTemp(255); + EXPECT_EQ(kDaikinMaxTemp, ac.getTemp()); + + ac.setTemp(kDaikinMinTemp); + EXPECT_EQ(kDaikinMinTemp, ac.getTemp()); + + ac.setTemp(kDaikinMaxTemp); + EXPECT_EQ(kDaikinMaxTemp, ac.getTemp()); + + ac.setTemp(kDaikinMinTemp - 1); + EXPECT_EQ(kDaikinMinTemp, ac.getTemp()); + + ac.setTemp(kDaikinMaxTemp + 1); + EXPECT_EQ(kDaikinMaxTemp, ac.getTemp()); + + ac.setTemp(kDaikinMinTemp + 1); + EXPECT_EQ(kDaikinMinTemp + 1, 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()); + + // Special temps. + ac.setTemp(kDaikin152FanTemp); + EXPECT_EQ(kDaikin152FanTemp, ac.getTemp()); +} + +TEST(TestDaikin152Class, OperatingMode) { + IRDaikin152 ac(0); + ac.begin(); + + ac.setMode(kDaikinAuto); + EXPECT_EQ(kDaikinAuto, ac.getMode()); + + ac.setTemp(25); + + ac.setMode(kDaikinCool); + EXPECT_EQ(kDaikinCool, ac.getMode()); + + ac.setMode(kDaikinHeat); + EXPECT_EQ(kDaikinHeat, ac.getMode()); + + ac.setMode(kDaikinFan); + EXPECT_EQ(kDaikinFan, ac.getMode()); + EXPECT_EQ(kDaikin152FanTemp, ac.getTemp()); + + ac.setMode(kDaikinDry); + EXPECT_EQ(kDaikinDry, ac.getMode()); + EXPECT_EQ(kDaikin152DryTemp, ac.getTemp()); + + ac.setMode(kDaikinFan + 1); + EXPECT_EQ(kDaikinAuto, ac.getMode()); + + ac.setMode(kDaikinAuto + 1); + EXPECT_EQ(kDaikinAuto, ac.getMode()); + + ac.setMode(255); + EXPECT_EQ(kDaikinAuto, ac.getMode()); +} + +TEST(TestDaikin152Class, Swing) { + IRDaikin152 ac(0); + ac.begin(); + + ac.setSwingV(false); + EXPECT_FALSE(ac.getSwingV()); + + ac.setSwingV(true); + EXPECT_TRUE(ac.getSwingV()); + + ac.setSwingV(false); + EXPECT_FALSE(ac.getSwingV()); +} + +TEST(TestDaikin152Class, QuietMode) { + IRDaikin152 ac(0); + ac.begin(); + + ac.setQuiet(true); + EXPECT_TRUE(ac.getQuiet()); + + ac.setQuiet(false); + EXPECT_FALSE(ac.getQuiet()); + + ac.setQuiet(true); + EXPECT_TRUE(ac.getQuiet()); + + // Setting Econo mode should NOT change out of quiet mode. + ac.setEcono(true); + EXPECT_TRUE(ac.getQuiet()); + ac.setEcono(false); + EXPECT_TRUE(ac.getQuiet()); + + // But setting Powerful mode should exit out of quiet mode. + ac.setPowerful(true); + EXPECT_FALSE(ac.getQuiet()); +} + +TEST(TestDaikin152Class, PowerfulMode) { + IRDaikin152 ac(0); + ac.begin(); + + ac.setPowerful(true); + EXPECT_TRUE(ac.getPowerful()); + + ac.setPowerful(false); + EXPECT_FALSE(ac.getPowerful()); + + ac.setPowerful(true); + EXPECT_TRUE(ac.getPowerful()); + + ac.setQuiet(true); + EXPECT_FALSE(ac.getPowerful()); + + ac.setPowerful(true); + ac.setEcono(true); + EXPECT_FALSE(ac.getPowerful()); +} + +TEST(TestDaikin152Class, EconoMode) { + IRDaikin152 ac(0); + ac.begin(); + + ac.setEcono(true); + EXPECT_TRUE(ac.getEcono()); + + ac.setEcono(false); + EXPECT_FALSE(ac.getEcono()); + + ac.setEcono(true); + EXPECT_TRUE(ac.getEcono()); + + // Setting Quiet mode should NOT change out of Econo mode. + ac.setQuiet(true); + EXPECT_TRUE(ac.getEcono()); + ac.setQuiet(false); + EXPECT_TRUE(ac.getEcono()); + + // But setting Powerful mode should exit out of Econo mode. + ac.setPowerful(true); + EXPECT_FALSE(ac.getEcono()); +} + +TEST(TestDaikin152Class, FanSpeed) { + IRDaikin152 ac(0); + ac.begin(); + + // Unexpected value should default to Auto. + ac.setFan(0); + EXPECT_EQ(kDaikinFanAuto, ac.getFan()); + + // Unexpected value should default to Auto. + ac.setFan(255); + EXPECT_EQ(kDaikinFanAuto, ac.getFan()); + + ac.setFan(kDaikinFanMax); + EXPECT_EQ(kDaikinFanMax, ac.getFan()); + + // Beyond Max should default to Auto. + ac.setFan(kDaikinFanMax + 1); + EXPECT_EQ(kDaikinFanAuto, ac.getFan()); + + ac.setFan(kDaikinFanMax - 1); + EXPECT_EQ(kDaikinFanMax - 1, ac.getFan()); + + ac.setFan(kDaikinFanMin); + EXPECT_EQ(kDaikinFanMin, ac.getFan()); + + ac.setFan(kDaikinFanMin + 1); + EXPECT_EQ(kDaikinFanMin + 1, ac.getFan()); + + // Beyond Min should default to Auto. + ac.setFan(kDaikinFanMin - 1); + EXPECT_EQ(kDaikinFanAuto, ac.getFan()); + + ac.setFan(3); + EXPECT_EQ(3, ac.getFan()); + + ac.setFan(kDaikinFanAuto); + EXPECT_EQ(kDaikinFanAuto, ac.getFan()); + + ac.setFan(kDaikinFanQuiet); + EXPECT_EQ(kDaikinFanQuiet, ac.getFan()); +} + +TEST(TestDaikin152Class, Comfort) { + IRDaikin152 ac(0); + ac.begin(); + + // Comfort mode should change these settings. + ac.setSwingV(true); + ac.setFan(kDaikinFanMax); + ac.setPowerful(true); + + ac.setComfort(false); + ASSERT_FALSE(ac.getComfort()); + + ac.setComfort(true); + ASSERT_TRUE(ac.getComfort()); + ASSERT_FALSE(ac.getSwingV()); + ASSERT_FALSE(ac.getPowerful()); + ASSERT_EQ(kDaikinFanAuto, ac.getFan()); + + ac.setComfort(false); + ASSERT_FALSE(ac.getComfort()); +} + +TEST(TestDaikin152Class, toCommon) { + IRDaikin152 ac(0); + ac.setPower(true); + ac.setMode(kDaikinCool); + ac.setTemp(20); + ac.setFan(kDaikinFanMax); + ac.setSwingV(true); + ac.setQuiet(false); + ac.setPowerful(true); + ac.setEcono(false); + // Now test it. + ASSERT_EQ(decode_type_t::DAIKIN152, ac.toCommon().protocol); + ASSERT_EQ(-1, ac.toCommon().model); + ASSERT_TRUE(ac.toCommon().power); + ASSERT_TRUE(ac.toCommon().celsius); + ASSERT_EQ(20, ac.toCommon().degrees); + ASSERT_TRUE(ac.toCommon().turbo); + ASSERT_FALSE(ac.toCommon().quiet); + ASSERT_FALSE(ac.toCommon().econo); + ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon().mode); + ASSERT_EQ(stdAc::fanspeed_t::kMax, ac.toCommon().fanspeed); + ASSERT_EQ(stdAc::swingv_t::kAuto, ac.toCommon().swingv); + // Unsupported. + ASSERT_EQ(stdAc::swingh_t::kOff, ac.toCommon().swingh); + ASSERT_FALSE(ac.toCommon().filter); + ASSERT_FALSE(ac.toCommon().clean); + ASSERT_FALSE(ac.toCommon().light); + ASSERT_FALSE(ac.toCommon().beep); + ASSERT_EQ(-1, ac.toCommon().sleep); + ASSERT_EQ(-1, ac.toCommon().clock); +} + +TEST(TestDaikin152Class, convertFan) { + EXPECT_EQ(kDaikinFanQuiet, IRDaikin152::convertFan(stdAc::fanspeed_t::kMin)); + EXPECT_EQ(kDaikinFanMin, IRDaikin152::convertFan(stdAc::fanspeed_t::kLow)); + EXPECT_EQ(kDaikinFanMed, + IRDaikin152::convertFan(stdAc::fanspeed_t::kMedium)); + EXPECT_EQ(kDaikinFanMax - 1, + IRDaikin152::convertFan(stdAc::fanspeed_t::kHigh)); + EXPECT_EQ(kDaikinFanMax, IRDaikin152::convertFan(stdAc::fanspeed_t::kMax)); + EXPECT_EQ(kDaikinFanAuto, + IRDaikin152::convertFan(stdAc::fanspeed_t::kAuto)); +} + +TEST(TestDaikin152Class, BuildKnownState) { + IRDaikin152 ac(0); + ac.setPower(true); + ac.setMode(kDaikinCool); + ac.setTemp(20); + ac.setFan(kDaikinFanMin); + ac.setSwingV(true); + ac.setQuiet(false); + ac.setPowerful(false); + ac.setEcono(false); + ac.setSensor(false); + ac.setComfort(false); + EXPECT_EQ( + "Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 1 (Low), Swing(V): On, " + "Powerful: Off, Quiet: Off, Econo: Off, Sensor: Off, Comfort: Off", + ac.toString()); + uint8_t expectedState[kDaikin152StateLength] = { + 0x11, 0xDA, 0x27, 0x00, 0x00, 0x31, 0x28, 0x00, 0x3F, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x00, 0x00, 0x6F}; + EXPECT_STATE_EQ(expectedState, ac.getRaw(), kDaikin152Bits); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Denon_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Denon_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Denon_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Denon_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Dish_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Dish_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Dish_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Dish_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Electra_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Electra_test.cpp old mode 100755 new mode 100644 similarity index 97% rename from lib/IRremoteESP8266-2.6.5/test/ir_Electra_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Electra_test.cpp index 581d40561..43ea456c6 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Electra_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Electra_test.cpp @@ -100,7 +100,7 @@ TEST(TestDecodeElectraAC, RealExampleDecode) { ASSERT_EQ(kElectraAcBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 3 (Low), " + "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), " "Swing(V): Off, Swing(H): Off", IRAcUtils::resultAcToString(&irsend.capture)); } @@ -231,20 +231,20 @@ TEST(TestIRElectraAcClass, HumanReadable) { 0x00, 0x00, 0x20, 0x00, 0x40, 0x8A}; ac.setRaw(on_cool_32C_auto_voff); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 32C, Fan: 5 (Auto), " + "Power: On, Mode: 1 (Cool), Temp: 32C, Fan: 5 (Auto), " "Swing(V): Off, Swing(H): Off", ac.toString()); uint8_t on_cool_16C_auto_voff[13] = { 0xC3, 0x47, 0xE0, 0x00, 0xA0, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x41, 0x0B}; ac.setRaw(on_cool_16C_auto_voff); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 16C, Fan: 5 (Auto), " + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 5 (Auto), " "Swing(V): Off, Swing(H): Off", ac.toString()); uint8_t on_cool_16C_low_voff[13] = { 0xC3, 0x47, 0xE0, 0x00, 0x60, 0x00, 0x20, 0x00, 0x00, 0x20, 0x00, 0x41, 0xCB}; ac.setRaw(on_cool_16C_low_voff); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 16C, Fan: 3 (Low), " + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 3 (Low), " "Swing(V): Off, Swing(H): Off", ac.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Fujitsu_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Fujitsu_test.cpp old mode 100755 new mode 100644 similarity index 81% rename from lib/IRremoteESP8266-2.6.5/test/ir_Fujitsu_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Fujitsu_test.cpp index b6613906f..2aead1e13 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Fujitsu_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Fujitsu_test.cpp @@ -21,8 +21,9 @@ TEST(TestIRFujitsuACClass, GetRawDefault) { 0x81, 0x01, 0x31, 0x00, 0x00, 0x00, 0x20, 0xFD}; EXPECT_STATE_EQ(expected_arrah2e, ac.getRaw(), 16 * 8); EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); - EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 1 (COOL), Temp: 24C, " - "Fan: 1 (High), Swing: Vert + Horiz, Command: N/A", + EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 1 (Cool), Temp: 24C, " + "Fan: 1 (High), Clean: Off, Filter: Off, " + "Swing: 3 (Swing(V)+Swing(H)), Command: N/A", ac.toString()); uint8_t expected_ardb1[15] = { @@ -31,7 +32,7 @@ TEST(TestIRFujitsuACClass, GetRawDefault) { ac.setModel(ARDB1); EXPECT_STATE_EQ(expected_ardb1, ac.getRaw(), 15 * 8); EXPECT_EQ(kFujitsuAcStateLength - 1, ac.getStateLength()); - EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (COOL), Temp: 24C, " + EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (Cool), Temp: 24C, " "Fan: 1 (High), Command: N/A", ac.toString()); } @@ -43,15 +44,16 @@ TEST(TestIRFujitsuACClass, GetRawTurnOff) { uint8_t expected_arrah2e[7] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x02, 0xFD}; EXPECT_STATE_EQ(expected_arrah2e, ac.getRaw(), 7 * 8); EXPECT_EQ(kFujitsuAcStateLengthShort, ac.getStateLength()); - EXPECT_EQ("Model: 1 (ARRAH2E), Power: Off, Mode: 1 (COOL), Temp: 24C, " - "Fan: 1 (High), Swing: Vert + Horiz, Command: N/A", + EXPECT_EQ("Model: 1 (ARRAH2E), Power: Off, Mode: 1 (Cool), Temp: 24C, " + "Fan: 1 (High), Clean: Off, Filter: Off, " + "Swing: 3 (Swing(V)+Swing(H)), Command: N/A", ac.toString()); ac.setModel(ARDB1); uint8_t expected_ardb1[6] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x02}; EXPECT_STATE_EQ(expected_ardb1, ac.getRaw(), 6 * 8); EXPECT_EQ(kFujitsuAcStateLengthShort - 1, ac.getStateLength()); - EXPECT_EQ("Model: 2 (ARDB1), Power: Off, Mode: 1 (COOL), Temp: 24C, " + EXPECT_EQ("Model: 2 (ARDB1), Power: Off, Mode: 1 (Cool), Temp: 24C, " "Fan: 1 (High), Command: N/A", ac.toString()); } @@ -63,8 +65,9 @@ TEST(TestIRFujitsuACClass, GetRawStepHoriz) { EXPECT_STATE_EQ(expected, ac.getRaw(), 7 * 8); EXPECT_EQ(kFujitsuAcStateLengthShort, ac.getStateLength()); EXPECT_EQ( - "Model: 1 (ARRAH2E), Power: On, Mode: 1 (COOL), Temp: 24C, " - "Fan: 1 (High), Swing: Vert + Horiz, Command: Step vane horizontally", + "Model: 1 (ARRAH2E), Power: On, Mode: 1 (Cool), Temp: 24C, " + "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 3 (Swing(V)+Swing(H)), " + "Command: Step Swing(H)", ac.toString()); } @@ -75,9 +78,11 @@ TEST(TestIRFujitsuACClass, GetRawStepVert) { uint8_t expected_arrah2e[7] = {0x14, 0x63, 0x0, 0x10, 0x10, 0x6C, 0x93}; EXPECT_STATE_EQ(expected_arrah2e, ac.getRaw(), 7 * 8); EXPECT_EQ(kFujitsuAcStateLengthShort, ac.getStateLength()); - EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 1 (COOL), Temp: 24C, " - "Fan: 1 (High), Swing: Vert + Horiz, Command: Step vane vertically", - ac.toString()); + EXPECT_EQ( + "Model: 1 (ARRAH2E), Power: On, Mode: 1 (Cool), Temp: 24C, " + "Fan: 1 (High), Clean: Off, Filter: Off, Swing: 3 (Swing(V)+Swing(H)), " + "Command: Step Swing(V)", + ac.toString()); ac.setModel(ARDB1); ac.stepVert(); @@ -85,8 +90,8 @@ TEST(TestIRFujitsuACClass, GetRawStepVert) { EXPECT_STATE_EQ(expected_ardb1, ac.getRaw(), 6 * 8); EXPECT_EQ(kFujitsuAcStateLengthShort - 1, ac.getStateLength()); - EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (COOL), Temp: 24C, " - "Fan: 1 (High), Command: Step vane vertically", + EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (Cool), Temp: 24C, " + "Fan: 1 (High), Command: Step Swing(V)", ac.toString()); } @@ -100,8 +105,9 @@ TEST(TestIRFujitsuACClass, GetRawWithSwingHoriz) { uint8_t expected[16] = {0x14, 0x63, 0x0, 0x10, 0x10, 0xFE, 0x9, 0x30, 0x90, 0x1, 0x24, 0x0, 0x0, 0x0, 0x20, 0xFB}; EXPECT_STATE_EQ(expected, ac.getRaw(), 16 * 8); - EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 1 (COOL), Temp: 25C, " - "Fan: 4 (Quiet), Swing: Horiz, Command: N/A", + EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 1 (Cool), Temp: 25C, " + "Fan: 4 (Quiet), Clean: Off, Filter: Off, " + "Swing: 2 (Swing(H)), Command: N/A", ac.toString()); } @@ -119,8 +125,10 @@ TEST(TestIRFujitsuACClass, GetRawWithFan) { 0x40, 0x03, 0x22, 0x00, 0x00, 0x00, 0x20, 0x4B}; EXPECT_STATE_EQ(expected_arrah2e, ac.getRaw(), 16 * 8); EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); - EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 3 (FAN), Temp: 20C, " - "Fan: 2 (Medium), Swing: Horiz, Command: N/A", ac.toString()); + EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 3 (Fan), Temp: 20C, " + "Fan: 2 (Medium), Clean: Off, Filter: Off, " + "Swing: 2 (Swing(H)), Command: N/A", + ac.toString()); ac.setModel(ARDB1); uint8_t expected_ardb1[15] = { @@ -128,7 +136,7 @@ TEST(TestIRFujitsuACClass, GetRawWithFan) { 0x40, 0x03, 0x02, 0x00, 0x00, 0x00, 0x8B}; EXPECT_EQ(kFujitsuAcStateLength - 1, ac.getStateLength()); EXPECT_STATE_EQ(expected_ardb1, ac.getRaw(), ac.getStateLength() * 8); - EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 3 (FAN), Temp: 20C, " + EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 3 (Fan), Temp: 20C, " "Fan: 2 (Medium), Command: N/A", ac.toString()); } @@ -140,8 +148,9 @@ TEST(TestIRFujitsuACClass, SetRaw) { 0x81, 0x01, 0x31, 0x00, 0x00, 0x00, 0x20, 0xFD}; EXPECT_STATE_EQ(expected_default_arrah2e, ac.getRaw(), ac.getStateLength() * 8); - EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 1 (COOL), Temp: 24C, " - "Fan: 1 (High), Swing: Vert + Horiz, Command: N/A", + EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 1 (Cool), Temp: 24C, " + "Fan: 1 (High), Clean: Off, Filter: Off, " + "Swing: 3 (Swing(V)+Swing(H)), Command: N/A", ac.toString()); // Now set a new state via setRaw(); // This state is a real state from an AR-DB1 remote. @@ -151,7 +160,7 @@ TEST(TestIRFujitsuACClass, SetRaw) { ac.setRaw(new_state1, kFujitsuAcStateLength - 1); EXPECT_EQ(kFujitsuAcStateLength - 1, ac.getStateLength()); EXPECT_STATE_EQ(new_state1, ac.getRaw(), ac.getStateLength() * 8); - EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (COOL), Temp: 19C, " + EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (Cool), Temp: 19C, " "Fan: 0 (Auto), Command: N/A", ac.toString()); } @@ -347,8 +356,10 @@ TEST(TestDecodeFujitsuAC, SyntheticLongMessages) { EXPECT_STATE_EQ(expected_arrah2e, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); - EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 1 (COOL), Temp: 18C, " - "Fan: 4 (Quiet), Swing: Vert, Command: N/A", ac.toString()); + EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 1 (Cool), Temp: 18C, " + "Fan: 4 (Quiet), Clean: Off, Filter: Off, " + "Swing: 1 (Swing(V)), Command: N/A", + ac.toString()); irsend.reset(); @@ -364,7 +375,7 @@ TEST(TestDecodeFujitsuAC, SyntheticLongMessages) { EXPECT_STATE_EQ(expected_ardb1, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ(kFujitsuAcStateLength - 1, ac.getStateLength()); - EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (COOL), Temp: 18C, " + EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (Cool), Temp: 18C, " "Fan: 4 (Quiet), Command: N/A", ac.toString()); } @@ -396,7 +407,7 @@ TEST(TestDecodeFujitsuAC, RealShortARDB1OffExample) { EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ(kFujitsuAcStateLengthShort - 1, ac.getStateLength()); - EXPECT_EQ("Model: 2 (ARDB1), Power: Off, Mode: 0 (AUTO), Temp: 16C, " + EXPECT_EQ("Model: 2 (ARDB1), Power: Off, Mode: 0 (Auto), Temp: 16C, " "Fan: 0 (Auto), Command: N/A", ac.toString()); } @@ -440,7 +451,7 @@ TEST(TestDecodeFujitsuAC, RealLongARDB1Example) { EXPECT_STATE_EQ(expected1, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ(kFujitsuAcStateLength - 1, ac.getStateLength()); - EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (COOL), Temp: 18C, " + EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (Cool), Temp: 18C, " "Fan: 4 (Quiet), Command: N/A", ac.toString()); irsend.reset(); @@ -477,7 +488,7 @@ TEST(TestDecodeFujitsuAC, RealLongARDB1Example) { EXPECT_STATE_EQ(expected2, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ(kFujitsuAcStateLength - 1, ac.getStateLength()); - EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (COOL), Temp: 19C, " + EXPECT_EQ("Model: 2 (ARDB1), Power: On, Mode: 1 (Cool), Temp: 19C, " "Fan: 0 (Auto), Command: N/A", ac.toString()); } @@ -519,8 +530,10 @@ TEST(TestDecodeFujitsuAC, Issue414) { EXPECT_STATE_EQ(state, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); - EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 4 (HEAT), Temp: 24C, " - "Fan: 0 (Auto), Swing: Off, Command: N/A", ac.toString()); + EXPECT_EQ( + "Model: 1 (ARRAH2E), Power: On, Mode: 4 (Heat), Temp: 24C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A", + ac.toString()); // Resend it using the state this time. irsend.reset(); @@ -594,8 +607,9 @@ TEST(TestIRFujitsuACClass, toCommon) { // Now test it. EXPECT_EQ( // Off mode technically has no temp, mode, fan, etc. - "Model: 1 (ARRAH2E), Power: Off, Mode: 0 (AUTO), Temp: 16C, " - "Fan: 0 (Auto), Swing: Off, Command: N/A", ac.toString()); + "Model: 1 (ARRAH2E), Power: Off, Mode: 0 (Auto), Temp: 16C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A", + ac.toString()); ASSERT_EQ(decode_type_t::FUJITSU_AC, ac.toCommon().protocol); ASSERT_EQ(fujitsu_ac_remote_model_t::ARRAH2E, ac.toCommon().model); ASSERT_FALSE(ac.toCommon().power); @@ -648,8 +662,9 @@ TEST(TestDecodeFujitsuAC, Issue716) { ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ(fujitsu_ac_remote_model_t::ARREB1E, ac.getModel()); EXPECT_EQ(kFujitsuAcStateLengthShort, ac.getStateLength()); - EXPECT_EQ("Model: 3 (ARREB1E), Power: On, Mode: 0 (AUTO), Temp: 16C, " - "Fan: 0 (Auto), Swing: Off, Command: Powerful, Outside Quiet: Off", + EXPECT_EQ("Model: 3 (ARREB1E), Power: On, Mode: 0 (Auto), Temp: 16C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), " + "Command: Powerful, Outside Quiet: Off", ac.toString()); // Economy (just from the state) @@ -662,8 +677,9 @@ TEST(TestDecodeFujitsuAC, Issue716) { ac.setRaw(econo, kFujitsuAcStateLengthShort); EXPECT_EQ(fujitsu_ac_remote_model_t::ARREB1E, ac.getModel()); EXPECT_EQ(kFujitsuAcStateLengthShort, ac.getStateLength()); - EXPECT_EQ("Model: 3 (ARREB1E), Power: On, Mode: 0 (AUTO), Temp: 16C, " - "Fan: 0 (Auto), Swing: Off, Command: Economy, Outside Quiet: Off", + EXPECT_EQ("Model: 3 (ARREB1E), Power: On, Mode: 0 (Auto), Temp: 16C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), " + "Command: Econo, Outside Quiet: Off", ac.toString()); } @@ -693,12 +709,14 @@ TEST(TestIRFujitsuACClass, OutsideQuiet) { // We can really only tell the difference between ARRAH2E & ARREB1E if // the option is set. Otheriwse they appear the same. EXPECT_EQ( - "Model: 1 (ARRAH2E), Power: On, Mode: 1 (COOL), Temp: 24C, " - "Fan: 0 (Auto), Swing: Off, Command: N/A", ac.toString()); + "Model: 1 (ARRAH2E), Power: On, Mode: 1 (Cool), Temp: 24C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), " + "Command: N/A", ac.toString()); ac.setModel(fujitsu_ac_remote_model_t::ARREB1E); EXPECT_EQ( - "Model: 3 (ARREB1E), Power: On, Mode: 1 (COOL), Temp: 24C, " - "Fan: 0 (Auto), Swing: Off, Command: N/A, Outside Quiet: Off", + "Model: 3 (ARREB1E), Power: On, Mode: 1 (Cool), Temp: 24C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), " + "Command: N/A, Outside Quiet: Off", ac.toString()); // Make sure we can't accidentally inherit the correct model. @@ -708,8 +726,9 @@ TEST(TestIRFujitsuACClass, OutsideQuiet) { EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); EXPECT_TRUE(ac.getOutsideQuiet()); EXPECT_EQ( - "Model: 3 (ARREB1E), Power: On, Mode: 1 (COOL), Temp: 24C, " - "Fan: 0 (Auto), Swing: Off, Command: N/A, Outside Quiet: On", + "Model: 3 (ARREB1E), Power: On, Mode: 1 (Cool), Temp: 24C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), " + "Command: N/A, Outside Quiet: On", ac.toString()); ac.setOutsideQuiet(false); @@ -756,8 +775,8 @@ TEST(TestIRFujitsuACClass, toggleSwing) { EXPECT_EQ(kFujitsuAcSwingBoth, ac.getSwing()); EXPECT_EQ( - "Model: 4 (ARJW2), Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 1 (High), " - "Command: Toggle horizontal swing", + "Model: 4 (ARJW2), Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 1 (High), " + "Command: Toggle Swing(H)", ac.toString()); // Test without the update set. @@ -792,7 +811,94 @@ TEST(TestDecodeFujitsuAC, Issue726) { ac.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ(fujitsu_ac_remote_model_t::ARRAH2E, ac.getModel()); EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); - EXPECT_EQ("Model: 1 (ARRAH2E), Power: On, Mode: 0 (AUTO), Temp: 24C, " - "Fan: 0 (Auto), Swing: Off, Command: N/A", - ac.toString()); + EXPECT_EQ( + "Model: 1 (ARRAH2E), Power: On, Mode: 0 (Auto), Temp: 24C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A", + ac.toString()); +} + +TEST(TestIRFujitsuACClass, Clean) { + IRFujitsuAC ac(0); + // Data from: + // https://docs.google.com/spreadsheets/d/1f8EGfIbBUo2B-CzUFdrgKQprWakoYNKM80IKZN4KXQE/edit#gid=646887633&range=A27:B30 + uint8_t clean_off[kFujitsuAcStateLength] = { + 0x14, 0x63, 0x00, 0x10, 0x10, 0xFE, 0x09, 0x30, + 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10}; + uint8_t clean_on[kFujitsuAcStateLength] = { + 0x14, 0x63, 0x00, 0x10, 0x10, 0xFE, 0x09, 0x30, + 0xA0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08}; + ac.setRaw(clean_on, kFujitsuAcStateLength); + EXPECT_TRUE(ac.getClean()); + EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); + EXPECT_EQ( + "Model: 5 (ARRY4), Power: On, Mode: 0 (Auto), Temp: 26C, " + "Fan: 0 (Auto), Clean: On, Filter: Off, Swing: 0 (Off), Command: N/A", + ac.toString()); + ac.setClean(false); + EXPECT_FALSE(ac.getClean()); + EXPECT_STATE_EQ(clean_off, ac.getRaw(), ac.getStateLength() * 8) + ac.setClean(true); + EXPECT_TRUE(ac.getClean()); + EXPECT_STATE_EQ(clean_on, ac.getRaw(), ac.getStateLength() * 8) + ac.setRaw(clean_off, kFujitsuAcStateLength); + EXPECT_FALSE(ac.getClean()); + EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); + EXPECT_EQ( + "Model: 1 (ARRAH2E), Power: On, Mode: 0 (Auto), Temp: 26C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A", + ac.toString()); + // Now it is in ARRAH2E model mode, it shouldn't accept setting it on. + ac.setClean(true); + EXPECT_EQ(fujitsu_ac_remote_model_t::ARRAH2E, ac.getModel()); + EXPECT_EQ( + "Model: 1 (ARRAH2E), Power: On, Mode: 0 (Auto), Temp: 26C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A", + ac.toString()); + // But ARRY4 does. + ac.setModel(fujitsu_ac_remote_model_t::ARRY4); + EXPECT_TRUE(ac.getClean()); + EXPECT_EQ( + "Model: 5 (ARRY4), Power: On, Mode: 0 (Auto), Temp: 26C, " + "Fan: 0 (Auto), Clean: On, Filter: Off, Swing: 0 (Off), Command: N/A", + ac.toString()); +} + +TEST(TestIRFujitsuACClass, Filter) { + IRFujitsuAC ac(0); + // Data from: + // https://docs.google.com/spreadsheets/d/1f8EGfIbBUo2B-CzUFdrgKQprWakoYNKM80IKZN4KXQE/edit#gid=646887633&range=A27:B30 + uint8_t filter_on[kFujitsuAcStateLength] = { + 0x14, 0x63, 0x00, 0x10, 0x10, 0xFE, 0x09, 0x30, + 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x07}; + uint8_t filter_off[kFujitsuAcStateLength] = { + 0x14, 0x63, 0x00, 0x10, 0x10, 0xFE, 0x09, 0x30, + 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10}; + ac.setRaw(filter_on, kFujitsuAcStateLength); + EXPECT_TRUE(ac.getFilter()); + EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); + EXPECT_EQ( + "Model: 5 (ARRY4), Power: On, Mode: 0 (Auto), Temp: 26C, " + "Fan: 0 (Auto), Clean: Off, Filter: On, Swing: 0 (Off), Command: N/A", + ac.toString()); + ac.setFilter(false); + EXPECT_FALSE(ac.getFilter()); + ac.setFilter(true); + EXPECT_TRUE(ac.getFilter()); + ac.setRaw(filter_off, kFujitsuAcStateLength); + EXPECT_FALSE(ac.getFilter()); + EXPECT_EQ(kFujitsuAcStateLength, ac.getStateLength()); + EXPECT_EQ( + "Model: 1 (ARRAH2E), Power: On, Mode: 0 (Auto), Temp: 26C, " + "Fan: 0 (Auto), Clean: Off, Filter: Off, Swing: 0 (Off), Command: N/A", + ac.toString()); + // Now it is in ARRAH2E model mode, it shouldn't accept setting it on. + ac.setFilter(true); + EXPECT_FALSE(ac.getFilter()); + // But ARRY4 does. + ac.setModel(fujitsu_ac_remote_model_t::ARRY4); + EXPECT_TRUE(ac.getFilter()); + EXPECT_EQ( + "Model: 5 (ARRY4), Power: On, Mode: 0 (Auto), Temp: 26C, " + "Fan: 0 (Auto), Clean: Off, Filter: On, Swing: 0 (Off), Command: N/A", + ac.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_GICable_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_GICable_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_GICable_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_GICable_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_GlobalCache_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_GlobalCache_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_GlobalCache_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_GlobalCache_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Goodweather_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Goodweather_test.cpp old mode 100755 new mode 100644 similarity index 93% rename from lib/IRremoteESP8266-2.6.5/test/ir_Goodweather_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Goodweather_test.cpp index 58f42f0fe..6345d2398 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Goodweather_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Goodweather_test.cpp @@ -24,20 +24,20 @@ TEST(TestSendGoodweather, SendDataOnly) { irsend.sendGoodweather(0x0); EXPECT_EQ( "f38000d50" - "m6800s6800" - "m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600" - "m640s580m640s580m640s580m640s580m640s580m640s580m640s580m640s580" - "m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600" - "m640s580m640s580m640s580m640s580m640s580m640s580m640s580m640s580" - "m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600" - "m640s580m640s580m640s580m640s580m640s580m640s580m640s580m640s580" - "m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600" - "m640s580m640s580m640s580m640s580m640s580m640s580m640s580m640s580" - "m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600" - "m640s580m640s580m640s580m640s580m640s580m640s580m640s580m640s580" - "m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600m640s1600" - "m640s580m640s580m640s580m640s580m640s580m640s580m640s580m640s580" - "m640s6800m640s100000", + "m6820s6820" + "m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860" + "m580s580m580s580m580s580m580s580m580s580m580s580m580s580m580s580" + "m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860" + "m580s580m580s580m580s580m580s580m580s580m580s580m580s580m580s580" + "m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860" + "m580s580m580s580m580s580m580s580m580s580m580s580m580s580m580s580" + "m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860" + "m580s580m580s580m580s580m580s580m580s580m580s580m580s580m580s580" + "m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860" + "m580s580m580s580m580s580m580s580m580s580m580s580m580s580m580s580" + "m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860m580s1860" + "m580s580m580s580m580s580m580s580m580s580m580s580m580s580m580s580" + "m580s6820m580s100000", irsend.outputStr()); irsend.reset(); @@ -113,7 +113,7 @@ TEST(TestDecodeGoodweather, RealExampleDecode) { EXPECT_FALSE(irsend.capture.repeat); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 20C, Fan: 3 (Low), " + "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 3 (Low), " "Turbo: -, Light: -, Sleep: -, Swing: 0 (Fast), Command: 0 (Power)", ac.toString()); @@ -146,7 +146,7 @@ uint16_t rawData_FAD2BE31[197] = { EXPECT_FALSE(irsend.capture.repeat); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Power: Off, Mode: 1 (COOL), Temp: 22C, Fan: 3 (Low), Turbo: -, " + "Power: Off, Mode: 1 (Cool), Temp: 22C, Fan: 3 (Low), Turbo: -, " "Light: -, Sleep: -, Swing: 2 (Off), Command: 0 (Power)", ac.toString()); @@ -179,7 +179,7 @@ uint16_t rawData_FAD2BE31[197] = { EXPECT_FALSE(irsend.capture.repeat); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 22C, Fan: 3 (Low), Turbo: -, " + "Power: On, Mode: 1 (Cool), Temp: 22C, Fan: 3 (Low), Turbo: -, " "Light: -, Sleep: -, Swing: 2 (Off), Command: 0 (Power)", ac.toString()); @@ -212,7 +212,7 @@ uint16_t rawData_FAD2BE31[197] = { EXPECT_FALSE(irsend.capture.repeat); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 3 (Low), Turbo: -, " + "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 3 (Low), Turbo: -, " "Light: -, Sleep: -, Swing: 2 (Off), Command: 2 (Temp Up)", ac.toString()); @@ -245,7 +245,7 @@ uint16_t rawData_FAD2BE31[197] = { EXPECT_FALSE(irsend.capture.repeat); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 23C, Fan: 3 (Low), " + "Power: On, Mode: 1 (Cool), Temp: 23C, Fan: 3 (Low), " "Turbo: -, Light: -, Sleep: -, Swing: 2 (Off), Command: 3 (Temp Down)", ac.toString()); @@ -278,7 +278,7 @@ uint16_t rawData_FAD2BE31[197] = { EXPECT_FALSE(irsend.capture.repeat); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 22C, Fan: 3 (Low), Turbo: -, Light: -, " + "Power: On, Mode: 1 (Cool), Temp: 22C, Fan: 3 (Low), Turbo: -, Light: -, " "Sleep: -, Swing: 1 (Slow), Command: 4 (Swing)", ac.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Gree_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Gree_test.cpp old mode 100755 new mode 100644 similarity index 97% rename from lib/IRremoteESP8266-2.6.5/test/ir_Gree_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Gree_test.cpp index d85df72b8..6c8672c77 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Gree_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Gree_test.cpp @@ -495,9 +495,9 @@ TEST(TestGreeClass, HumanReadable) { IRGreeAC irgree(0); EXPECT_EQ( - "Model: 1 (YAW1F), Power: Off, Mode: 0 (AUTO), Temp: 25C, Fan: 0 (Auto), " + "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 Vertical Mode: Manual, Swing Vertical Pos: 0 (Last Pos), " + "Swing(V) Mode: Manual, Swing(V): 0 (Last), " "Timer: Off", irgree.toString()); irgree.on(); @@ -513,9 +513,9 @@ TEST(TestGreeClass, HumanReadable) { irgree.setSwingVertical(true, kGreeSwingAuto); irgree.setTimer(12 * 60 + 30); EXPECT_EQ( - "Model: 1 (YAW1F), Power: On, Mode: 1 (COOL), Temp: 16C, Fan: 3 (High), " + "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 Vertical Mode: Auto, Swing Vertical Pos: 1 (Auto), Timer: 12:30", + "Swing(V) Mode: Auto, Swing(V): 1 (Auto), Timer: 12:30", irgree.toString()); } @@ -573,9 +573,9 @@ TEST(TestDecodeGree, NormalRealExample) { EXPECT_STATE_EQ(gree_code, irsend.capture.state, kGreeBits); irgree.setRaw(irsend.capture.state); EXPECT_EQ( - "Model: 1 (YAW1F), Power: On, Mode: 1 (COOL), Temp: 26C, Fan: 1 (Low), " + "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 Vertical Mode: Manual, Swing Vertical Pos: 2, Timer: Off", + "Swing(V) Mode: Manual, Swing(V): 2 (UNKNOWN), Timer: Off", irgree.toString()); } @@ -628,9 +628,9 @@ TEST(TestGreeClass, Issue814Power) { EXPECT_TRUE(ac.getPower()); 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), " + "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 Vertical Mode: Auto, Swing Vertical Pos: 1 (Auto), Timer: Off", + "Swing(V) Mode: Auto, Swing(V): 1 (Auto), Timer: Off", ac.toString()); ac.off(); EXPECT_STATE_EQ(off, ac.getRaw(), kGreeBits); diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Haier_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Haier_test.cpp old mode 100755 new mode 100644 similarity index 92% rename from lib/IRremoteESP8266-2.6.5/test/ir_Haier_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Haier_test.cpp index 03cc63f93..db824a28e --- a/lib/IRremoteESP8266-2.6.5/test/ir_Haier_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Haier_test.cpp @@ -131,6 +131,8 @@ TEST(TestHaierACClass, Command) { EXPECT_EQ(kHaierAcCmdSwing, haier.getCommand()); haier.setCommand(kHaierAcCmdOn); EXPECT_EQ(kHaierAcCmdOn, haier.getCommand()); + haier.setCommand(kHaierAcCmdOff); + EXPECT_EQ(kHaierAcCmdOff, haier.getCommand()); // Test unexpected values. haier.setCommand(0b00001110); @@ -347,50 +349,50 @@ TEST(TestHaierACClass, MessageConstuction) { IRHaierAC haier(0); EXPECT_EQ( - "Command: 1 (On), Mode: 0 (AUTO), Temp: 25C, Fan: 0 (Auto), " + "Command: 1 (On), Mode: 0 (Auto), Temp: 25C, Fan: 0 (Auto), " "Swing: 0 (Off), Sleep: Off, Health: Off, " - "Current Time: 00:00, On Timer: Off, Off Timer: Off", + "Clock: 00:00, On Timer: Off, Off Timer: Off", haier.toString()); haier.setMode(kHaierAcCool); haier.setTemp(21); haier.setFan(kHaierAcFanHigh); EXPECT_EQ( - "Command: 3 (Fan), Mode: 1 (COOL), Temp: 21C, Fan: 3 (High), " + "Command: 3 (Fan), Mode: 1 (Cool), Temp: 21C, Fan: 3 (High), " "Swing: 0 (Off), Sleep: Off, Health: Off, " - "Current Time: 00:00, On Timer: Off, Off Timer: Off", + "Clock: 00:00, On Timer: Off, Off Timer: Off", haier.toString()); haier.setSwing(kHaierAcSwingChg); haier.setHealth(true); haier.setSleep(true); haier.setCurrTime(615); // 10:15am EXPECT_EQ( - "Command: 8 (Sleep), Mode: 1 (COOL), Temp: 21C, Fan: 3 (High), " - "Swing: 3 (Chg), Sleep: On, Health: On, " - "Current Time: 10:15, On Timer: Off, Off Timer: Off", + "Command: 8 (Sleep), Mode: 1 (Cool), Temp: 21C, Fan: 3 (High), " + "Swing: 3 (Change), Sleep: On, Health: On, " + "Clock: 10:15, On Timer: Off, Off Timer: Off", haier.toString()); haier.setOnTimer(800); // 1:20pm haier.setOffTimer(1125); // 6:45pm haier.setCommand(kHaierAcCmdOn); EXPECT_EQ( - "Command: 1 (On), Mode: 1 (COOL), Temp: 21C, Fan: 2 (Medium), " - "Swing: 3 (Chg), Sleep: On, Health: On, " - "Current Time: 10:15, On Timer: 13:20, Off Timer: 18:45", + "Command: 1 (On), Mode: 1 (Cool), Temp: 21C, Fan: 2 (Medium), " + "Swing: 3 (Change), Sleep: On, Health: On, " + "Clock: 10:15, On Timer: 13:20, Off Timer: 18:45", haier.toString()); // Now change a few already set things. haier.setMode(kHaierAcHeat); EXPECT_EQ( - "Command: 2 (Mode), Mode: 3 (HEAT), Temp: 21C, Fan: 2 (Medium), " - "Swing: 3 (Chg), Sleep: On, Health: On, " - "Current Time: 10:15, On Timer: 13:20, Off Timer: 18:45", + "Command: 2 (Mode), Mode: 3 (Heat), Temp: 21C, Fan: 2 (Medium), " + "Swing: 3 (Change), Sleep: On, Health: On, " + "Clock: 10:15, On Timer: 13:20, Off Timer: 18:45", haier.toString()); haier.setTemp(25); EXPECT_EQ( - "Command: 6 (Temp Up), Mode: 3 (HEAT), Temp: 25C, Fan: 2 (Medium), " - "Swing: 3 (Chg), Sleep: On, Health: On, " - "Current Time: 10:15, On Timer: 13:20, Off Timer: 18:45", + "Command: 6 (Temp Up), Mode: 3 (Heat), Temp: 25C, Fan: 2 (Medium), " + "Swing: 3 (Change), Sleep: On, Health: On, " + "Clock: 10:15, On Timer: 13:20, Off Timer: 18:45", haier.toString()); uint8_t expectedState[kHaierACStateLength] = {0xA5, 0x96, 0xEA, 0xCF, 0x32, @@ -406,9 +408,9 @@ TEST(TestHaierACClass, MessageConstuction) { EXPECT_FALSE(IRHaierAC::validChecksum(randomState)); haier.setRaw(randomState); EXPECT_EQ( - "Command: 9 (Timer Set), Mode: 3 (HEAT), Temp: 20C, Fan: 2 (Medium), " + "Command: 9 (Timer Set), Mode: 3 (Heat), Temp: 20C, Fan: 2 (Medium), " "Swing: 1 (Up), Sleep: On, Health: Off, " - "Current Time: 16:32, On Timer: Off, Off Timer: Off", + "Clock: 16:32, On Timer: Off, Off Timer: Off", haier.toString()); // getRaw() should correct the checksum. EXPECT_TRUE(IRHaierAC::validChecksum(haier.getRaw())); @@ -670,16 +672,16 @@ TEST(TestHaierACYRW02Class, MessageConstuction) { IRHaierACYRW02 haier(0); EXPECT_EQ( - "Power: On, Button: 5 (Power), Mode: 0 (AUTO), Temp: 25C," - " Fan: 10 (Auto), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off," + "Power: On, Button: 5 (Power), Mode: 0 (Auto), Temp: 25C," + " Fan: 5 (Auto), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off," " Health: On", haier.toString()); haier.setMode(kHaierAcYrw02Cool); haier.setTemp(21); haier.setFan(kHaierAcYrw02FanHigh); EXPECT_EQ( - "Power: On, Button: 4 (Fan), Mode: 2 (COOL), Temp: 21C," - " Fan: 2 (High), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off," + "Power: On, Button: 4 (Fan), Mode: 1 (Cool), Temp: 21C," + " Fan: 1 (High), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off," " Health: On", haier.toString()); @@ -688,8 +690,8 @@ TEST(TestHaierACYRW02Class, MessageConstuction) { haier.setSleep(true); haier.setTurbo(kHaierAcYrw02TurboHigh); EXPECT_EQ( - "Power: On, Button: 8 (Turbo), Mode: 2 (COOL), Temp: 21C," - " Fan: 2 (High), Turbo: 1 (High), Swing: 2 (Middle)," + "Power: On, Button: 8 (Turbo), Mode: 1 (Cool), Temp: 21C," + " Fan: 1 (High), Turbo: 1 (High), Swing: 2 (Middle)," " Sleep: On, Health: Off", haier.toString()); } @@ -703,8 +705,8 @@ TEST(TestHaierACYRW02Class, RealStates) { IRHaierACYRW02 haier(0); haier.setRaw(expectedState1); EXPECT_EQ( - "Power: On, Button: 7 (Health), Mode: 8 (HEAT), Temp: 30C," - " Fan: 2 (High), Turbo: 0 (Off), Swing: 1 (Top), Sleep: Off," + "Power: On, Button: 7 (Health), Mode: 4 (Heat), Temp: 30C," + " Fan: 1 (High), Turbo: 0 (Off), Swing: 1 (Highest), Sleep: Off," " Health: Off", haier.toString()); @@ -713,8 +715,8 @@ TEST(TestHaierACYRW02Class, RealStates) { 0x80, 0x00, 0x00, 0x00, 0x00, 0x05, 0x75}; haier.setRaw(expectedState2); EXPECT_EQ( - "Power: Off, Button: 5 (Power), Mode: 8 (HEAT), Temp: 30C," - " Fan: 2 (High), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off," + "Power: Off, Button: 5 (Power), Mode: 4 (Heat), Temp: 30C," + " Fan: 1 (High), Turbo: 0 (Off), Swing: 0 (Off), Sleep: Off," " Health: Off", haier.toString()); @@ -723,8 +725,8 @@ TEST(TestHaierACYRW02Class, RealStates) { 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2B}; haier.setRaw(expectedState3); EXPECT_EQ( - "Power: On, Button: 1 (Temp Down), Mode: 2 (COOL), Temp: 16C," - " Fan: 2 (High), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off," + "Power: On, Button: 1 (Temp Down), Mode: 1 (Cool), Temp: 16C," + " Fan: 1 (High), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off," " Health: On", haier.toString()); @@ -734,8 +736,8 @@ TEST(TestHaierACYRW02Class, RealStates) { 0x20, 0x80, 0x00, 0x00, 0x00, 0x0B, 0xD7}; haier.setRaw(expectedState4); EXPECT_EQ( - "Power: On, Button: 11 (Sleep), Mode: 2 (COOL), Temp: 25C," - " Fan: 10 (Auto), Turbo: 0 (Off), Swing: 12 (Auto), Sleep: On," + "Power: On, Button: 11 (Sleep), Mode: 1 (Cool), Temp: 25C," + " Fan: 5 (Auto), Turbo: 0 (Off), Swing: 12 (Auto), Sleep: On," " Health: On", haier.toString()); @@ -745,8 +747,8 @@ TEST(TestHaierACYRW02Class, RealStates) { 0x20, 0x80, 0x00, 0x00, 0x00, 0x04, 0x85}; haier.setRaw(expectedState5); EXPECT_EQ( - "Power: On, Button: 4 (Fan), Mode: 2 (COOL), Temp: 25C," - " Fan: 2 (High), Turbo: 0 (Off), Swing: 12 (Auto), Sleep: On," + "Power: On, Button: 4 (Fan), Mode: 1 (Cool), Temp: 25C," + " Fan: 1 (High), Turbo: 0 (Off), Swing: 12 (Auto), Sleep: On," " Health: On", haier.toString()); } @@ -818,9 +820,9 @@ TEST(TestDecodeHaierAC, RealExample1) { IRHaierAC haier(0); haier.setRaw(irsend.capture.state); EXPECT_EQ( - "Command: 1 (On), Mode: 1 (COOL), Temp: 16C, Fan: 0 (Auto), " + "Command: 1 (On), Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), " "Swing: 0 (Off), Sleep: Off, Health: Off, " - "Current Time: 00:01, On Timer: Off, Off Timer: Off", + "Clock: 00:01, On Timer: Off, Off Timer: Off", haier.toString()); } @@ -860,9 +862,9 @@ TEST(TestDecodeHaierAC, RealExample2) { IRHaierAC haier(0); haier.setRaw(irsend.capture.state); EXPECT_EQ( - "Command: 6 (Temp Up), Mode: 1 (COOL), Temp: 22C, Fan: 0 (Auto), " + "Command: 6 (Temp Up), Mode: 1 (Cool), Temp: 22C, Fan: 0 (Auto), " "Swing: 0 (Off), Sleep: Off, Health: Off, " - "Current Time: 00:01, On Timer: Off, Off Timer: Off", + "Clock: 00:01, On Timer: Off, Off Timer: Off", haier.toString()); } @@ -902,9 +904,9 @@ TEST(TestDecodeHaierAC, RealExample3) { IRHaierAC haier(0); haier.setRaw(irsend.capture.state); EXPECT_EQ( - "Command: 12 (Health), Mode: 1 (COOL), Temp: 30C, Fan: 0 (Auto), " + "Command: 12 (Health), Mode: 1 (Cool), Temp: 30C, Fan: 0 (Auto), " "Swing: 0 (Off), Sleep: Off, Health: On, " - "Current Time: 00:09, On Timer: Off, Off Timer: Off", + "Clock: 00:09, On Timer: Off, Off Timer: Off", haier.toString()); } @@ -972,8 +974,8 @@ TEST(TestDecodeHaierAC_YRW02, RealExample) { IRHaierACYRW02 haier(0); haier.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Button: 5 (Power), Mode: 2 (COOL), Temp: 17C," - " Fan: 2 (High), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off," + "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 17C," + " Fan: 1 (High), Turbo: 0 (Off), Swing: 2 (Middle), Sleep: Off," " Health: On", haier.toString()); } @@ -989,8 +991,8 @@ TEST(TestHaierAcIssues, Issue668) { // Turn on the AC. ac._irsend.reset(); char expected_on[] = - "Command: 1 (On), Mode: 1 (COOL), Temp: 25C, Fan: 0 (Auto), " - "Swing: 0 (Off), Sleep: Off, Health: Off, Current Time: 00:00, " + "Command: 1 (On), Mode: 1 (Cool), Temp: 25C, Fan: 0 (Auto), " + "Swing: 0 (Off), Sleep: Off, Health: Off, Clock: 00:00, " "On Timer: Off, Off Timer: Off"; // State taken from real capture: // https://github.com/crankyoldgit/IRremoteESP8266/issues/668#issuecomment-483531895 @@ -1027,8 +1029,8 @@ TEST(TestHaierAcIssues, Issue668) { // Increase the temp by 1. ac._irsend.reset(); char expected_temp_plus_one[] = - "Command: 6 (Temp Up), Mode: 1 (COOL), Temp: 26C, Fan: 0 (Auto), " - "Swing: 0 (Off), Sleep: Off, Health: Off, Current Time: 00:00, " + "Command: 6 (Temp Up), Mode: 1 (Cool), Temp: 26C, Fan: 0 (Auto), " + "Swing: 0 (Off), Sleep: Off, Health: Off, Clock: 00:00, " "On Timer: Off, Off Timer: Off"; // State taken from real capture: // https://github.com/crankyoldgit/IRremoteESP8266/issues/668#issuecomment-483531895 @@ -1051,8 +1053,8 @@ TEST(TestHaierAcIssues, Issue668) { // Decrease the temp by 1. ac._irsend.reset(); char expected_temp_minus_one[] = - "Command: 7 (Temp Down), Mode: 1 (COOL), Temp: 25C, Fan: 0 (Auto), " - "Swing: 0 (Off), Sleep: Off, Health: Off, Current Time: 00:00, " + "Command: 7 (Temp Down), Mode: 1 (Cool), Temp: 25C, Fan: 0 (Auto), " + "Swing: 0 (Off), Sleep: Off, Health: Off, Clock: 00:00, " "On Timer: Off, Off Timer: Off"; ASSERT_EQ(26, ac.getTemp()); ac.setTemp(ac.getTemp() - 1); diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Hitachi_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Hitachi_test.cpp old mode 100755 new mode 100644 similarity index 74% rename from lib/IRremoteESP8266-2.6.5/test/ir_Hitachi_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Hitachi_test.cpp index 7e7935638..e84897dc8 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Hitachi_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Hitachi_test.cpp @@ -1,6 +1,7 @@ // Copyright 2018 David Conran #include "ir_Hitachi.h" +#include "IRac.h" #include "IRrecv.h" #include "IRrecv_test.h" #include "IRremoteESP8266.h" @@ -300,8 +301,8 @@ TEST(TestIRHitachiAcClass, HumanReadable) { ac.setFan(kHitachiAcFanHigh); ac.setSwingVertical(true); EXPECT_EQ( - "Power: On, Mode: 3 (HEAT), Temp: 32C, Fan: 5 (High), " - "Swing (Vertical): On, Swing (Horizontal): Off", + "Power: On, Mode: 3 (Heat), Temp: 32C, Fan: 5 (High), " + "Swing(V): On, Swing(H): Off", ac.toString()); ac.setMode(kHitachiAcCool); ac.setTemp(kHitachiAcMinTemp); @@ -309,8 +310,8 @@ TEST(TestIRHitachiAcClass, HumanReadable) { ac.setSwingVertical(false); ac.setSwingHorizontal(true); EXPECT_EQ( - "Power: On, Mode: 4 (COOL), Temp: 16C, Fan: 2 (Low), " - "Swing (Vertical): Off, Swing (Horizontal): On", + "Power: On, Mode: 4 (Cool), Temp: 16C, Fan: 2 (Low), " + "Swing(V): Off, Swing(H): On", ac.toString()); } @@ -428,8 +429,8 @@ TEST(TestDecodeHitachiAC, NormalRealExample1) { IRHitachiAc ac(0); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 4 (COOL), Temp: 16C, Fan: 1 (Auto), " - "Swing (Vertical): Off, Swing (Horizontal): Off", + "Power: On, Mode: 4 (Cool), Temp: 16C, Fan: 1 (Auto), " + "Swing(V): Off, Swing(H): Off", ac.toString()); } @@ -496,8 +497,8 @@ TEST(TestDecodeHitachiAC, NormalRealExample2) { IRHitachiAc ac(0); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 3 (HEAT), Temp: 32C, Fan: 5 (High), " - "Swing (Vertical): Off, Swing (Horizontal): Off", + "Power: On, Mode: 3 (Heat), Temp: 32C, Fan: 5 (High), " + "Swing(V): Off, Swing(H): Off", ac.toString()); } @@ -798,3 +799,300 @@ TEST(TestIRHitachiAcClass, toCommon) { ASSERT_EQ(-1, ac.toCommon().sleep); ASSERT_EQ(-1, ac.toCommon().clock); } + +TEST(TestUtils, Housekeeping) { + ASSERT_EQ("HITACHI_AC", typeToString(decode_type_t::HITACHI_AC)); + ASSERT_EQ(decode_type_t::HITACHI_AC, strToDecodeType("HITACHI_AC")); + ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC)); + + ASSERT_EQ("HITACHI_AC1", typeToString(decode_type_t::HITACHI_AC1)); + ASSERT_EQ(decode_type_t::HITACHI_AC1, strToDecodeType("HITACHI_AC1")); + ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC1)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC1)); + + ASSERT_EQ("HITACHI_AC2", typeToString(decode_type_t::HITACHI_AC2)); + ASSERT_EQ(decode_type_t::HITACHI_AC2, strToDecodeType("HITACHI_AC2")); + ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC2)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC2)); + + ASSERT_EQ("HITACHI_AC424", typeToString(decode_type_t::HITACHI_AC424)); + ASSERT_EQ(decode_type_t::HITACHI_AC424, strToDecodeType("HITACHI_AC424")); + ASSERT_TRUE(hasACState(decode_type_t::HITACHI_AC424)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::HITACHI_AC424)); +} + +// Decode a 'real' HitachiAc424 message. +TEST(TestDecodeHitachiAc424, RealExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + uint8_t expected[kHitachiAc424StateLength] = { + 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xCC, 0x33, 0x92, + 0x6D, 0x13, 0xEC, 0x5C, 0xA3, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x53, 0xAC, 0xF1, 0x0E, 0x00, + 0xFF, 0x00, 0xFF, 0x80, 0x7F, 0x03, 0xFC, 0x01, 0xFE, 0x88, + 0x77, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00}; + + // Ref: https://docs.google.com/spreadsheets/d/1TTRx7INyDlsJBn9UwebL2Q4Q0S0apq0DlKP6bfrVPQw/edit#gid=0&range=A2:B2 + uint16_t rawData[853] = { + // On Auto Cool 23 + 29784, 49290, 3416, 1604, 464, 1210, 468, 372, 460, 374, 462, 374, 466, + 368, 464, 372, 462, 374, 464, 374, 464, 368, 464, 370, 464, 370, 466, 370, + 464, 1208, 464, 374, 462, 372, 466, 374, 464, 370, 462, 372, 464, 370, + 466, 370, 464, 372, 462, 374, 462, 374, 462, 378, 460, 370, 460, 374, 464, + 372, 462, 372, 464, 374, 466, 368, 464, 1210, 464, 374, 466, 1202, 464, + 1206, 464, 1210, 466, 1206, 468, 1204, 464, 1210, 466, 370, 462, 1214, + 460, 1208, 464, 1206, 464, 1208, 466, 1208, 464, 1206, 466, 1208, 464, + 1206, 466, 1212, 464, 370, 464, 370, 462, 374, 462, 374, 462, 374, 462, + 374, 462, 372, 464, 376, 460, 372, 462, 374, 466, 1204, 464, 1210, 464, + 372, 460, 374, 462, 1208, 464, 1212, 464, 1202, 468, 1204, 464, 374, 460, + 374, 466, 1208, 462, 1210, 462, 374, 462, 376, 464, 368, 466, 1204, 462, + 374, 466, 372, 464, 1206, 462, 376, 460, 376, 464, 1210, 462, 1208, 462, + 372, 466, 1206, 464, 1208, 466, 372, 462, 1210, 462, 1210, 466, 374, 468, + 1202, 464, 1206, 466, 374, 462, 372, 464, 1208, 464, 374, 464, 372, 464, + 376, 462, 370, 466, 368, 464, 1208, 462, 1210, 460, 374, 464, 1208, 466, + 1206, 464, 1214, 464, 368, 462, 374, 462, 1212, 460, 1210, 466, 1206, 466, + 370, 462, 1210, 464, 416, 424, 1202, 466, 1220, 448, 376, 464, 372, 462, + 372, 462, 1212, 462, 374, 460, 1214, 468, 364, 468, 370, 462, 372, 462, + 376, 458, 374, 464, 372, 462, 376, 464, 376, 462, 1204, 464, 1210, 462, + 1210, 464, 1208, 466, 1208, 464, 1206, 462, 1210, 464, 1212, 464, 368, + 462, 372, 464, 372, 464, 372, 464, 372, 466, 370, 466, 370, 464, 376, + 464, 1202, 464, 1212, 464, 1204, 464, 1210, 462, 1208, 464, 1212, 462, + 1210, 464, 1212, 460, 372, 462, 374, 462, 374, 466, 370, 462, 374, 462, + 372, 464, 372, 462, 376, 462, 1206, 464, 1206, 466, 1210, 462, 1208, 464, + 1210, 466, 1204, 464, 1210, 462, 1214, 462, 368, 462, 374, 466, 370, 462, + 376, 466, 368, 466, 370, 462, 414, 424, 374, 464, 1206, 464, 1206, 464, + 1206, 468, 1206, 466, 1206, 466, 1210, 462, 1206, 464, 1214, 468, 364, + 466, 372, 466, 370, 462, 372, 462, 374, 464, 372, 462, 374, 460, 376, 466, + 1204, 464, 1208, 462, 1210, 464, 1206, 464, 1210, 464, 1208, 464, 1208, + 466, 1210, 462, 1206, 466, 1206, 466, 372, 462, 374, 466, 1206, 466, 370, + 464, 1206, 466, 376, 464, 368, 462, 372, 466, 1206, 464, 1206, 464, 374, + 466, 1204, 464, 374, 466, 1206, 466, 1204, 468, 368, 466, 370, 466, 370, + 462, 1212, 462, 1210, 462, 1210, 462, 1214, 464, 368, 464, 1206, 466, + 1206, 466, 1206, 464, 374, 464, 370, 466, 370, 462, 378, 466, 366, 464, + 372, 466, 368, 466, 370, 464, 370, 462, 372, 462, 374, 464, 374, 464, + 1202, 466, 1206, 462, 1208, 466, 1208, 466, 1208, 464, 1210, 462, 1206, + 464, 1212, 464, 368, 464, 372, 464, 370, 468, 368, 462, 376, 462, 372, + 466, 370, 464, 376, 462, 1206, 464, 1210, 462, 1212, 462, 1208, 464, 1208, + 462, 1212, 466, 1246, 424, 1212, 464, 368, 464, 372, 466, 370, 464, 372, + 462, 374, 464, 372, 464, 370, 462, 1212, 466, 1206, 462, 1206, 464, 1210, + 466, 1206, 462, 1208, 464, 1250, 422, 1208, 468, 372, 464, 1204, 466, + 1206, 466, 370, 462, 374, 462, 376, 460, 374, 466, 370, 462, 376, 464, + 368, 462, 376, 462, 1210, 462, 1208, 464, 1206, 466, 1206, 464, 1208, 468, + 1212, 460, 1206, 464, 372, 464, 372, 466, 370, 462, 374, 466, 370, 466, + 370, 466, 374, 464, 368, 462, 1210, 462, 1210, 464, 1210, 462, 1208, 462, + 1212, 464, 1206, 466, 1208, 466, 366, 464, 374, 460, 374, 462, 1208, 466, + 372, 462, 374, 462, 374, 464, 1212, 468, 1202, 464, 1208, 466, 1204, 464, + 376, 460, 1208, 468, 1208, 462, 1208, 464, 378, 460, 372, 460, 372, 462, + 376, 464, 372, 462, 374, 460, 374, 464, 370, 462, 378, 464, 1202, 468, + 1204, 468, 1204, 466, 1208, 466, 1208, 464, 1210, 460, 1212, 462, 1212, + 464, 366, 466, 370, 464, 372, 466, 370, 464, 372, 462, 414, 424, 372, 466, + 372, 460, 1206, 466, 1206, 466, 1206, 466, 1208, 466, 1206, 464, 1208, + 466, 1208, 462, 1212, 468, 1202, 466, 1204, 470, 1204, 468, 1204, 466, + 1206, 466, 1206, 464, 1210, 462, 1212, 468, 366, 464, 372, 462, 374, 460, + 374, 460, 374, 466, 410, 424, 372, 460, 378, 466, 1200, 464, 1212, 462, + 1210, 464, 1210, 466, 1206, 462, 1208, 464, 1210, 464, 1210, 464, 366, + 462, 376, 462, 374, 460, 376, 462, 372, 466, 374, 460, 372, 462, 378, 462, + 1202, 468, 1206, 464, 1208, 466, 1208, 462, 1208, 464, 1208, 468, 1204, + 464, 1212, 466, 368, 462, 374, 466, 372, 464, 370, 462, 374, 464, 370, + 462, 376, 464, 374, 462, 1206, 464, 1208, 462, 1210, 466, 1208, 460, 1210, + 468, 1206, 462, 1210, 464, 1212, 466, 366, 464, 374, 462, 372, 466, 370, + 462, 374, 464, 372, 464, 370, 464, 374, 462}; + + irsend.reset(); + irsend.sendRaw(rawData, 853, kHitachiAcFreq); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(HITACHI_AC424, irsend.capture.decode_type); + ASSERT_EQ(kHitachiAc424Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expected, irsend.capture.state, kHitachiAc424Bits); + IRHitachiAc ac(0); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: On, Mode: 3 (Cool), Temp: 23C, Fan: 5 (Auto)", + IRAcUtils::resultAcToString(&irsend.capture)); +} + +TEST(TestDecodeHitachiAc424, SyntheticExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + uint8_t expected[kHitachiAc424StateLength] = { + 0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xCC, 0x33, 0x92, + 0x6D, 0x13, 0xEC, 0x5C, 0xA3, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x53, 0xAC, 0xF1, 0x0E, 0x00, + 0xFF, 0x00, 0xFF, 0x80, 0x7F, 0x03, 0xFC, 0x01, 0xFE, 0x88, + 0x77, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xFF, 0x00}; + + irsend.reset(); + irsend.sendHitachiAc424(expected); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(HITACHI_AC424, irsend.capture.decode_type); + ASSERT_EQ(kHitachiAc424Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits); +} + +// Tests for IRHitachiAc424 class. +TEST(TestIRHitachiAc424Class, SetInvertedStates) { + IRHitachiAc424 ac(0); + + uint8_t raw[kHitachiAc424StateLength] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00}; + uint8_t expected[kHitachiAc424StateLength] = { + 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF}; + + ac.setRaw(raw); + EXPECT_STATE_EQ(expected, ac.getRaw(), kHitachiAc424Bits); +} + +TEST(TestIRHitachiAc424Class, SetAndGetPower) { + IRHitachiAc424 ac(0); + 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(TestIRHitachiAc424Class, SetAndGetTemp) { + IRHitachiAc424 ac(0); + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + ac.setTemp(kHitachiAc424MinTemp); + EXPECT_EQ(kHitachiAc424MinTemp, ac.getTemp()); + ac.setTemp(kHitachiAc424MinTemp - 1); + EXPECT_EQ(kHitachiAc424MinTemp, ac.getTemp()); + ac.setTemp(kHitachiAc424MaxTemp); + EXPECT_EQ(kHitachiAc424MaxTemp, ac.getTemp()); + ac.setTemp(kHitachiAc424MaxTemp + 1); + EXPECT_EQ(kHitachiAc424MaxTemp, ac.getTemp()); +} + +TEST(TestIRHitachiAc424Class, SetAndGetMode) { + IRHitachiAc424 ac(0); + ac.setMode(kHitachiAc424Cool); + ac.setFan(kHitachiAc424FanAuto); + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + EXPECT_EQ(kHitachiAc424Cool, ac.getMode()); + EXPECT_EQ(kHitachiAc424FanAuto, ac.getFan()); + ac.setMode(kHitachiAc424Fan); + EXPECT_EQ(kHitachiAc424Fan, ac.getMode()); + EXPECT_EQ(27, ac.getTemp()); + EXPECT_NE(kHitachiAc424FanAuto, ac.getFan()); + ac.setMode(kHitachiAc424Heat); + EXPECT_EQ(25, ac.getTemp()); + EXPECT_EQ(kHitachiAc424Heat, ac.getMode()); + ac.setMode(kHitachiAc424Dry); + EXPECT_EQ(kHitachiAc424Dry, ac.getMode()); + EXPECT_NE(kHitachiAc424FanAuto, ac.getFan()); +} + +TEST(TestIRHitachiAc424Class, SetAndGetFan) { + IRHitachiAc424 ac(0); + ac.setMode(kHitachiAc424Cool); // All fan options are available in this mode. + ac.setFan(kHitachiAc424FanAuto); + EXPECT_EQ(kHitachiAc424FanAuto, ac.getFan()); + ac.setFan(kHitachiAc424FanLow); + EXPECT_EQ(kHitachiAc424FanLow, ac.getFan()); + ac.setFan(kHitachiAc424FanHigh); + EXPECT_EQ(kHitachiAc424FanHigh, ac.getFan()); + ac.setFan(kHitachiAc424FanMax + 1); + EXPECT_EQ(kHitachiAc424FanMax, ac.getFan()); + ac.setFan(kHitachiAc424FanMin - 1); + EXPECT_EQ(kHitachiAc424FanMin, ac.getFan()); + + ac.setFan(kHitachiAc424FanAuto); + ac.setMode(kHitachiAc424Fan); // No auto-fan in Fan mode. + EXPECT_EQ(kHitachiAc424FanMin, ac.getFan()); + ac.setFan(kHitachiAc424FanMax); + EXPECT_EQ(kHitachiAc424FanMax, ac.getFan()); + + // Only min, low and auto fan settings in Dry mode. + ac.setMode(kHitachiAc424Dry); + EXPECT_EQ(kHitachiAc424FanLow, ac.getFan()); + ac.setFan(kHitachiAc424FanHigh); + EXPECT_EQ(kHitachiAc424FanLow, ac.getFan()); + ac.setFan(kHitachiAc424FanMin); + EXPECT_EQ(kHitachiAc424FanMin, ac.getFan()); + ac.setFan(kHitachiAc424FanAuto); + EXPECT_EQ(kHitachiAc424FanAuto, ac.getFan()); + + // Check additional bytes set by min & max fan + ac.setMode(kHitachiAc424Cool); + ac.setFan(kHitachiAc424FanMax); + EXPECT_EQ(ac.getRaw()[9], 0xA9); + EXPECT_EQ(ac.getRaw()[29], 0x30); + ac.setFan(kHitachiAc424FanMin); + EXPECT_EQ(ac.getRaw()[9], 0x98); + EXPECT_EQ(ac.getRaw()[29], 0x00); + ac.setFan(kHitachiAc424FanLow); + EXPECT_EQ(ac.getRaw()[9], 0x92); + EXPECT_EQ(ac.getRaw()[29], 0x00); +} + +TEST(TestIRHitachiAc424Class, HumanReadable) { + IRHitachiAc424 ac(0); + + ac.setMode(kHitachiAc424Heat); + ac.setTemp(kHitachiAc424MaxTemp); + ac.on(); + ac.setFan(kHitachiAc424FanHigh); + EXPECT_EQ( + "Power: On, Mode: 6 (Heat), Temp: 32C, Fan: 4 (High)", + ac.toString()); + ac.setMode(kHitachiAc424Cool); + ac.setTemp(kHitachiAc424MinTemp); + ac.setFan(kHitachiAc424FanMin); + EXPECT_EQ( + "Power: On, Mode: 3 (Cool), Temp: 16C, Fan: 1 (Min)", + ac.toString()); +} + +TEST(TestIRHitachiAcClass424, toCommon) { + IRHitachiAc424 ac(0); + ac.setPower(true); + ac.setMode(kHitachiAc424Cool); + ac.setTemp(20); + ac.setFan(kHitachiAc424FanMax); + // Now test it. + ASSERT_EQ(decode_type_t::HITACHI_AC424, ac.toCommon().protocol); + ASSERT_EQ(-1, ac.toCommon().model); + ASSERT_TRUE(ac.toCommon().power); + ASSERT_TRUE(ac.toCommon().celsius); + ASSERT_EQ(20, ac.toCommon().degrees); + ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon().mode); + ASSERT_EQ(stdAc::fanspeed_t::kMax, ac.toCommon().fanspeed); + // TODO(jamsinclair): Add support. + 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().clean); + ASSERT_FALSE(ac.toCommon().light); + ASSERT_FALSE(ac.toCommon().quiet); + ASSERT_FALSE(ac.toCommon().econo); + ASSERT_FALSE(ac.toCommon().filter); + ASSERT_FALSE(ac.toCommon().beep); + ASSERT_EQ(-1, ac.toCommon().sleep); + ASSERT_EQ(-1, ac.toCommon().clock); +} diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Inax_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Inax_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Inax_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Inax_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_JVC_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_JVC_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_JVC_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_JVC_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Kelvinator_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Kelvinator_test.cpp old mode 100755 new mode 100644 similarity index 98% rename from lib/IRremoteESP8266-2.6.5/test/ir_Kelvinator_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Kelvinator_test.cpp index 436336c04..e01a585bd --- a/lib/IRremoteESP8266-2.6.5/test/ir_Kelvinator_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Kelvinator_test.cpp @@ -422,9 +422,9 @@ TEST(TestKelvinatorClass, HumanReadable) { IRKelvinatorAC irkelv(0); EXPECT_EQ( - "Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (Auto), Turbo: Off, " - "Quiet: Off, XFan: Off, IonFilter: Off, Light: Off, " - "Swing (Horizontal): Off, Swing (Vertical): Off", + "Power: Off, Mode: 0 (Auto), Temp: 16C, Fan: 0 (Auto), Turbo: Off, " + "Quiet: Off, XFan: Off, Ion: Off, Light: Off, " + "Swing(H): Off, Swing(V): Off", irkelv.toString()); irkelv.on(); irkelv.setMode(kKelvinatorCool); @@ -435,9 +435,9 @@ TEST(TestKelvinatorClass, HumanReadable) { irkelv.setLight(true); irkelv.setSwingHorizontal(true); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 25C, Fan: 5 (High), Turbo: Off, " - "Quiet: Off, XFan: On, IonFilter: On, Light: On, " - "Swing (Horizontal): On, Swing (Vertical): Off", + "Power: On, Mode: 1 (Cool), Temp: 25C, Fan: 5 (High), Turbo: Off, " + "Quiet: Off, XFan: On, Ion: On, Light: On, " + "Swing(H): On, Swing(V): Off", irkelv.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_LG_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_LG_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_LG_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_LG_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Lasertag_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Lasertag_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Lasertag_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Lasertag_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Lego_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Lego_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Lego_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Lego_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Lutron_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Lutron_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Lutron_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Lutron_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_MWM_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_MWM_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_MWM_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_MWM_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Magiquest_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Magiquest_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Magiquest_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Magiquest_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Midea_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Midea_test.cpp old mode 100755 new mode 100644 similarity index 94% rename from lib/IRremoteESP8266-2.6.5/test/ir_Midea_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Midea_test.cpp index 319528e9c..ebe291048 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Midea_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Midea_test.cpp @@ -445,7 +445,7 @@ TEST(TestMideaACClass, HumanReadableOutput) { ac.setRaw(0xA1826FFFFF62); EXPECT_EQ( - "Power: On, Mode: 2 (AUTO), Celsius: Off, Temp: 25C/77F, Fan: 0 (Auto), " + "Power: On, Mode: 2 (Auto), Celsius: Off, Temp: 25C/77F, Fan: 0 (Auto), " "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); ac.off(); ac.setTemp(25, true); @@ -453,16 +453,16 @@ TEST(TestMideaACClass, HumanReadableOutput) { ac.setMode(kMideaACDry); ac.setSleep(true); EXPECT_EQ( - "Power: Off, Mode: 1 (DRY), Celsius: Off, Temp: 25C/77F, Fan: 3 (High), " + "Power: Off, Mode: 1 (Dry), Celsius: Off, Temp: 25C/77F, Fan: 3 (High), " "Sleep: On, Swing(V) Toggle: Off", ac.toString()); ac.setUseCelsius(true); EXPECT_EQ( - "Power: Off, Mode: 1 (DRY), Celsius: On, Temp: 25C/77F, Fan: 3 (High), " + "Power: Off, Mode: 1 (Dry), Celsius: On, Temp: 25C/77F, Fan: 3 (High), " "Sleep: On, Swing(V) Toggle: Off", ac.toString()); ac.setRaw(0xA19867FFFF7E); EXPECT_EQ( - "Power: On, Mode: 0 (COOL), Celsius: Off, Temp: 21C/69F, Fan: 3 (High), " + "Power: On, Mode: 0 (Cool), Celsius: Off, Temp: 21C/69F, Fan: 3 (High), " "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); } @@ -705,13 +705,13 @@ TEST(TestMideaACClass, CelsiusRemoteTemp) { EXPECT_TRUE(ac.getUseCelsius()); EXPECT_EQ(on_cool_low_17c, ac.getRaw()); EXPECT_EQ( - "Power: On, Mode: 0 (COOL), Celsius: On, Temp: 17C/62F, Fan: 1 (Low), " + "Power: On, Mode: 0 (Cool), Celsius: On, Temp: 17C/62F, Fan: 1 (Low), " "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); ac.setRaw(on_cool_low_17c); EXPECT_EQ(17, ac.getTemp(true)); EXPECT_EQ(62, ac.getTemp(false)); EXPECT_EQ( - "Power: On, Mode: 0 (COOL), Celsius: On, Temp: 17C/62F, Fan: 1 (Low), " + "Power: On, Mode: 0 (Cool), Celsius: On, Temp: 17C/62F, Fan: 1 (Low), " "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); ac.setTemp(17, true); EXPECT_EQ(17, ac.getTemp(true)); @@ -720,7 +720,7 @@ TEST(TestMideaACClass, CelsiusRemoteTemp) { ac.setRaw(on_cool_low_30c); EXPECT_EQ( - "Power: On, Mode: 0 (COOL), Celsius: On, Temp: 30C/86F, Fan: 1 (Low), " + "Power: On, Mode: 0 (Cool), Celsius: On, Temp: 30C/86F, Fan: 1 (Low), " "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); } @@ -732,13 +732,44 @@ TEST(TestMideaACClass, SwingV) { ac.setSwingVToggle(true); ASSERT_TRUE(ac.getSwingVToggle()); EXPECT_EQ( - "Power: On, Mode: 2 (AUTO), Celsius: Off, Temp: 25C/77F, Fan: 0 (Auto), " + "Power: On, Mode: 2 (Auto), Celsius: Off, Temp: 25C/77F, Fan: 0 (Auto), " "Sleep: Off, Swing(V) Toggle: On", ac.toString()); ac.setSwingVToggle(false); ASSERT_FALSE(ac.getSwingVToggle()); EXPECT_EQ( - "Power: On, Mode: 2 (AUTO), Celsius: Off, Temp: 25C/77F, Fan: 0 (Auto), " + "Power: On, Mode: 2 (Auto), Celsius: Off, Temp: 25C/77F, Fan: 0 (Auto), " "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); ac.setRaw(kMideaACToggleSwingV); EXPECT_EQ("Swing(V) Toggle: On", ac.toString()); } + +// Test abusing the protocol for sending 6 arbitary bytes. +// See https://github.com/crankyoldgit/IRremoteESP8266/issues/887 +TEST(TestDecodeMidea, Issue887) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + irsend.reset(); + + uint64_t hwaddr = 0x1234567890AB; // 48bits doen't conform to Midea checksum + + irsend.sendMidea(hwaddr); + irsend.makeDecodeResult(); + + // Test normal operation, it shouldn't match. + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_NE(MIDEA, irsend.capture.decode_type); + irsend.reset(); + irsend.sendMidea(hwaddr); + irsend.makeDecodeResult(); + EXPECT_FALSE(irrecv.decodeMidea(&irsend.capture)); + + // Now test it with Midea's strict processing turned off! + irsend.reset(); + irsend.sendMidea(hwaddr); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decodeMidea(&irsend.capture, kMideaBits, false)); + EXPECT_EQ(MIDEA, irsend.capture.decode_type); + EXPECT_EQ(kMideaBits, irsend.capture.bits); + EXPECT_EQ(hwaddr, irsend.capture.value); +} diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_MitsubishiHeavy_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_MitsubishiHeavy_test.cpp old mode 100755 new mode 100644 similarity index 91% rename from lib/IRremoteESP8266-2.6.5/test/ir_MitsubishiHeavy_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_MitsubishiHeavy_test.cpp index 0af6b5d07..a8226feb8 --- a/lib/IRremoteESP8266-2.6.5/test/ir_MitsubishiHeavy_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_MitsubishiHeavy_test.cpp @@ -293,8 +293,8 @@ TEST(TestMitsubishiHeavy152AcClass, HumanReadable) { IRMitsubishiHeavy152Ac ac(0); EXPECT_EQ( - "Power: Off, Mode: 0 (AUTO), Temp: 17C, Fan: 0 (Auto), " - "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, " + "Power: Off, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), " + "Swing(V): 0 (Auto), Swing(H): 0 (Auto), Silent: Off, Turbo: Off, " "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off", ac.toString()); ac.on(); @@ -310,8 +310,8 @@ TEST(TestMitsubishiHeavy152AcClass, HumanReadable) { ac.setSwingVertical(kMitsubishiHeavy152SwingVAuto); ac.setSwingHorizontal(kMitsubishiHeavy152SwingHAuto); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 17C, Fan: 4 (Max), " - "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: On, Turbo: Off, " + "Power: On, Mode: 1 (Cool), Temp: 17C, Fan: 4 (Max), " + "Swing(V): 0 (Auto), Swing(H): 0 (Auto), Silent: On, Turbo: Off, " "Econo: Off, Night: On, Filter: On, 3D: On, Clean: Off", ac.toString()); @@ -327,8 +327,8 @@ TEST(TestMitsubishiHeavy152AcClass, HumanReadable) { ac.setSwingHorizontal(kMitsubishiHeavy152SwingHLeftMax); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 31C, Fan: 8 (Turbo), " - "Swing (V): 5 (Lowest), Swing (H): 1 (Max Left), Silent: Off, Turbo: On, " + "Power: On, Mode: 4 (Heat), Temp: 31C, Fan: 8 (Turbo), " + "Swing(V): 5 (Lowest), Swing(H): 1 (Max Left), Silent: Off, Turbo: On, " "Econo: Off, Night: Off, Filter: On, 3D: Off, Clean: Off", ac.toString()); @@ -338,8 +338,8 @@ TEST(TestMitsubishiHeavy152AcClass, HumanReadable) { ac.setSwingVertical(kMitsubishiHeavy152SwingVOff); EXPECT_EQ( - "Power: On, Mode: 0 (AUTO), Temp: 31C, Fan: 6 (Econo), " - "Swing (V): 6 (Off), Swing (H): 1 (Max Left), Silent: Off, " + "Power: On, Mode: 0 (Auto), Temp: 31C, Fan: 6 (Econo), " + "Swing(V): 6 (Off), Swing(H): 1 (Max Left), Silent: Off, " "Turbo: Off, Econo: On, Night: Off, Filter: On, 3D: Off, Clean: On", ac.toString()); @@ -349,8 +349,8 @@ TEST(TestMitsubishiHeavy152AcClass, HumanReadable) { ac.setMode(kMitsubishiHeavyDry); ac.setSwingHorizontal(kMitsubishiHeavy152SwingHLeftRight); EXPECT_EQ( - "Power: On, Mode: 2 (DRY), Temp: 25C, Fan: 0 (Auto), " - "Swing (V): 6 (Off), Swing (H): 7 (Left Right), Silent: Off, " + "Power: On, Mode: 2 (Dry), Temp: 25C, Fan: 0 (Auto), " + "Swing(V): 6 (Off), Swing(H): 7 (Left Right), Silent: Off, " "Turbo: Off, Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off", ac.toString()); } @@ -359,8 +359,8 @@ TEST(TestMitsubishiHeavy152AcClass, ReconstructKnownExample) { IRMitsubishiHeavy152Ac ac(0); EXPECT_EQ( - "Power: Off, Mode: 0 (AUTO), Temp: 17C, Fan: 0 (Auto), " - "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, " + "Power: Off, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), " + "Swing(V): 0 (Auto), Swing(H): 0 (Auto), Silent: Off, Turbo: Off, " "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off", ac.toString()); ac.on(); @@ -377,8 +377,8 @@ TEST(TestMitsubishiHeavy152AcClass, ReconstructKnownExample) { ac.setSwingVertical(kMitsubishiHeavy152SwingVAuto); ac.setSwingHorizontal(kMitsubishiHeavy152SwingHAuto); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 24C, Fan: 4 (Max), " - "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, " + "Power: On, Mode: 4 (Heat), Temp: 24C, Fan: 4 (Max), " + "Swing(V): 0 (Auto), Swing(H): 0 (Auto), Silent: Off, Turbo: Off, " "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off", ac.toString()); @@ -572,10 +572,10 @@ TEST(TestMitsubishiHeavy88AcClass, VerticalSwing) { ac.setSwingVertical(kMitsubishiHeavy88SwingVOff); EXPECT_EQ(kMitsubishiHeavy88SwingVOff, ac.getSwingVertical()); - ac.setSwingVertical(kMitsubishiHeavy88SwingVHighest + 1); + ac.setSwingVertical(kMitsubishiHeavy88SwingVLowest + 1); EXPECT_EQ(kMitsubishiHeavy88SwingVOff, ac.getSwingVertical()); - ac.setSwingVertical(kMitsubishiHeavy88SwingVOff + 1); + ac.setSwingVertical(kMitsubishiHeavy88SwingVHigh + 1); EXPECT_EQ(kMitsubishiHeavy88SwingVOff, ac.getSwingVertical()); // Out of bounds. @@ -592,19 +592,19 @@ TEST(TestMitsubishiHeavy88AcClass, HorizontalSwing) { ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftMax); EXPECT_EQ(kMitsubishiHeavy88SwingHLeftMax, ac.getSwingHorizontal()); - ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftMax + 1); + ac.setSwingHorizontal(kMitsubishiHeavy88SwingHRightMax + 1); EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal()); ac.setSwingHorizontal(kMitsubishiHeavy88SwingHRightMax); EXPECT_EQ(kMitsubishiHeavy88SwingHRightMax, ac.getSwingHorizontal()); - ac.setSwingHorizontal(kMitsubishiHeavy88SwingHRightMax - 1); + ac.setSwingHorizontal(kMitsubishiHeavy88SwingHRightMax + 1); EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal()); ac.setSwingHorizontal(kMitsubishiHeavy88SwingHOff); EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal()); - ac.setSwingHorizontal(kMitsubishiHeavy88SwingHOff + 1); + ac.setSwingHorizontal(kMitsubishiHeavy88SwingH3D + 1); EXPECT_EQ(kMitsubishiHeavy88SwingHOff, ac.getSwingHorizontal()); // Out of bounds. @@ -635,8 +635,8 @@ TEST(TestMitsubishiHeavy88AcClass, HumanReadable) { IRMitsubishiHeavy88Ac ac(0); EXPECT_EQ( - "Power: Off, Mode: 0 (AUTO), Temp: 17C, Fan: 0 (Auto), " - "Swing (V): 0 (Off), Swing (H): 0 (Off), " + "Power: Off, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto), " + "Swing(V): 0 (Off), Swing(H): 0 (Off), " "Turbo: Off, Econo: Off, 3D: Off, Clean: Off", ac.toString()); ac.on(); @@ -648,8 +648,8 @@ TEST(TestMitsubishiHeavy88AcClass, HumanReadable) { ac.set3D(true); ac.setSwingVertical(kMitsubishiHeavy88SwingVAuto); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 17C, Fan: 4 (High), " - "Swing (V): 16 (Auto), Swing (H): 200 (3D), " + "Power: On, Mode: 1 (Cool), Temp: 17C, Fan: 4 (High), " + "Swing(V): 4 (Auto), Swing(H): 14 (3D), " "Turbo: Off, Econo: Off, 3D: On, Clean: Off", ac.toString()); @@ -662,8 +662,8 @@ TEST(TestMitsubishiHeavy88AcClass, HumanReadable) { ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftMax); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 31C, Fan: 6 (Turbo), " - "Swing (V): 26 (Lowest), Swing (H): 4 (Max Left), Turbo: On, Econo: Off, " + "Power: On, Mode: 4 (Heat), Temp: 31C, Fan: 6 (Turbo), " + "Swing(V): 7 (Lowest), Swing(H): 1 (Max Left), Turbo: On, Econo: Off, " "3D: Off, Clean: Off", ac.toString()); @@ -673,8 +673,8 @@ TEST(TestMitsubishiHeavy88AcClass, HumanReadable) { ac.setSwingVertical(kMitsubishiHeavy88SwingVOff); EXPECT_EQ( - "Power: On, Mode: 0 (AUTO), Temp: 31C, Fan: 7 (Econo), " - "Swing (V): 0 (Off), Swing (H): 4 (Max Left), Turbo: Off, Econo: On, " + "Power: On, Mode: 0 (Auto), Temp: 31C, Fan: 7 (Econo), " + "Swing(V): 0 (Off), Swing(H): 1 (Max Left), Turbo: Off, Econo: On, " "3D: Off, Clean: On", ac.toString()); @@ -684,8 +684,8 @@ TEST(TestMitsubishiHeavy88AcClass, HumanReadable) { ac.setMode(kMitsubishiHeavyDry); ac.setSwingHorizontal(kMitsubishiHeavy88SwingHLeftRight); EXPECT_EQ( - "Power: On, Mode: 2 (DRY), Temp: 25C, Fan: 0 (Auto), " - "Swing (V): 0 (Off), Swing (H): 72 (Left Right), Turbo: Off, Econo: Off, " + "Power: On, Mode: 2 (Dry), Temp: 25C, Fan: 0 (Auto), " + "Swing(V): 0 (Off), Swing(H): 6 (Left Right), Turbo: Off, Econo: Off, " "3D: Off, Clean: Off", ac.toString()); } @@ -739,8 +739,8 @@ TEST(TestDecodeMitsubishiHeavy, ZmsRealExample) { EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 24C, Fan: 4 (Max), " - "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, " + "Power: On, Mode: 4 (Heat), Temp: 24C, Fan: 4 (Max), " + "Swing(V): 0 (Auto), Swing(H): 0 (Auto), Silent: Off, Turbo: Off, " "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off", ac.toString()); } @@ -766,8 +766,8 @@ TEST(TestDecodeMitsubishiHeavy, ZmsSyntheticExample) { EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 24C, Fan: 4 (Max), " - "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, " + "Power: On, Mode: 4 (Heat), Temp: 24C, Fan: 4 (Max), " + "Swing(V): 0 (Auto), Swing(H): 0 (Auto), Silent: Off, Turbo: Off, " "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off", ac.toString()); } @@ -819,8 +819,8 @@ TEST(TestDecodeMitsubishiHeavy, ZmsRealExample2) { EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: Off, Mode: 4 (HEAT), Temp: 24C, Fan: 4 (Max), " - "Swing (V): 0 (Auto), Swing (H): 0 (Auto), Silent: Off, Turbo: Off, " + "Power: Off, Mode: 4 (Heat), Temp: 24C, Fan: 4 (Max), " + "Swing(V): 0 (Auto), Swing(H): 0 (Auto), Silent: Off, Turbo: Off, " "Econo: Off, Night: Off, Filter: Off, 3D: Off, Clean: Off", ac.toString()); } @@ -844,8 +844,8 @@ TEST(TestDecodeMitsubishiHeavy, ZjsSyntheticExample) { EXPECT_STATE_EQ(expected, irsend.capture.state, irsend.capture.bits); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 2 (DRY), Temp: 25C, Fan: 0 (Auto), " - "Swing (V): 0 (Off), Swing (H): 72 (Left Right), Turbo: Off, Econo: Off, " + "Power: On, Mode: 2 (Dry), Temp: 25C, Fan: 0 (Auto), " + "Swing(V): 0 (Off), Swing(H): 6 (Left Right), Turbo: Off, Econo: Off, " "3D: Off, Clean: Off", ac.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Mitsubishi_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Mitsubishi_test.cpp old mode 100755 new mode 100644 similarity index 72% rename from lib/IRremoteESP8266-2.6.5/test/ir_Mitsubishi_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Mitsubishi_test.cpp index 7d16ed91e..8236777b5 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Mitsubishi_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Mitsubishi_test.cpp @@ -1,7 +1,9 @@ -// Copyright 2017 David Conran +// Copyright 2017-2019 David Conran +// Copyright 2019 kuchel77 // Copyright 2018 denxhun #include "ir_Mitsubishi.h" +#include "IRac.h" #include "IRrecv_test.h" #include "IRsend.h" #include "IRsend_test.h" @@ -984,8 +986,9 @@ TEST(TestDecodeMitsubishiAC, DecodeRealExampleRepeatNeededButError) { TEST(TestMitsubishiACClass, HumanReadable) { IRMitsubishiAC irMitsu(0); EXPECT_EQ( - "Power: On, Mode: 8 (HEAT), Temp: 22C, Fan: 6 (Quiet), Vane: AUTO, " - "Wide Vane: 3, Time: 17:10, On timer: 00:00, Off timer: 00:00, Timer: -", + "Power: On, Mode: 1 (Heat), Temp: 22C, Fan: 6 (Quiet), " + "Swing(V): 0 (Auto), Swing(H): 3 (UNKNOWN), " + "Clock: 17:10, On Timer: 00:00, Off Timer: 00:00, Timer: -", irMitsu.toString()); } @@ -1163,3 +1166,559 @@ TEST(TestMitsubishiACClass, toCommon) { ASSERT_EQ(-1, ac.toCommon().sleep); ASSERT_EQ(-1, ac.toCommon().clock); } + +// Decode a 'real' example. +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/888 +TEST(TestDecodeMitsubishi136, DecodeRealExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + // Mitsubishi Electric Ducted A/C - ON, 20C, Cooling, MaxFan. + uint16_t rawData[275] = { + 3324, 1474, 520, 1110, 492, 1110, 524, 314, 498, 318, 466, 336, 474, 1124, + 514, 322, 464, 338, 472, 1124, 516, 1112, 482, 342, 480, 1118, 488, 338, + 466, 344, 480, 1124, 480, 1124, 510, 328, 484, 1114, 480, 1132, 510, 330, + 456, 344, 464, 1134, 506, 334, 452, 346, 462, 1136, 504, 336, 450, 348, + 460, 350, 472, 338, 474, 1124, 472, 352, 472, 340, 474, 342, 446, 354, + 454, 354, 468, 344, 470, 344, 442, 356, 450, 358, 466, 346, 466, 348, 440, + 360, 448, 360, 462, 350, 464, 352, 438, 360, 434, 1162, 490, 350, 438, + 1148, 486, 350, 464, 352, 436, 362, 432, 376, 462, 352, 462, 1138, 448, + 376, 460, 1142, 462, 1150, 484, 1140, 462, 360, 446, 1152, 492, 1132, 460, + 362, 466, 348, 466, 348, 438, 360, 446, 1152, 492, 348, 436, 360, 434, + 374, 462, 350, 464, 350, 436, 362, 434, 376, 460, 352, 462, 352, 434, 364, + 432, 378, 458, 354, 460, 356, 434, 364, 430, 380, 456, 356, 458, 356, 432, + 366, 428, 382, 454, 358, 456, 358, 430, 1158, 476, 1146, 458, 1156, 478, + 1150, 454, 1154, 480, 1142, 460, 362, 434, 1164, 488, 352, 436, 1148, 488, + 1140, 462, 1144, 490, 1136, 466, 1142, 492, 346, 466, 1132, 462, 360, 466, + 348, 466, 350, 438, 1152, 482, 348, 464, 350, 438, 1144, 490, 1142, 462, + 1148, 486, 1138, 466, 354, 450, 1146, 496, 1132, 460, 1150, 494, 1130, + 464, 1146, 498, 1130, 464, 1144, 498, 1130, 462, 1144, 500, 1126, 468, + 1142, 502, 1122, 470, 1142, 502, 1130, 464, 1140, 504, 1124, 468, 1140, + 504, 1122, 472, 1142, 502, 1122, 472, 1138, 506}; // UNKNOWN 66B4490E + + irsend.sendRaw(rawData, 275, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(MITSUBISHI136, irsend.capture.decode_type); + EXPECT_EQ(kMitsubishi136Bits, irsend.capture.bits); + uint8_t expected[kMitsubishi136StateLength] = { + 0x23, 0xCB, 0x26, 0x21, 0x00, 0x40, 0x41, 0x37, 0x04, + 0x00, 0x00, 0xBF, 0xBE, 0xC8, 0xFB, 0xFF, 0xFF}; + EXPECT_STATE_EQ(expected, irsend.capture.state, kMitsubishi136Bits); + EXPECT_EQ( + "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 3 (High), " + "Swing(V): 3 (Highest), Quiet: Off", + IRAcUtils::resultAcToString(&irsend.capture)); +} + +// Self decode a synthetic example. +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/888 +TEST(TestDecodeMitsubishi136, SyntheticExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + // Mitsubishi Electric Ducted A/C - ON, 20C, Cooling, MaxFan. + uint8_t expected[kMitsubishi136StateLength] = { + 0x23, 0xCB, 0x26, 0x21, 0x00, 0x40, 0x41, 0x37, 0x04, + 0x00, 0x00, 0xBF, 0xBE, 0xC8, 0xFB, 0xFF, 0xFF}; + + irsend.sendMitsubishi136(expected); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(MITSUBISHI136, irsend.capture.decode_type); + EXPECT_EQ(kMitsubishi136Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expected, irsend.capture.state, kMitsubishi136Bits); +} + +// General housekeeping +TEST(TestMitsubishi, Housekeeping) { + ASSERT_EQ("MITSUBISHI", typeToString(decode_type_t::MITSUBISHI)); + ASSERT_FALSE(hasACState(decode_type_t::MITSUBISHI)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::MITSUBISHI)); + + ASSERT_EQ("MITSUBISHI2", typeToString(decode_type_t::MITSUBISHI2)); + ASSERT_FALSE(hasACState(decode_type_t::MITSUBISHI2)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::MITSUBISHI2)); + + ASSERT_EQ("MITSUBISHI_AC", typeToString(decode_type_t::MITSUBISHI_AC)); + ASSERT_TRUE(hasACState(decode_type_t::MITSUBISHI_AC)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::MITSUBISHI_AC)); + + ASSERT_EQ("MITSUBISHI136", typeToString(decode_type_t::MITSUBISHI136)); + ASSERT_TRUE(hasACState(decode_type_t::MITSUBISHI136)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::MITSUBISHI136)); +} + +// Tests for IRMitsubishi136 class. + +TEST(TestMitsubishi136Class, Power) { + IRMitsubishi136 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(TestMitsubishi136Class, Temperature) { + IRMitsubishi136 ac(0); + ac.begin(); + + ac.setTemp(0); + EXPECT_EQ(kMitsubishi136MinTemp, ac.getTemp()); + + ac.setTemp(255); + EXPECT_EQ(kMitsubishi136MaxTemp, ac.getTemp()); + + ac.setTemp(kMitsubishi136MinTemp); + EXPECT_EQ(kMitsubishi136MinTemp, ac.getTemp()); + + ac.setTemp(kMitsubishi136MaxTemp); + EXPECT_EQ(kMitsubishi136MaxTemp, ac.getTemp()); + + ac.setTemp(kMitsubishi136MinTemp - 1); + EXPECT_EQ(kMitsubishi136MinTemp, ac.getTemp()); + + ac.setTemp(kMitsubishi136MaxTemp + 1); + EXPECT_EQ(kMitsubishi136MaxTemp, ac.getTemp()); + + ac.setTemp(19); + EXPECT_EQ(19, 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(TestMitsubishi136Class, OperatingMode) { + IRMitsubishi136 ac(0); + ac.begin(); + + ac.setMode(kMitsubishi136Auto); + EXPECT_EQ(kMitsubishi136Auto, ac.getMode()); + + ac.setMode(kMitsubishi136Fan); + EXPECT_EQ(kMitsubishi136Fan, ac.getMode()); + + ac.setMode(kMitsubishi136Cool); + EXPECT_EQ(kMitsubishi136Cool, ac.getMode()); + + ac.setMode(kMitsubishi136Heat); + EXPECT_EQ(kMitsubishi136Heat, ac.getMode()); + + ac.setMode(kMitsubishi136Dry); + EXPECT_EQ(kMitsubishi136Dry, ac.getMode()); + + ac.setMode(kMitsubishi136Dry + 1); + EXPECT_EQ(kMitsubishi136Auto, ac.getMode()); + + ac.setMode(255); + EXPECT_EQ(kMitsubishi136Auto, ac.getMode()); +} + +TEST(TestMitsubishi136Class, FanSpeed) { + IRMitsubishi136 ac(0); + ac.begin(); + + ac.setFan(kMitsubishi136FanMax); + EXPECT_EQ(kMitsubishi136FanMax, ac.getFan()); + + ac.setFan(kMitsubishi136FanMin); + EXPECT_EQ(kMitsubishi136FanMin, ac.getFan()); + + ac.setFan(255); + EXPECT_EQ(kMitsubishi136FanMax, ac.getFan()); + + ac.setFan(kMitsubishi136FanMed); + EXPECT_EQ(kMitsubishi136FanMed, ac.getFan()); + + ac.setFan(kMitsubishi136FanLow); + EXPECT_EQ(kMitsubishi136FanLow, ac.getFan()); + + ac.setFan(kMitsubishi136FanQuiet); + EXPECT_EQ(kMitsubishi136FanQuiet, ac.getFan()); +} + +TEST(TestMitsubishi136Class, Quiet) { + IRMitsubishi136 ac(0); + ac.begin(); + + ac.setQuiet(true); + EXPECT_TRUE(ac.getQuiet()); + ac.setQuiet(false); + EXPECT_FALSE(ac.getQuiet()); + ac.setQuiet(true); + EXPECT_TRUE(ac.getQuiet()); +} + +TEST(TestMitsubishi136Class, SwingV) { + IRMitsubishi136 ac(0); + ac.begin(); + + ac.setSwingV(kMitsubishi136SwingVAuto); + EXPECT_EQ(kMitsubishi136SwingVAuto, ac.getSwingV()); + + ac.setSwingV(kMitsubishi136SwingVAuto + 1); + EXPECT_EQ(kMitsubishi136SwingVAuto, ac.getSwingV()); + + ac.setSwingV(kMitsubishi136SwingVLowest); + EXPECT_EQ(kMitsubishi136SwingVLowest, ac.getSwingV()); + + ac.setSwingV(kMitsubishi136SwingVLow); + EXPECT_EQ(kMitsubishi136SwingVLow, ac.getSwingV()); + + ac.setSwingV(kMitsubishi136SwingVHighest); + EXPECT_EQ(kMitsubishi136SwingVHighest, ac.getSwingV()); + + ac.setSwingV(kMitsubishi136SwingVHigh); + EXPECT_EQ(kMitsubishi136SwingVHigh, ac.getSwingV()); +} + +TEST(TestMitsubishi136Class, toCommon) { + IRMitsubishi136 ac(0); + ac.setPower(true); + ac.setMode(kMitsubishi136Dry); + ac.setTemp(22); + ac.setFan(kMitsubishi136FanQuiet); + ac.setSwingV(kMitsubishi136SwingVAuto); + // Now test it. + ASSERT_EQ(decode_type_t::MITSUBISHI136, ac.toCommon().protocol); + ASSERT_EQ(-1, ac.toCommon().model); + ASSERT_TRUE(ac.toCommon().power); + ASSERT_TRUE(ac.toCommon().celsius); + ASSERT_EQ(22, ac.toCommon().degrees); + ASSERT_EQ(stdAc::opmode_t::kDry, ac.toCommon().mode); + ASSERT_EQ(stdAc::fanspeed_t::kMin, ac.toCommon().fanspeed); + ASSERT_EQ(stdAc::swingv_t::kAuto, ac.toCommon().swingv); + ASSERT_TRUE(ac.toCommon().quiet); + // Unsupported. + ASSERT_EQ(stdAc::swingh_t::kOff, ac.toCommon().swingh); + ASSERT_FALSE(ac.toCommon().turbo); + ASSERT_FALSE(ac.toCommon().clean); + ASSERT_FALSE(ac.toCommon().light); + ASSERT_FALSE(ac.toCommon().econo); + ASSERT_FALSE(ac.toCommon().filter); + ASSERT_FALSE(ac.toCommon().beep); + ASSERT_EQ(-1, ac.toCommon().sleep); + ASSERT_EQ(-1, ac.toCommon().clock); +} + +TEST(TestMitsubishi136Class, toCommonMode) { + ASSERT_EQ(stdAc::opmode_t::kCool, + IRMitsubishi136::toCommonMode(kMitsubishi136Cool)); + ASSERT_EQ(kMitsubishi136Cool, + IRMitsubishi136::convertMode(stdAc::opmode_t::kCool)); + ASSERT_EQ(stdAc::opmode_t::kDry, + IRMitsubishi136::toCommonMode(kMitsubishi136Dry)); + ASSERT_EQ(kMitsubishi136Dry, + IRMitsubishi136::convertMode(stdAc::opmode_t::kDry)); +} + +// https://github.com/crankyoldgit/IRremoteESP8266/issues/891#issuecomment-531484295 +TEST(TestDecodeMitsubishiAC, Issue891) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + uint16_t rawData[583] = { + 3418, 1742, 386, 1342, 398, 1324, 366, 498, 342, 524, 384, 482, 366, 1354, + 340, 528, 366, 500, 396, 1328, 366, 1354, 340, 522, 340, 1384, 342, 528, + 366, 496, 340, 1382, 398, 1324, 386, 482, 338, 1386, 420, 1320, 340, 526, + 366, 500, 396, 1324, 398, 466, 384, 480, 340, 1382, 340, 530, 340, 526, + 380, 486, 366, 500, 384, 480, 424, 452, 398, 466, 380, 488, 366, 500, 396, + 470, 340, 526, 366, 496, 366, 502, 396, 468, 342, 522, 384, 482, 342, 530, + 386, 482, 340, 524, 396, 468, 366, 500, 382, 486, 366, 500, 366, 502, 396, + 468, 366, 502, 366, 1356, 340, 1380, 382, 484, 386, 482, 342, 526, 362, + 506, 340, 526, 338, 526, 340, 1388, 366, 500, 380, 486, 366, 500, 366, + 498, 380, 488, 416, 1308, 412, 1316, 368, 500, 384, 1338, 396, 1324, 382, + 488, 368, 498, 380, 488, 340, 524, 366, 502, 384, 480, 418, 452, 396, 468, + 340, 1382, 366, 498, 366, 500, 366, 496, 340, 528, 366, 506, 342, 528, + 340, 526, 340, 524, 412, 458, 340, 528, 366, 502, 340, 526, 338, 528, 396, + 466, 396, 466, 366, 496, 366, 500, 366, 502, 366, 498, 366, 500, 396, 470, + 396, 470, 386, 484, 366, 498, 382, 496, 396, 470, 368, 498, 366, 500, 396, + 474, 342, 524, 342, 524, 366, 500, 396, 470, 366, 502, 366, 498, 380, 488, + 340, 522, 412, 460, 396, 468, 396, 468, 366, 496, 340, 522, 366, 504, 396, + 466, 396, 470, 340, 526, 396, 468, 412, 470, 396, 470, 366, 502, 384, 482, + 366, 498, 418, 452, 424, 450, 366, 496, 342, 524, 340, 524, 366, 1356, + 396, 1326, 366, 496, 340, 1382, 396, 470, 366, 1356, 342, 526, 396, 1322, + 386, 17100, 3524, 1772, 366, 1358, 396, 1326, 364, 506, 366, 500, 384, + 482, 396, 1324, 340, 526, 340, 524, 342, 1380, 342, 1382, 342, 526, 338, + 1382, 386, 484, 428, 450, 364, 1356, 366, 1358, 366, 498, 412, 1312, 382, + 1346, 368, 500, 384, 482, 398, 1326, 366, 500, 396, 466, 412, 1314, 342, + 526, 380, 490, 340, 526, 384, 484, 396, 466, 366, 498, 340, 522, 342, 524, + 382, 488, 366, 494, 340, 524, 366, 496, 352, 520, 340, 522, 380, 486, 366, + 498, 340, 526, 340, 524, 382, 488, 366, 498, 396, 470, 342, 524, 340, 524, + 366, 500, 366, 498, 366, 498, 414, 1312, 366, 1354, 362, 508, 340, 524, + 340, 528, 422, 454, 422, 452, 396, 468, 384, 1340, 366, 502, 412, 460, + 426, 450, 396, 466, 382, 486, 366, 1358, 382, 1344, 414, 458, 366, 1356, + 382, 1342, 386, 482, 366, 494, 386, 482, 342, 524, 342, 524, 380, 484, + 366, 500, 384, 480, 428, 1306, 366, 502, 396, 472, 340, 526, 366, 496, + 420, 456, 380, 486, 366, 498, 366, 496, 398, 466, 340, 524, 382, 490, 366, + 494, 342, 524, 396, 466, 380, 490, 340, 524, 396, 470, 394, 478, 422, 452, + 396, 466, 362, 508, 396, 466, 396, 466, 364, 498, 340, 528, 412, 454, 342, + 522, 416, 450, 366, 498, 340, 530, 366, 498, 396, 466, 366, 500, 396, 468, + 340, 530, 366, 502, 412, 458, 396, 468, 384, 482, 366, 498, 340, 522, 380, + 488, 366, 498, 340, 528, 342, 534, 396, 472, 380, 484, 380, 486, 386, 484, + 342, 526, 396, 470, 366, 500, 396, 466, 366, 502, 412, 460, 426, 450, 396, + 468, 380, 1344, 340, 1380, 414, 460, 380, 1342, 386, 482, 366, 1354, 340, + 526, 340, 1386, 396}; // MITSUBISHI_AC + + irsend.sendRaw(rawData, 583, 33); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(MITSUBISHI_AC, irsend.capture.decode_type); + ASSERT_EQ(kMitsubishiACBits, irsend.capture.bits); + uint8_t expected[kMitsubishiACStateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x00, 0x18, 0x08, 0x36, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB}; + EXPECT_STATE_EQ(expected, irsend.capture.state, kMitsubishiACBits); + IRMitsubishiAC ac(0); + ac.setRaw(irsend.capture.state); + EXPECT_EQ( + "Power: Off, Mode: 3 (Cool), Temp: 24C, Fan: 0 (Auto), " + "Swing(V): 0 (Auto), Swing(H): 3 (UNKNOWN), " + "Clock: 00:00, On Timer: 00:00, Off Timer: 00:00, Timer: -", + ac.toString()); +} + +// Tests for IRMitsubishi112 class. + +TEST(TestMitsubishi112Class, Power) { + IRMitsubishi112 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(TestMitsubishi112Class, Temperature) { + IRMitsubishi112 ac(0); + ac.begin(); + + ac.setTemp(0); + EXPECT_EQ(kMitsubishi112MinTemp, ac.getTemp()); + + ac.setTemp(255); + EXPECT_EQ(kMitsubishi112MaxTemp, ac.getTemp()); + + ac.setTemp(kMitsubishi112MinTemp); + EXPECT_EQ(kMitsubishi112MinTemp, ac.getTemp()); + + ac.setTemp(kMitsubishi112MaxTemp); + EXPECT_EQ(kMitsubishi112MaxTemp, ac.getTemp()); + + ac.setTemp(kMitsubishi112MinTemp - 1); + EXPECT_EQ(kMitsubishi112MinTemp, ac.getTemp()); + + ac.setTemp(kMitsubishi112MaxTemp + 1); + EXPECT_EQ(kMitsubishi112MaxTemp, ac.getTemp()); + + ac.setTemp(19); + EXPECT_EQ(19, 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(TestMitsubishi112Class, OperatingMode) { + IRMitsubishi112 ac(0); + ac.begin(); + + ac.setMode(kMitsubishi112Auto); + EXPECT_EQ(kMitsubishi112Auto, ac.getMode()); + + ac.setMode(kMitsubishi112Cool); + EXPECT_EQ(kMitsubishi112Cool, ac.getMode()); + + ac.setMode(kMitsubishi112Heat); + EXPECT_EQ(kMitsubishi112Heat, ac.getMode()); + + ac.setMode(kMitsubishi112Dry); + EXPECT_EQ(kMitsubishi112Dry, ac.getMode()); +} + +TEST(TestMitsubishi112Class, FanSpeed) { + IRMitsubishi112 ac(0); + ac.begin(); + + ac.setFan(kMitsubishi112FanMax); + EXPECT_EQ(kMitsubishi112FanMax, ac.getFan()); + + ac.setFan(kMitsubishi112FanMin); + EXPECT_EQ(kMitsubishi112FanMin, ac.getFan()); + + ac.setFan(255); + EXPECT_EQ(kMitsubishi112FanMax, ac.getFan()); + + ac.setFan(kMitsubishi112FanMed); + EXPECT_EQ(kMitsubishi112FanMed, ac.getFan()); + + ac.setFan(kMitsubishi112FanLow); + EXPECT_EQ(kMitsubishi112FanLow, ac.getFan()); + + ac.setFan(kMitsubishi112FanQuiet); + EXPECT_EQ(kMitsubishi112FanQuiet, ac.getFan()); +} + + +TEST(TestMitsubishi112Class, SwingV) { + IRMitsubishi112 ac(0); + ac.begin(); + + ac.setSwingV(kMitsubishi112SwingVAuto); + EXPECT_EQ(kMitsubishi112SwingVAuto, ac.getSwingV()); + + ac.setSwingV(kMitsubishi112SwingVAuto + 1); + EXPECT_EQ(kMitsubishi112SwingVAuto, ac.getSwingV()); + + ac.setSwingV(kMitsubishi112SwingVLowest); + EXPECT_EQ(kMitsubishi112SwingVLowest, ac.getSwingV()); + + ac.setSwingV(kMitsubishi112SwingVLow); + EXPECT_EQ(kMitsubishi112SwingVLow, ac.getSwingV()); + + ac.setSwingV(kMitsubishi112SwingVHighest); + EXPECT_EQ(kMitsubishi112SwingVHighest, ac.getSwingV()); + + ac.setSwingV(kMitsubishi112SwingVHigh); + EXPECT_EQ(kMitsubishi112SwingVHigh, ac.getSwingV()); +} + +TEST(TestMitsubishi112Class, toCommon) { + IRMitsubishi112 ac(0); + ac.setPower(true); + ac.setMode(kMitsubishi112Dry); + ac.setTemp(22); + ac.setFan(kMitsubishi112FanQuiet); + ac.setSwingV(kMitsubishi112SwingVAuto); + ac.setSwingH(kMitsubishi112SwingHAuto); + // Now test it. + ASSERT_EQ(decode_type_t::MITSUBISHI112, ac.toCommon().protocol); + ASSERT_EQ(-1, ac.toCommon().model); + ASSERT_TRUE(ac.toCommon().power); + ASSERT_TRUE(ac.toCommon().celsius); + ASSERT_EQ(22, ac.toCommon().degrees); + ASSERT_EQ(stdAc::opmode_t::kDry, ac.toCommon().mode); + ASSERT_EQ(stdAc::fanspeed_t::kMin, ac.toCommon().fanspeed); + ASSERT_EQ(stdAc::swingv_t::kAuto, ac.toCommon().swingv); + ASSERT_EQ(stdAc::swingh_t::kAuto, ac.toCommon().swingh); + ASSERT_TRUE(ac.toCommon().quiet); + // Unsupported. + ASSERT_FALSE(ac.toCommon().turbo); + ASSERT_FALSE(ac.toCommon().clean); + ASSERT_FALSE(ac.toCommon().light); + ASSERT_FALSE(ac.toCommon().econo); + ASSERT_FALSE(ac.toCommon().filter); + ASSERT_FALSE(ac.toCommon().beep); + ASSERT_EQ(-1, ac.toCommon().sleep); + ASSERT_EQ(-1, ac.toCommon().clock); +} + +TEST(TestMitsubishi112Class, toCommonMode) { + ASSERT_EQ(stdAc::opmode_t::kCool, + IRMitsubishi112::toCommonMode(kMitsubishi112Cool)); + ASSERT_EQ(kMitsubishi112Cool, + IRMitsubishi112::convertMode(stdAc::opmode_t::kCool)); + ASSERT_EQ(stdAc::opmode_t::kDry, + IRMitsubishi112::toCommonMode(kMitsubishi112Dry)); + ASSERT_EQ(kMitsubishi112Dry, + IRMitsubishi112::convertMode(stdAc::opmode_t::kDry)); +} + +// Decode a 'real' example. +TEST(TestDecodeMitsubishi112, DecodeRealExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + uint16_t rawData[227] = {3468, 1694, 464, 1248, 464, 1248, 466, 376, 468, + 422, 470, 380, 488, 1246, 464, 382, 462, 422, 470, 1248, 466, 1246, + 442, 420, 472, 1246, 466, 380, 488, 382, 486, 1248, 442, 1272, 440, + 422, 472, 1246, 464, 1248, 466, 378, 490, 382, 464, 1270, 466, 380, + 464, 420, 448, 1270, 440, 422, 472, 380, 488, 380, 490, 378, 490, + 376, 466, 424, 468, 386, 486, 380, 488, 382, 462, 422, 448, 422, + 448, 422, 472, 378, 464, 422, 472, 380, 488, 380, 490, 380, 486, + 1248, 466, 380, 488, 380, 490, 1246, 440, 424, 468, 382, 488, 1246, + 466, 1246, 466, 380, 490, 380, 464, 422, 472, 380, 464, 422, 472, + 380, 464, 424, 472, 376, 466, 422, 448, 1270, 444, 420, 448, 420, + 470, 384, 486, 380, 490, 380, 486, 1248, 442, 422, 474, 1244, 464, + 1246, 466, 1246, 466, 384, 462, 422, 472, 378, 490, 382, 486, 384, + 462, 422, 470, 382, 488, 380, 464, 420, 448, 420, 448, 422, 470, + 380, 466, 420, 472, 378, 490, 380, 490, 378, 490, 378, 466, 422, + 446, 422, 446, 422, 446, 422, 472, 378, 488, 380, 490, 380, 466, + 420, 472, 380, 490, 380, 486, 384, 462, 422, 472, 378, 466, 1270, + 466, 1246, 442, 422, 470, 380, 488, 384, 486, 1246, 466, 1246, 442, + 1270, 440, 420, 472, 1248, 466, 384, 462, 1270, 440}; // MITSUBISHI112 + + irsend.sendRaw(rawData, 227, 38); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(MITSUBISHI112, irsend.capture.decode_type); + EXPECT_EQ(kMitsubishi112Bits, irsend.capture.bits); + uint8_t expected[kMitsubishi112StateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03, 0x08, 0x3A, 0x00, + 0x00, 0x00, 0x30, 0xAE}; + EXPECT_STATE_EQ(expected, irsend.capture.state, kMitsubishi112Bits); + EXPECT_EQ( + "Power: On, Mode: 3 (Cool), Temp: 23C, Fan: 2 (Quiet), " + "Swing(V): 7 (Auto), Swing(H): 12 (Auto), Quiet: On", + IRAcUtils::resultAcToString(&irsend.capture)); +} + +// Self decode a synthetic example. +TEST(TestDecodeMitsubishi112, SyntheticExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + uint8_t expected[kMitsubishi112StateLength] = { + 0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03, 0x08, 0x3A, + 0x00, 0x00, 0x00, 0x30, 0xAE}; + + irsend.sendMitsubishi112(expected); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + ASSERT_EQ(MITSUBISHI112, irsend.capture.decode_type); + EXPECT_EQ(kMitsubishi112Bits, irsend.capture.bits); + EXPECT_STATE_EQ(expected, irsend.capture.state, kMitsubishi112Bits); +} diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_NEC_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_NEC_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_NEC_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_NEC_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Neoclima_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Neoclima_test.cpp old mode 100755 new mode 100644 similarity index 99% rename from lib/IRremoteESP8266-2.6.5/test/ir_Neoclima_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Neoclima_test.cpp index 38747f276..c743e7ba5 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Neoclima_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Neoclima_test.cpp @@ -79,7 +79,7 @@ TEST(TestDecodeNeoclima, RealExample) { IRNeoclimaAc ac(0); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 26C, Fan: 3 (Low), " + "Power: On, Mode: 1 (Cool), Temp: 26C, Fan: 3 (Low), " "Swing(V): Off, Swing(H): On, Sleep: Off, Turbo: Off, Hold: Off, " "Ion: Off, Eye: Off, Light: Off, Follow: Off, 8C Heat: Off, Fresh: Off, " "Button: 0 (Power)", diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Nikai_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Nikai_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Nikai_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Nikai_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Panasonic_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Panasonic_test.cpp old mode 100755 new mode 100644 similarity index 94% rename from lib/IRremoteESP8266-2.6.5/test/ir_Panasonic_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Panasonic_test.cpp index 7f84c2a8a..471a324c8 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Panasonic_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Panasonic_test.cpp @@ -647,15 +647,17 @@ TEST(TestIRPanasonicAcClass, SetAndGetFan) { pana.setFan(kPanasonicAcFanMin); EXPECT_EQ(kPanasonicAcFanMin, pana.getFan()); pana.setFan(kPanasonicAcFanMin - 1); - EXPECT_EQ(kPanasonicAcFanMin, pana.getFan()); + EXPECT_EQ(kPanasonicAcFanAuto, pana.getFan()); + pana.setFan(kPanasonicAcFanMed); + EXPECT_EQ(kPanasonicAcFanMed, pana.getFan()); pana.setFan(kPanasonicAcFanMin + 1); - EXPECT_EQ(kPanasonicAcFanMin + 1, pana.getFan()); + EXPECT_EQ(kPanasonicAcFanAuto, pana.getFan()); pana.setFan(kPanasonicAcFanMax); EXPECT_EQ(kPanasonicAcFanMax, pana.getFan()); pana.setFan(kPanasonicAcFanMax + 1); - EXPECT_EQ(kPanasonicAcFanMax, pana.getFan()); + EXPECT_EQ(kPanasonicAcFanAuto, pana.getFan()); pana.setFan(kPanasonicAcFanMax - 1); - EXPECT_EQ(kPanasonicAcFanMax - 1, pana.getFan()); + EXPECT_EQ(kPanasonicAcFanAuto, pana.getFan()); } TEST(TestIRPanasonicAcClass, SetAndGetSwings) { @@ -665,19 +667,19 @@ TEST(TestIRPanasonicAcClass, SetAndGetSwings) { pana.setSwingVertical(kPanasonicAcSwingVAuto); EXPECT_EQ(kPanasonicAcSwingVAuto, pana.getSwingVertical()); - pana.setSwingVertical(kPanasonicAcSwingVUp); - EXPECT_EQ(kPanasonicAcSwingVUp, pana.getSwingVertical()); - pana.setSwingVertical(kPanasonicAcSwingVUp - 1); - EXPECT_EQ(kPanasonicAcSwingVUp, pana.getSwingVertical()); - pana.setSwingVertical(kPanasonicAcSwingVUp + 1); - EXPECT_EQ(kPanasonicAcSwingVUp + 1, pana.getSwingVertical()); + pana.setSwingVertical(kPanasonicAcSwingVHighest); + EXPECT_EQ(kPanasonicAcSwingVHighest, pana.getSwingVertical()); + pana.setSwingVertical(kPanasonicAcSwingVHighest - 1); + EXPECT_EQ(kPanasonicAcSwingVHighest, pana.getSwingVertical()); + pana.setSwingVertical(kPanasonicAcSwingVHighest + 1); + EXPECT_EQ(kPanasonicAcSwingVHighest + 1, pana.getSwingVertical()); - pana.setSwingVertical(kPanasonicAcSwingVDown); - EXPECT_EQ(kPanasonicAcSwingVDown, pana.getSwingVertical()); - pana.setSwingVertical(kPanasonicAcSwingVDown + 1); - EXPECT_EQ(kPanasonicAcSwingVDown, pana.getSwingVertical()); - pana.setSwingVertical(kPanasonicAcSwingVDown - 1); - EXPECT_EQ(kPanasonicAcSwingVDown - 1, pana.getSwingVertical()); + pana.setSwingVertical(kPanasonicAcSwingVLowest); + EXPECT_EQ(kPanasonicAcSwingVLowest, pana.getSwingVertical()); + pana.setSwingVertical(kPanasonicAcSwingVLowest + 1); + EXPECT_EQ(kPanasonicAcSwingVLowest, pana.getSwingVertical()); + pana.setSwingVertical(kPanasonicAcSwingVLowest - 1); + EXPECT_EQ(kPanasonicAcSwingVLowest - 1, pana.getSwingVertical()); pana.setSwingVertical(kPanasonicAcSwingVAuto); EXPECT_EQ(kPanasonicAcSwingVAuto, pana.getSwingVertical()); @@ -737,8 +739,8 @@ TEST(TestIRPanasonicAcClass, QuietAndPowerful) { TEST(TestIRPanasonicAcClass, HumanReadable) { IRPanasonicAc pana(0); EXPECT_EQ( - "Model: 4 (JKE), Power: Off, Mode: 0 (AUTO), Temp: 0C, " - "Fan: 253 (UNKNOWN), Swing (Vertical): 0 (UNKNOWN), Quiet: Off, " + "Model: 4 (JKE), Power: Off, Mode: 0 (Auto), Temp: 0C, " + "Fan: 253 (UNKNOWN), Swing(V): 0 (UNKNOWN), Quiet: Off, " "Powerful: Off, Clock: 00:00, On Timer: Off, Off Timer: Off", pana.toString()); pana.setPower(true); @@ -748,24 +750,24 @@ TEST(TestIRPanasonicAcClass, HumanReadable) { pana.setSwingVertical(kPanasonicAcSwingVAuto); pana.setPowerful(true); EXPECT_EQ( - "Model: 4 (JKE), Power: On, Mode: 4 (HEAT), Temp: 30C, " - "Fan: 4 (High), Swing (Vertical): 15 (AUTO), Quiet: Off, " + "Model: 4 (JKE), Power: On, Mode: 4 (Heat), Temp: 30C, " + "Fan: 4 (High), Swing(V): 15 (Auto), Quiet: Off, " "Powerful: On, Clock: 00:00, On Timer: Off, Off Timer: Off", pana.toString()); pana.setQuiet(true); pana.setModel(kPanasonicLke); EXPECT_EQ( - "Model: 1 (LKE), Power: Off, Mode: 4 (HEAT), Temp: 30C, " - "Fan: 4 (High), Swing (Vertical): 15 (AUTO), " - "Swing (Horizontal): 6 (Middle), Quiet: On, Powerful: Off, " + "Model: 1 (LKE), Power: Off, Mode: 4 (Heat), Temp: 30C, " + "Fan: 4 (High), Swing(V): 15 (Auto), " + "Swing(H): 6 (Middle), Quiet: On, Powerful: Off, " "Clock: 00:00, On Timer: 00:00, Off Timer: Off", pana.toString()); pana.setModel(kPanasonicDke); pana.setSwingHorizontal(kPanasonicAcSwingHRight); EXPECT_EQ( - "Model: 3 (DKE), Power: Off, Mode: 4 (HEAT), Temp: 30C, " - "Fan: 4 (High), Swing (Vertical): 15 (AUTO), " - "Swing (Horizontal): 11 (Right), Quiet: On, Powerful: Off, " + "Model: 3 (DKE), Power: Off, Mode: 4 (Heat), Temp: 30C, " + "Fan: 4 (High), Swing(V): 15 (Auto), " + "Swing(H): 11 (Right), Quiet: On, Powerful: Off, " "Clock: 00:00, On Timer: Off, Off Timer: Off", pana.toString()); } @@ -856,8 +858,8 @@ TEST(TestDecodePanasonicAC, SyntheticExample) { IRPanasonicAc pana(0); pana.setRaw(irsend.capture.state); EXPECT_EQ( - "Model: 4 (JKE), Power: Off, Mode: 3 (COOL), Temp: 25C, " - "Fan: 7 (Auto), Swing (Vertical): 15 (AUTO), Quiet: Off, " + "Model: 4 (JKE), Power: Off, Mode: 3 (Cool), Temp: 25C, " + "Fan: 7 (Auto), Swing(V): 15 (Auto), Quiet: Off, " "Powerful: Off, Clock: 00:00, On Timer: Off, Off Timer: Off", pana.toString()); } @@ -935,9 +937,9 @@ TEST(TestDecodePanasonicAC, Issue540) { pana.setRaw(irsend.capture.state); // TODO(crankyoldgit): Try to figure out what model this should be. EXPECT_EQ( - "Model: 0 (UNKNOWN), Power: On, Mode: 3 (COOL), Temp: 26C, " - "Fan: 7 (Auto), Swing (Vertical): 15 (AUTO), " - "Swing (Horizontal): 13 (AUTO), Quiet: Off, Powerful: Off, " + "Model: 0 (UNKNOWN), Power: On, Mode: 3 (Cool), Temp: 26C, " + "Fan: 7 (Auto), Swing(V): 15 (Auto), " + "Swing(H): 13 (Auto), Quiet: Off, Powerful: Off, " "Clock: 00:00, On Timer: Off, Off Timer: Off", pana.toString()); } @@ -1115,8 +1117,8 @@ TEST(TestDecodePanasonicAC, CkpModelSpecifics) { IRPanasonicAc pana(0); pana.setRaw(irsend.capture.state); EXPECT_EQ( - "Model: 5 (CKP), Power: Off, Mode: 4 (HEAT), Temp: 23C, " - "Fan: 7 (Auto), Swing (Vertical): 15 (AUTO), Quiet: Off, " + "Model: 5 (CKP), Power: Off, Mode: 4 (Heat), Temp: 23C, " + "Fan: 7 (Auto), Swing(V): 15 (Auto), Quiet: Off, " "Powerful: On, Clock: 00:00, On Timer: 00:00, Off Timer: 00:00", pana.toString()); @@ -1164,4 +1166,17 @@ TEST(TestIRPanasonicAcClass, toCommon) { ASSERT_FALSE(ac.toCommon().beep); ASSERT_EQ(-1, ac.toCommon().sleep); ASSERT_EQ(-1, ac.toCommon().clock); + + // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/921#issuecomment-532267240 + ac.setSwingVertical(kPanasonicAcSwingVLow); + ASSERT_EQ(stdAc::swingv_t::kLow, ac.toCommon().swingv); + // Real data. + uint8_t swingVMiddle[27] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, 0x20, 0xE0, 0x04, + 0x00, 0x39, 0x32, 0x80, 0x73, 0x00, 0x00, 0x0E, 0xE0, 0x00, 0x00, 0x89, + 0x00, 0x00, 0xDB}; + ac.setRaw(swingVMiddle); + ASSERT_EQ(stdAc::swingv_t::kMiddle, ac.toCommon().swingv); + ASSERT_EQ(kPanasonicAcSwingVMiddle, + IRPanasonicAc::convertSwingV(stdAc::swingv_t::kMiddle)); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Pioneer_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Pioneer_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Pioneer_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Pioneer_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Pronto_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Pronto_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Pronto_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Pronto_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_RC5_RC6_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_RC5_RC6_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_RC5_RC6_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_RC5_RC6_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_RCMM_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_RCMM_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_RCMM_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_RCMM_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Samsung_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Samsung_test.cpp old mode 100755 new mode 100644 similarity index 96% rename from lib/IRremoteESP8266-2.6.5/test/ir_Samsung_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Samsung_test.cpp index b928350b6..9a572c631 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Samsung_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Samsung_test.cpp @@ -548,7 +548,7 @@ 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, " + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 7 (Turbo), Swing: Off, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: On", ac.toString()); uint8_t off[kSamsungAcStateLength] = { @@ -558,7 +558,7 @@ 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, " + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off", ac.toString()); } @@ -623,7 +623,7 @@ TEST(TestIRSamsungAcClass, ChecksumCalculation) { TEST(TestIRSamsungAcClass, HumanReadable) { IRSamsungAc samsung(0); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 16C, Fan: 2 (Low), Swing: On, " + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), Swing: On, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off", samsung.toString()); samsung.setTemp(kSamsungAcMaxTemp); @@ -634,18 +634,18 @@ TEST(TestIRSamsungAcClass, HumanReadable) { samsung.setBeep(true); samsung.setClean(true); EXPECT_EQ( - "Power: Off, Mode: 4 (HEAT), Temp: 30C, Fan: 5 (High), Swing: Off, " + "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 5 (High), Swing: Off, " "Beep: On, Clean: On, Quiet: Off, Powerful: Off", samsung.toString()); samsung.setQuiet(true); EXPECT_EQ( - "Power: Off, Mode: 4 (HEAT), Temp: 30C, Fan: 0 (Auto), Swing: Off, " + "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), Swing: Off, " "Beep: On, Clean: On, Quiet: On, Powerful: Off", samsung.toString()); samsung.setQuiet(false); samsung.setPowerful(true); EXPECT_EQ( - "Power: Off, Mode: 4 (HEAT), Temp: 30C, Fan: 7 (Turbo), Swing: Off, " + "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 7 (Turbo), Swing: Off, " "Beep: On, Clean: On, Quiet: Off, Powerful: On", samsung.toString()); } @@ -749,7 +749,7 @@ TEST(TestDecodeSamsungAC, DecodeRealExample) { IRSamsungAc samsung(0); samsung.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 16C, Fan: 2 (Low), Swing: On, " + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 2 (Low), Swing: On, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off", samsung.toString()); } @@ -798,7 +798,7 @@ TEST(TestDecodeSamsungAC, DecodeRealExample2) { IRSamsungAc samsung(0); samsung.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 0 (Auto), Swing: Off, " + "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off", samsung.toString()); } @@ -857,7 +857,7 @@ TEST(TestDecodeSamsungAC, DecodePowerOnSample) { IRSamsungAc samsung(0); samsung.setRaw(irsend.capture.state, kSamsungAcExtendedStateLength); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 24C, Fan: 0 (Auto), Swing: Off, " + "Power: On, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off", samsung.toString()); } @@ -917,7 +917,7 @@ TEST(TestDecodeSamsungAC, DecodePowerOffSample) { IRSamsungAc samsung(0); samsung.setRaw(irsend.capture.state, kSamsungAcExtendedStateLength); EXPECT_EQ( - "Power: Off, Mode: 1 (COOL), Temp: 24C, Fan: 0 (Auto), Swing: Off, " + "Power: Off, Mode: 1 (Cool), Temp: 24C, Fan: 0 (Auto), Swing: Off, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off", samsung.toString()); } @@ -964,7 +964,7 @@ TEST(TestDecodeSamsungAC, DecodeHeatSample) { IRSamsungAc samsung(0); samsung.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 17C, Fan: 0 (Auto), Swing: On, " + "Power: On, Mode: 4 (Heat), Temp: 17C, Fan: 0 (Auto), Swing: On, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off", samsung.toString()); } @@ -1011,7 +1011,7 @@ TEST(TestDecodeSamsungAC, DecodeCoolSample) { IRSamsungAc samsung(0); samsung.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 20C, Fan: 0 (Auto), Swing: Off, " + "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 0 (Auto), Swing: Off, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off", samsung.toString()); } @@ -1069,7 +1069,7 @@ TEST(TestDecodeSamsungAC, Issue604DecodeExtended) { IRSamsungAc samsung(0); samsung.setRaw(irsend.capture.state, irsend.capture.bits / 8); EXPECT_EQ( - "Power: Off, Mode: 4 (HEAT), Temp: 30C, Fan: 0 (Auto), Swing: Off, " + "Power: Off, Mode: 4 (Heat), Temp: 30C, Fan: 0 (Auto), Swing: Off, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off", samsung.toString()); } @@ -1212,6 +1212,7 @@ TEST(TestDecodeSamsung36, SyntheticExample) { TEST(TestIRSamsungAcClass, Issue604SendPowerHack) { IRSamsungAc ac(0); ac.begin(); + ac.stateReset(false); // Disable the initial forced sending of a power mesg. std::string freqduty = "f38000d50"; @@ -1264,7 +1265,7 @@ TEST(TestIRSamsungAcClass, Issue604SendPowerHack) { "m586s1432m586s436m586s436m586s1432m586s1432m586s436m586s436m586s436" "m586s436m586s436m586s436m586s436m586s1432m586s1432m586s1432m586s1432" "m586s100000"; - std::string text = "Power: On, Mode: 1 (COOL), Temp: 23C, Fan: 4 (Medium), " + std::string text = "Power: On, Mode: 1 (Cool), Temp: 23C, Fan: 4 (Med), " "Swing: On, Beep: Off, Clean: Off, Quiet: Off, " "Powerful: Off"; // Don't do a setPower()/on()/off() as that will trigger the special message. @@ -1275,23 +1276,46 @@ TEST(TestIRSamsungAcClass, Issue604SendPowerHack) { ac.send(); EXPECT_EQ(text, ac.toString()); EXPECT_EQ(freqduty + settings, ac._irsend.outputStr()); - ac._irsend.reset(); + // Ensure the power state is changed by changing it and sending it. + ac.off(); + ac.send(); + ac._irsend.reset(); // Clear the capture buffer. // Now trigger a special power message by using a power method. ac.on(); ac.send(); // This should result in two messages. 1 x extended + 1 x normal. EXPECT_EQ(text, ac.toString()); EXPECT_EQ(freqduty + poweron + settings, ac._irsend.outputStr()); - ac._irsend.reset(); + ac._irsend.reset(); // Clear the capture buffer. // Subsequent sending should be just the "settings" message. ac.send(); EXPECT_EQ(text, ac.toString()); EXPECT_EQ(freqduty + settings, ac._irsend.outputStr()); - ac._irsend.reset(); - // Now trigger a special power message by using a power method (again). - ac.setPower(true); - ac.send(); // This should result in two messages. 1 x extended + 1 x normal. + ac._irsend.reset(); // Clear the capture buffer. + ac.setPower(true); // Note: The power state hasn't changed from previous. + ac.send(); // This should result in a normal setting message. + EXPECT_EQ(text, ac.toString()); + EXPECT_EQ(freqduty + settings, ac._irsend.outputStr()); + + ac._irsend.reset(); // Clear the capture buffer. + ac.setPower(false); + ac.setPower(true); // Note: The power state hasn't changed from the last sent + ac.send(); // This should result in a normal setting message. + EXPECT_EQ(text, ac.toString()); + EXPECT_EQ(freqduty + settings, ac._irsend.outputStr()); + + ac.stateReset(); // Normal `stateReset` defaults to send the power message + // on first send. + ac._irsend.reset(); // Clear the capture buffer. + ac.setTemp(23); + ac.setMode(kSamsungAcCool); + ac.setFan(kSamsungAcFanMed); + ac.send(); EXPECT_EQ(text, ac.toString()); EXPECT_EQ(freqduty + poweron + settings, ac._irsend.outputStr()); + ac._irsend.reset(); // Clear the capture buffer. + ac.send(); // Subsequent send() should just be a settings message. + EXPECT_EQ(text, ac.toString()); + EXPECT_EQ(freqduty + settings, ac._irsend.outputStr()); } TEST(TestIRSamsungAcClass, toCommon) { @@ -1367,7 +1391,7 @@ 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, " + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, " "Beep: Off, Clean: Off, Quiet: On, Powerful: Off", ac.toString()); @@ -1389,7 +1413,7 @@ TEST(TestDecodeSamsungAC, Issue734QuietSetting) { ac.setClean(false); ac.setQuiet(true); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 16C, Fan: 0 (Auto), Swing: Off, " + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, " "Beep: Off, Clean: Off, Quiet: On, Powerful: Off", ac.toString()); // Check it matches the known good/expected state. @@ -1439,7 +1463,7 @@ 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, " + "Power: On, Mode: 1 (Cool), Temp: 16C, Fan: 0 (Auto), Swing: Off, " "Beep: Off, Clean: Off, Quiet: Off, Powerful: Off", ac.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Sanyo_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Sanyo_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Sanyo_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Sanyo_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Sharp_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Sharp_test.cpp old mode 100755 new mode 100644 similarity index 96% rename from lib/IRremoteESP8266-2.6.5/test/ir_Sharp_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Sharp_test.cpp index 2949580ed..571e59859 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Sharp_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Sharp_test.cpp @@ -402,7 +402,7 @@ TEST(TestDecodeSharpAc, RealExample) { IRSharpAc ac(0); ac.begin(); ac.setRaw(irsend.capture.state); - EXPECT_EQ("Power: On, Mode: 2 (COOL), Temp: 27C, Fan: 2 (Auto)", + EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 27C, Fan: 2 (Auto)", ac.toString()); } @@ -584,7 +584,7 @@ TEST(TestSharpAcClass, ReconstructKnownState) { ac.setTemp(kSharpAcMinTemp); ac.setFan(kSharpAcFanAuto); EXPECT_STATE_EQ(on_auto_auto, ac.getRaw(), kSharpAcBits); - EXPECT_EQ("Power: On, Mode: 0 (AUTO), Temp: 15C, Fan: 2 (Auto)", + EXPECT_EQ("Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto)", ac.toString()); uint8_t cool_auto_28[kSharpAcStateLength] = { @@ -595,7 +595,7 @@ TEST(TestSharpAcClass, ReconstructKnownState) { ac.setMode(kSharpAcCool); ac.setTemp(28); ac.setFan(kSharpAcFanAuto); - EXPECT_EQ("Power: On, Mode: 2 (COOL), Temp: 28C, Fan: 2 (Auto)", + EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto)", ac.toString()); EXPECT_STATE_EQ(cool_auto_28, ac.getRaw(), kSharpAcBits); } @@ -610,49 +610,49 @@ TEST(TestSharpAcClass, KnownStates) { 0x31}; ASSERT_TRUE(ac.validChecksum(off_auto_auto)); ac.setRaw(off_auto_auto); - EXPECT_EQ("Power: Off, Mode: 0 (AUTO), Temp: 15C, Fan: 2 (Auto)", + EXPECT_EQ("Power: Off, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto)", ac.toString()); uint8_t on_auto_auto[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0x00, 0x11, 0x20, 0x00, 0x08, 0x80, 0x00, 0xE0, 0x01}; ASSERT_TRUE(ac.validChecksum(on_auto_auto)); ac.setRaw(on_auto_auto); - EXPECT_EQ("Power: On, Mode: 0 (AUTO), Temp: 15C, Fan: 2 (Auto)", + EXPECT_EQ("Power: On, Mode: 0 (Auto), Temp: 15C, Fan: 2 (Auto)", ac.toString()); uint8_t cool_auto_28[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x22, 0x00, 0x08, 0x80, 0x04, 0xE0, 0x51}; ASSERT_TRUE(ac.validChecksum(cool_auto_28)); ac.setRaw(cool_auto_28); - EXPECT_EQ("Power: On, Mode: 2 (COOL), Temp: 28C, Fan: 2 (Auto)", + EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 2 (Auto)", ac.toString()); uint8_t cool_fan1_28[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x42, 0x00, 0x08, 0x80, 0x05, 0xE0, 0x21}; ASSERT_TRUE(ac.validChecksum(cool_fan1_28)); ac.setRaw(cool_fan1_28); - EXPECT_EQ("Power: On, Mode: 2 (COOL), Temp: 28C, Fan: 4 (Low)", + EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 4 (Low)", ac.toString()); uint8_t cool_fan2_28[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x32, 0x00, 0x08, 0x80, 0x05, 0xE0, 0x51}; ASSERT_TRUE(ac.validChecksum(cool_fan2_28)); ac.setRaw(cool_fan2_28); - EXPECT_EQ("Power: On, Mode: 2 (COOL), Temp: 28C, Fan: 3 (Medium)", + EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium)", ac.toString()); uint8_t cool_fan3_28[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x52, 0x00, 0x08, 0x80, 0x05, 0xE0, 0x31}; ASSERT_TRUE(ac.validChecksum(cool_fan3_28)); ac.setRaw(cool_fan3_28); - EXPECT_EQ("Power: On, Mode: 2 (COOL), Temp: 28C, Fan: 5 (UNKNOWN)", + EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 5 (UNKNOWN)", ac.toString()); uint8_t cool_fan4_28[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x31, 0x72, 0x00, 0x08, 0x80, 0x05, 0xE0, 0x11}; ASSERT_TRUE(ac.validChecksum(cool_fan4_28)); ac.setRaw(cool_fan4_28); - EXPECT_EQ("Power: On, Mode: 2 (COOL), Temp: 28C, Fan: 7 (High)", + EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 7 (High)", ac.toString()); /* Unsupported / Not yet reverse engineered. uint8_t cool_fan4_28_ion_on[kSharpAcStateLength] = { @@ -660,21 +660,21 @@ TEST(TestSharpAcClass, KnownStates) { 0xD1}; ASSERT_TRUE(ac.validChecksum(cool_fan4_28_ion_on)); ac.setRaw(cool_fan4_28_ion_on); - EXPECT_EQ("Power: On, Mode: 2 (COOL), Temp: 28C, Fan: 7 (MAX)", + EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 7 (Max)", ac.toString()); uint8_t cool_fan4_28_eco1[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0xCD, 0x61, 0x72, 0x18, 0x08, 0x80, 0x00, 0xE8, 0x01}; ASSERT_TRUE(ac.validChecksum(cool_fan4_28_eco1)); ac.setRaw(cool_fan4_28_eco1); - EXPECT_EQ("Power: On, Mode: 2 (COOL), Temp: 28C, Fan: 7 (MAX)", + EXPECT_EQ("Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 7 (Max)", ac.toString()); */ uint8_t dry_auto[kSharpAcStateLength] = { 0xAA, 0x5A, 0xCF, 0x10, 0x00, 0x31, 0x23, 0x00, 0x08, 0x80, 0x00, 0xE0, 0x11}; ASSERT_TRUE(ac.validChecksum(dry_auto)); ac.setRaw(dry_auto); - EXPECT_EQ("Power: On, Mode: 3 (DRY), Temp: 15C, Fan: 2 (Auto)", + EXPECT_EQ("Power: On, Mode: 3 (Dry), Temp: 15C, Fan: 2 (Auto)", ac.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Sherwood_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Sherwood_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Sherwood_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Sherwood_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Sony_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Sony_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Sony_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Sony_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Tcl_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Tcl_test.cpp old mode 100755 new mode 100644 similarity index 89% rename from lib/IRremoteESP8266-2.6.5/test/ir_Tcl_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Tcl_test.cpp index 8432cf9ac..99a9e7de7 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Tcl_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Tcl_test.cpp @@ -65,8 +65,8 @@ TEST(TestDecodeTcl112Ac, DecodeRealExample) { IRTcl112Ac ac(0); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 24C, Fan: 0 (Auto), Econo: Off, " - "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off", + "Power: On, Mode: 3 (Cool), Temp: 24C, Fan: 0 (Auto), Econo: Off, " + "Health: Off, Light: On, Turbo: Off, Swing(H): Off, Swing(V): Off", ac.toString()); } @@ -107,23 +107,23 @@ TEST(TestTcl112AcClass, Temperature) { IRTcl112Ac ac(0); ac.setRaw(temp16C); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 16C, Fan: 0 (Auto), Econo: Off, " - "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off", + "Power: On, Mode: 3 (Cool), Temp: 16C, Fan: 0 (Auto), Econo: Off, " + "Health: Off, Light: On, Turbo: Off, Swing(H): Off, Swing(V): Off", ac.toString()); ac.setRaw(temp16point5C); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 16.5C, Fan: 0 (Auto), Econo: Off, " - "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off", + "Power: On, Mode: 3 (Cool), Temp: 16.5C, Fan: 0 (Auto), Econo: Off, " + "Health: Off, Light: On, Turbo: Off, Swing(H): Off, Swing(V): Off", ac.toString()); ac.setRaw(temp19point5C); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 19.5C, Fan: 0 (Auto), Econo: Off, " - "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off", + "Power: On, Mode: 3 (Cool), Temp: 19.5C, Fan: 0 (Auto), Econo: Off, " + "Health: Off, Light: On, Turbo: Off, Swing(H): Off, Swing(V): Off", ac.toString()); ac.setRaw(temp31C); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 31C, Fan: 0 (Auto), Econo: Off, " - "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off", + "Power: On, Mode: 3 (Cool), Temp: 31C, Fan: 0 (Auto), Econo: Off, " + "Health: Off, Light: On, Turbo: Off, Swing(H): Off, Swing(V): Off", ac.toString()); ac.setTemp(kTcl112AcTempMin); @@ -203,8 +203,8 @@ TEST(TestTcl112AcClass, OperatingMode) { 0x07, 0x00, 0x00, 0x00, 0x00, 0x80, 0x48}; ac.setRaw(automode); EXPECT_EQ( - "Power: On, Mode: 8 (AUTO), Temp: 24C, Fan: 0 (Auto), Econo: Off, " - "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off", + "Power: On, Mode: 8 (Auto), Temp: 24C, Fan: 0 (Auto), Econo: Off, " + "Health: Off, Light: On, Turbo: Off, Swing(H): Off, Swing(V): Off", ac.toString()); } @@ -232,8 +232,8 @@ TEST(TestTcl112AcClass, Power) { 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCB}; ac.setRaw(on); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 16C, Fan: 0 (Auto), Econo: Off, " - "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off", + "Power: On, Mode: 3 (Cool), Temp: 16C, Fan: 0 (Auto), Econo: Off, " + "Health: Off, Light: On, Turbo: Off, Swing(H): Off, Swing(V): Off", ac.toString()); const uint8_t off[kTcl112AcStateLength] = { @@ -241,8 +241,8 @@ TEST(TestTcl112AcClass, Power) { 0x07, 0x40, 0x00, 0x00, 0x00, 0x80, 0xCB}; ac.setRaw(off); EXPECT_EQ( - "Power: Off, Mode: 3 (COOL), Temp: 24C, Fan: 0 (Auto), Econo: Off, " - "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off", + "Power: Off, Mode: 3 (Cool), Temp: 24C, Fan: 0 (Auto), Econo: Off, " + "Health: Off, Light: On, Turbo: Off, Swing(H): Off, Swing(V): Off", ac.toString()); } @@ -257,13 +257,13 @@ TEST(TestTcl112AcClass, Checksum) { EXPECT_EQ(0xCB, ac.calcChecksum(temp16C)); ac.setRaw(temp16C); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 16C, Fan: 0 (Auto), Econo: Off, " - "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off", + "Power: On, Mode: 3 (Cool), Temp: 16C, Fan: 0 (Auto), Econo: Off, " + "Health: Off, Light: On, Turbo: Off, Swing(H): Off, Swing(V): Off", ac.toString()); ac.setRaw(temp31C); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 31C, Fan: 0 (Auto), Econo: Off, " - "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off", + "Power: On, Mode: 3 (Cool), Temp: 31C, Fan: 0 (Auto), Econo: Off, " + "Health: Off, Light: On, Turbo: Off, Swing(H): Off, Swing(V): Off", ac.toString()); EXPECT_EQ(0xBC, ac.calcChecksum(temp31C)); @@ -456,7 +456,7 @@ TEST(TestDecodeTcl112Ac, Issue744) { IRTcl112Ac ac(0); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 3 (COOL), Temp: 23C, Fan: 0 (Auto), Econo: Off, " - "Health: Off, Light: On, Turbo: Off, Swing (H): Off, Swing (V): Off", + "Power: On, Mode: 3 (Cool), Temp: 23C, Fan: 0 (Auto), Econo: Off, " + "Health: Off, Light: On, Turbo: Off, Swing(H): Off, Swing(V): Off", ac.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Teco_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Teco_test.cpp old mode 100755 new mode 100644 similarity index 82% rename from lib/IRremoteESP8266-2.6.5/test/ir_Teco_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Teco_test.cpp index 4ed7fbd9f..cb6c8bcd9 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Teco_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Teco_test.cpp @@ -243,12 +243,45 @@ TEST(TestTecoACClass, Save) { EXPECT_TRUE(ac.getSave()); } +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/882 +TEST(TestTecoACClass, Timer) { + IRTecoAc ac(0); + ac.begin(); + + ac.setTimer(60); + EXPECT_TRUE(ac.getTimerEnabled()); + EXPECT_EQ(60, ac.getTimer()); + ac.setTimer(0); + EXPECT_EQ(false, ac.getTimerEnabled()); + EXPECT_EQ(0, ac.getTimer()); + ac.setTimer(17 * 60 + 59); + EXPECT_TRUE(ac.getTimerEnabled()); + EXPECT_EQ(17 * 60 + 30, ac.getTimer()); + ac.setTimer(24 * 60 + 31); + EXPECT_TRUE(ac.getTimerEnabled()); + EXPECT_EQ(24 * 60, ac.getTimer()); + + // Data from: https://github.com/crankyoldgit/IRremoteESP8266/issues/882#issuecomment-527079339 + ac.setRaw(0x250218A49); // Timer On 1hr + EXPECT_TRUE(ac.getTimerEnabled()); + EXPECT_EQ(60, ac.getTimer()); + ac.setRaw(0x250219A49); // Timer On 1.5hr + EXPECT_TRUE(ac.getTimerEnabled()); + EXPECT_EQ(60 + 30, ac.getTimer()); + ac.setRaw(0x250200A49); // Timer Off + EXPECT_FALSE(ac.getTimerEnabled()); + EXPECT_EQ(0, ac.getTimer()); + ac.setRaw(0x25023DA41); // Timer On 23.5hrs + EXPECT_TRUE(ac.getTimerEnabled()); + EXPECT_EQ(23 * 60 + 30, ac.getTimer()); +} + TEST(TestTecoACClass, MessageConstuction) { IRTecoAc ac(0); EXPECT_EQ( - "Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (Auto), Sleep: Off, " - "Swing: Off, Light: Off, Humid: Off, Save: Off", + "Power: Off, Mode: 0 (Auto), Temp: 16C, Fan: 0 (Auto), Sleep: Off, " + "Swing: Off, Light: Off, Humid: Off, Save: Off, Timer: Off", ac.toString()); ac.setPower(true); ac.setMode(kTecoCool); @@ -257,34 +290,35 @@ TEST(TestTecoACClass, MessageConstuction) { ac.setSwing(false); ac.setLight(false); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 3 (High), Sleep: Off, " - "Swing: Off, Light: Off, Humid: Off, Save: Off", + "Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 3 (High), Sleep: Off, " + "Swing: Off, Light: Off, Humid: Off, Save: Off, Timer: Off", ac.toString()); ac.setSwing(true); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 3 (High), Sleep: Off, " - "Swing: On, Light: Off, Humid: Off, Save: Off", + "Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 3 (High), Sleep: Off, " + "Swing: On, Light: Off, Humid: Off, Save: Off, Timer: Off", ac.toString()); ac.setSwing(false); ac.setFan(kTecoFanLow); ac.setSleep(true); ac.setMode(kTecoHeat); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 21C, Fan: 1 (Low), Sleep: On, " - "Swing: Off, Light: Off, Humid: Off, Save: Off", + "Power: On, Mode: 4 (Heat), Temp: 21C, Fan: 1 (Low), Sleep: On, " + "Swing: Off, Light: Off, Humid: Off, Save: Off, Timer: Off", ac.toString()); ac.setSleep(false); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 21C, Fan: 1 (Low), Sleep: Off, " - "Swing: Off, Light: Off, Humid: Off, Save: Off", + "Power: On, Mode: 4 (Heat), Temp: 21C, Fan: 1 (Low), Sleep: Off, " + "Swing: Off, Light: Off, Humid: Off, Save: Off, Timer: Off", ac.toString()); ac.setTemp(25); ac.setLight(true); ac.setSave(true); ac.setHumid(true); + ac.setTimer(18 * 60 + 37); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 25C, Fan: 1 (Low), Sleep: Off, " - "Swing: Off, Light: On, Humid: On, Save: On", + "Power: On, Mode: 4 (Heat), Temp: 25C, Fan: 1 (Low), Sleep: Off, " + "Swing: Off, Light: On, Humid: On, Save: On, Timer: 18:30", ac.toString()); } @@ -301,8 +335,8 @@ TEST(TestTecoACClass, ReconstructKnownMessage) { ac.setSwing(true); EXPECT_EQ(expected, ac.getRaw()); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 27C, Fan: 0 (Auto), Sleep: On, " - "Swing: On, Light: Off, Humid: Off, Save: Off", + "Power: On, Mode: 1 (Cool), Temp: 27C, Fan: 0 (Auto), Sleep: On, " + "Swing: On, Light: Off, Humid: Off, Save: Off, Timer: Off", ac.toString()); } @@ -343,8 +377,8 @@ TEST(TestDecodeTeco, NormalDecodeWithStrict) { ac.begin(); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Power: Off, Mode: 0 (AUTO), Temp: 16C, Fan: 0 (Auto), Sleep: Off, " - "Swing: Off, Light: Off, Humid: Off, Save: Off", + "Power: Off, Mode: 0 (Auto), Temp: 16C, Fan: 0 (Auto), Sleep: Off, " + "Swing: Off, Light: Off, Humid: Off, Save: Off, Timer: Off", ac.toString()); } @@ -376,8 +410,8 @@ TEST(TestDecodeTeco, RealNormalExample) { ac.begin(); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 27C, Fan: 0 (Auto), Sleep: On, " - "Swing: On, Light: Off, Humid: Off, Save: Off", + "Power: On, Mode: 1 (Cool), Temp: 27C, Fan: 0 (Auto), Sleep: On, " + "Swing: On, Light: Off, Humid: Off, Save: Off, Timer: Off", ac.toString()); uint16_t rawData2[73] = { @@ -401,8 +435,8 @@ TEST(TestDecodeTeco, RealNormalExample) { ac.begin(); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Power: On, Mode: 2 (DRY), Temp: 21C, Fan: 2 (Medium), Sleep: Off, " - "Swing: On, Light: Off, Humid: Off, Save: Off", + "Power: On, Mode: 2 (Dry), Temp: 21C, Fan: 2 (Medium), Sleep: Off, " + "Swing: On, Light: Off, Humid: Off, Save: Off, Timer: Off", ac.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Toshiba_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Toshiba_test.cpp old mode 100755 new mode 100644 similarity index 99% rename from lib/IRremoteESP8266-2.6.5/test/ir_Toshiba_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Toshiba_test.cpp index 15f8e6b90..66c258ae4 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Toshiba_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Toshiba_test.cpp @@ -352,16 +352,16 @@ TEST(TestToshibaACClass, HumanReadableOutput) { 0x00, 0xC1, 0x00, 0xC0}; toshiba.setRaw(initial_state); - EXPECT_EQ("Power: On, Mode: 0 (AUTO), Temp: 17C, Fan: 0 (Auto)", + EXPECT_EQ("Power: On, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto)", toshiba.toString()); toshiba.setRaw(modified_state); - EXPECT_EQ("Power: On, Mode: 1 (COOL), Temp: 17C, Fan: 5 (High)", + EXPECT_EQ("Power: On, Mode: 1 (Cool), Temp: 17C, Fan: 5 (High)", toshiba.toString()); toshiba.off(); toshiba.setTemp(25); toshiba.setFan(3); toshiba.setMode(kToshibaAcDry); - EXPECT_EQ("Power: Off, Mode: 2 (DRY), Temp: 25C, Fan: 3 (Medium)", + EXPECT_EQ("Power: Off, Mode: 2 (Dry), Temp: 25C, Fan: 3 (Medium)", toshiba.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Trotec_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Trotec_test.cpp old mode 100755 new mode 100644 similarity index 97% rename from lib/IRremoteESP8266-2.6.5/test/ir_Trotec_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Trotec_test.cpp index f9272f384..43cb3fc06 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Trotec_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Trotec_test.cpp @@ -48,7 +48,7 @@ TEST(TestTrotecESPClass, MessageConstructon) { 0x12, 0x34, 0x29, 0x82, 0x00, 0x00, 0x00, 0x00, 0xAB}; EXPECT_STATE_EQ(expected, ac.getRaw(), kTrotecBits); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 20C, Fan: 2 (Medium), Sleep: On", + "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 2 (Medium), Sleep: On", ac.toString()); } @@ -100,7 +100,7 @@ TEST(TestDecodeTrotec, SyntheticDecode) { IRTrotecESP ac(0); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 20C, Fan: 2 (Medium), Sleep: On", + "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 2 (Medium), Sleep: On", ac.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Vestel_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Vestel_test.cpp old mode 100755 new mode 100644 similarity index 93% rename from lib/IRremoteESP8266-2.6.5/test/ir_Vestel_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Vestel_test.cpp index da95b57c4..4164386f7 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Vestel_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Vestel_test.cpp @@ -321,7 +321,7 @@ TEST(TestVestelAcClass, MessageConstuction) { IRVestelAc ac(0); EXPECT_EQ( - "Power: On, Mode: 0 (AUTO), Temp: 25C, Fan: 13 (Auto Hot), Sleep: Off, " + "Power: On, Mode: 0 (Auto), Temp: 25C, Fan: 13 (Auto Heat), Sleep: Off, " "Turbo: Off, Ion: Off, Swing: Off", ac.toString()); ac.setMode(kVestelAcCool); @@ -329,7 +329,7 @@ TEST(TestVestelAcClass, MessageConstuction) { ac.setFan(kVestelAcFanHigh); EXPECT_FALSE(ac.isTimeCommand()); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 11 (High), Sleep: Off, " + "Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 11 (High), Sleep: Off, " "Turbo: Off, Ion: Off, Swing: Off", ac.toString()); ac.setSwing(true); @@ -337,7 +337,7 @@ TEST(TestVestelAcClass, MessageConstuction) { ac.setTurbo(true); EXPECT_FALSE(ac.isTimeCommand()); EXPECT_EQ( - "Power: On, Mode: 1 (COOL), Temp: 21C, Fan: 11 (High), Sleep: Off, " + "Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 11 (High), Sleep: Off, " "Turbo: On, Ion: On, Swing: On", ac.toString()); @@ -345,7 +345,7 @@ TEST(TestVestelAcClass, MessageConstuction) { ac.setSleep(true); ac.setMode(kVestelAcHeat); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 21C, Fan: 11 (High), Sleep: On, " + "Power: On, Mode: 4 (Heat), Temp: 21C, Fan: 11 (High), Sleep: On, " "Turbo: Off, Ion: On, Swing: On", ac.toString()); EXPECT_FALSE(ac.isTimeCommand()); @@ -353,7 +353,7 @@ TEST(TestVestelAcClass, MessageConstuction) { ac.setTemp(25); ac.setPower(false); EXPECT_EQ( - "Power: Off, Mode: 4 (HEAT), Temp: 25C, Fan: 11 (High), Sleep: On, " + "Power: Off, Mode: 4 (Heat), Temp: 25C, Fan: 11 (High), Sleep: On, " "Turbo: Off, Ion: On, Swing: On", ac.toString()); EXPECT_FALSE(ac.isTimeCommand()); @@ -363,33 +363,33 @@ TEST(TestVestelAcClass, MessageConstuction) { ac.setTime(23 * 60 + 59); EXPECT_TRUE(ac.isTimeCommand()); EXPECT_EQ( - "Time: 23:59, Timer: Off, On Timer: Off, Off Timer: Off", + "Clock: 23:59, Timer: Off, On Timer: Off, Off Timer: Off", ac.toString()); ac.setTimer(8 * 60 + 0); EXPECT_TRUE(ac.isTimeCommand()); EXPECT_EQ( - "Time: 23:59, Timer: 08:00, On Timer: Off, Off Timer: Off", + "Clock: 23:59, Timer: 08:00, On Timer: Off, Off Timer: Off", ac.toString()); ac.setOnTimer(7 * 60 + 40); EXPECT_EQ( - "Time: 23:59, Timer: Off, On Timer: 07:40, Off Timer: Off", + "Clock: 23:59, Timer: Off, On Timer: 07:40, Off Timer: Off", ac.toString()); ac.setOffTimer(17 * 60 + 10); EXPECT_EQ( - "Time: 23:59, Timer: Off, On Timer: 07:40, Off Timer: 17:10", + "Clock: 23:59, Timer: Off, On Timer: 07:40, Off Timer: 17:10", ac.toString()); ac.setTimer(8 * 60 + 0); EXPECT_EQ( - "Time: 23:59, Timer: 08:00, On Timer: Off, Off Timer: Off", + "Clock: 23:59, Timer: 08:00, On Timer: Off, Off Timer: Off", ac.toString()); ac.setTimer(0); EXPECT_EQ( - "Time: 23:59, Timer: Off, On Timer: Off, Off Timer: Off", + "Clock: 23:59, Timer: Off, On Timer: Off, Off Timer: Off", ac.toString()); ac.on(); EXPECT_FALSE(ac.isTimeCommand()); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 25C, Fan: 11 (High), Sleep: On, " + "Power: On, Mode: 4 (Heat), Temp: 25C, Fan: 11 (High), Sleep: On, " "Turbo: Off, Ion: On, Swing: On", ac.toString()); } @@ -431,7 +431,7 @@ TEST(TestDecodeVestelAc, NormalDecodeWithStrict) { ac.begin(); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Power: On, Mode: 0 (AUTO), Temp: 25C, Fan: 13 (Auto Hot), Sleep: Off, " + "Power: On, Mode: 0 (Auto), Temp: 25C, Fan: 13 (Auto Heat), Sleep: Off, " "Turbo: Off, Ion: Off, Swing: Off", ac.toString()); } @@ -467,7 +467,7 @@ TEST(TestDecodeVestelAc, RealNormalExample) { ac.begin(); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Power: On, Mode: 4 (HEAT), Temp: 16C, Fan: 1 (Auto), Sleep: Off, " + "Power: On, Mode: 4 (Heat), Temp: 16C, Fan: 1 (Auto), Sleep: Off, " "Turbo: Off, Ion: On, Swing: Off", ac.toString()); } @@ -502,7 +502,7 @@ TEST(TestDecodeVestelAc, RealTimerExample) { ac.begin(); ac.setRaw(irsend.capture.value); EXPECT_EQ( - "Time: 05:45, Timer: Off, On Timer: 14:00, Off Timer: 23:00", + "Clock: 05:45, Timer: Off, On Timer: 14:00, Off Timer: 23:00", ac.toString()); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Whirlpool_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Whirlpool_test.cpp old mode 100755 new mode 100644 similarity index 97% rename from lib/IRremoteESP8266-2.6.5/test/ir_Whirlpool_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Whirlpool_test.cpp index 6349a8154..901318326 --- a/lib/IRremoteESP8266-2.6.5/test/ir_Whirlpool_test.cpp +++ b/lib/IRremoteESP8266-2.7.0/test/ir_Whirlpool_test.cpp @@ -69,9 +69,9 @@ TEST(TestDecodeWhirlpoolAC, SyntheticDecode) { IRWhirlpoolAc ac(0); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Model: 1 (DG11J13A), Power toggle: Off, Mode: 1 (AUTO), Temp: 25C, " + "Model: 1 (DG11J13A), Power Toggle: Off, Mode: 1 (Auto), Temp: 25C, " "Fan: 0 (Auto), Swing: Off, Light: On, Clock: 17:31, On Timer: Off, " - "Off Timer: Off, Sleep: Off, Super: Off, Command: 2 (TEMP)", + "Off Timer: Off, Sleep: Off, Super: Off, Command: 2 (Temp)", ac.toString()); } @@ -93,9 +93,9 @@ TEST(TestDecodeWhirlpoolAC, Real26CFanAutoCoolingSwingOnClock1918) { IRWhirlpoolAc ac(0); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Model: 1 (DG11J13A), Power toggle: Off, Mode: 2 (COOL), Temp: 26C, " + "Model: 1 (DG11J13A), Power Toggle: Off, Mode: 2 (Cool), Temp: 26C, " "Fan: 0 (Auto), Swing: On, Light: On, Clock: 19:18, On Timer: Off, " - "Off Timer: Off, Sleep: Off, Super: Off, Command: 7 (SWING)", + "Off Timer: Off, Sleep: Off, Super: Off, Command: 7 (Swing)", ac.toString()); } @@ -148,9 +148,9 @@ TEST(TestDecodeWhirlpoolAC, RealTimerExample) { IRWhirlpoolAc ac(0); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Model: 1 (DG11J13A), Power toggle: Off, Mode: 3 (DRY), Temp: 25C, " + "Model: 1 (DG11J13A), Power Toggle: Off, Mode: 3 (Dry), Temp: 25C, " "Fan: 0 (Auto), Swing: Off, Light: On, Clock: 07:35, On Timer: 07:40, " - "Off Timer: 08:05, Sleep: Off, Super: Off, Command: 5 (ONTIMER)", + "Off Timer: 08:05, Sleep: Off, Super: Off, Command: 5 (On Timer)", ac.toString()); } @@ -206,9 +206,9 @@ TEST(TestDecodeWhirlpoolAC, RealExampleDecode) { IRWhirlpoolAc ac(0); ac.setRaw(irsend.capture.state); EXPECT_EQ( - "Model: 1 (DG11J13A), Power toggle: Off, Mode: 1 (AUTO), Temp: 25C, " + "Model: 1 (DG11J13A), Power Toggle: Off, Mode: 1 (Auto), Temp: 25C, " "Fan: 0 (Auto), Swing: Off, Light: On, Clock: 17:31, On Timer: Off, " - "Off Timer: Off, Sleep: Off, Super: Off, Command: 2 (TEMP)", + "Off Timer: Off, Sleep: Off, Super: Off, Command: 2 (Temp)", ac.toString()); } @@ -556,9 +556,9 @@ TEST(TestIRWhirlpoolAcClass, MessageConstruction) { ac.enableOnTimer(true); EXPECT_EQ( - "Model: 1 (DG11J13A), Power toggle: Off, Mode: 3 (DRY), Temp: 25C, " + "Model: 1 (DG11J13A), Power Toggle: Off, Mode: 3 (Dry), Temp: 25C, " "Fan: 0 (Auto), Swing: Off, Light: On, Clock: 07:35, On Timer: 07:40, " - "Off Timer: 08:05, Sleep: Off, Super: Off, Command: 5 (ONTIMER)", + "Off Timer: 08:05, Sleep: Off, Super: Off, Command: 5 (On Timer)", ac.toString()); EXPECT_STATE_EQ(expectedState, ac.getRaw(), kWhirlpoolAcBits); } diff --git a/lib/IRremoteESP8266-2.6.5/test/ir_Whynter_test.cpp b/lib/IRremoteESP8266-2.7.0/test/ir_Whynter_test.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/test/ir_Whynter_test.cpp rename to lib/IRremoteESP8266-2.7.0/test/ir_Whynter_test.cpp diff --git a/lib/IRremoteESP8266-2.6.5/tools/Makefile b/lib/IRremoteESP8266-2.7.0/tools/Makefile old mode 100755 new mode 100644 similarity index 94% rename from lib/IRremoteESP8266-2.6.5/tools/Makefile rename to lib/IRremoteESP8266-2.7.0/tools/Makefile index d2da05eb3..bf23fbce6 --- a/lib/IRremoteESP8266-2.6.5/tools/Makefile +++ b/lib/IRremoteESP8266-2.7.0/tools/Makefile @@ -18,7 +18,7 @@ INCLUDES = -I$(USER_DIR) -I$(TEST_DIR) # Flags passed to the preprocessor. # Set Google Test's header directory as a system directory, such that # the compiler doesn't generate warnings in Google Test headers. -CPPFLAGS += -DUNIT_TEST +CPPFLAGS += -DUNIT_TEST -D_IR_LOCALE_=en-AU # Flags passed to the C++ compiler. CXXFLAGS += -g -Wall -Wextra -pthread -std=gnu++11 @@ -54,12 +54,12 @@ PROTOCOLS = ir_NEC.o ir_Sony.o ir_Samsung.o ir_JVC.o ir_RCMM.o ir_RC5_RC6.o \ ir_Trotec.o ir_Neoclima.o ir_Amcor.o # Common object files -COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o $(PROTOCOLS) +COMMON_OBJ = IRutils.o IRtimer.o IRsend.o IRrecv.o IRtext.o IRac.o $(PROTOCOLS) # Common dependencies COMMON_DEPS = $(USER_DIR)/IRrecv.h $(USER_DIR)/IRsend.h $(USER_DIR)/IRtimer.h \ $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h \ - $(TEST_DIR)/IRsend_test.h + $(TEST_DIR)/IRsend_test.h $(USER_DIR)/IRtext.h $(USER_DIR)/i18n.h # Common test dependencies COMMON_TEST_DEPS = $(COMMON_DEPS) $(TEST_DIR)/IRsend_test.h @@ -75,6 +75,9 @@ mode2_decode.o : mode2_decode.cpp $(COMMON_TEST_DEPS) $(GTEST_HEADERS) mode2_decode : $(COMMON_OBJ) mode2_decode.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ +IRtext.o : $(USER_DIR)/IRtext.cpp $(USER_DIR)/IRtext.h $(USER_DIR)/IRremoteESP8266.h $(USER_DIR)/i18n.h $(USER_DIR)/locale/*.h + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/IRtext.cpp + IRutils.o : $(USER_DIR)/IRutils.cpp $(USER_DIR)/IRutils.h $(USER_DIR)/IRremoteESP8266.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/IRutils.cpp @@ -230,3 +233,6 @@ ir_Neoclima.o : $(USER_DIR)/ir_Neoclima.cpp $(USER_DIR)/ir_Neoclima.h $(COMMON_D ir_Amcor.o : $(USER_DIR)/ir_Amcor.cpp $(USER_DIR)/ir_Amcor.h $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Amcor.cpp + +IRac.o : $(USER_DIR)/IRac.cpp $(USER_DIR)/IRac.h $(COMMON_DEPS) $(GTEST_HEADERS) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/IRac.cpp diff --git a/lib/IRremoteESP8266-2.6.5/tools/RawToGlobalCache.sh b/lib/IRremoteESP8266-2.7.0/tools/RawToGlobalCache.sh similarity index 100% rename from lib/IRremoteESP8266-2.6.5/tools/RawToGlobalCache.sh rename to lib/IRremoteESP8266-2.7.0/tools/RawToGlobalCache.sh diff --git a/lib/IRremoteESP8266-2.7.0/tools/auto_analyse_raw_data.py b/lib/IRremoteESP8266-2.7.0/tools/auto_analyse_raw_data.py new file mode 100755 index 000000000..d673d52d4 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/tools/auto_analyse_raw_data.py @@ -0,0 +1,729 @@ +#!/usr/bin/python +"""Attempt an automatic analysis of IRremoteESP8266's Raw data output. + Makes suggestions on key values and tried to break down the message + into likely chunks.""" +# +# Copyright 2018 David Conran +import argparse +import sys + + +class RawIRMessage(): + """Basic analyse functions & structure for raw IR messages.""" + + # pylint: disable=too-many-instance-attributes + + def __init__(self, margin, timings, output=sys.stdout, verbose=True): + self.ldr_mark = None + self.hdr_mark = None + self.hdr_space = None + self.bit_mark = None + self.zero_space = None + self.one_space = None + self.gaps = [] + self.margin = margin + self.marks = [] + self.mark_buckets = {} + self.spaces = [] + self.space_buckets = {} + self.output = output + self.verbose = verbose + self.section_count = 1 + self.rawlen = len(timings) + if self.rawlen <= 3: + raise ValueError("Too few message timings supplied.") + self.timings = timings + self._generate_timing_candidates() + self._calc_values() + + def _generate_timing_candidates(self): + """Determine the likely values from the given data.""" + count = 0 + for usecs in self.timings: + count = count + 1 + if count % 2: + self.marks.append(usecs) + else: + self.spaces.append(usecs) + self.marks, self.mark_buckets = self.reduce_list(self.marks) + self.spaces, self.space_buckets = self.reduce_list(self.spaces) + + def reduce_list(self, items): + """Reduce a list of numbers into buckets that are at least margin apart.""" + result = [] + last = -1 + buckets = {} + for item in sorted(items, reverse=True): + if last == -1 or item < last - self.margin: + result.append(item) + last = item + buckets[last] = [item] + else: + buckets[last].append(item) + return result, buckets + + def _usec_compare(self, seen, expected): + """Compare two usec values and see if they match within a + subtractive margin.""" + return expected - self.margin < seen <= expected + + def _usec_compares(self, usecs, expecteds): + """Compare a usec value to a list of values and return True + if they are within a subtractive margin.""" + for expected in expecteds: + if self._usec_compare(usecs, expected): + return True + return False + + def display_binary(self, binary_str): + """Display common representations of the suppied binary string.""" + num = int(binary_str, 2) + bits = len(binary_str) + rev_binary_str = binary_str[::-1] + rev_num = int(rev_binary_str, 2) + self.output.write("\n Bits: %d\n" + " Hex: %s (MSB first)\n" + " %s (LSB first)\n" + " Dec: %s (MSB first)\n" + " %s (LSB first)\n" + " Bin: 0b%s (MSB first)\n" + " 0b%s (LSB first)\n" % + (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)) + + 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) + if footer: + code.append(" // Footer") + code.append(" mark(k%sBitMark);" % name) + return code + + def add_data_decode_code(self, bin_str, name="", footer=True): + """Add the common "data" sequence code to decode the bulk of a message.""" + # pylint: disable=no-self-use + code = [] + nbits = len(bin_str) + code.extend([ + "", + " // 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), + " offset += data_result.used;", + " if (data_result.success == false) return false; // Fail", + " data <<= %s; // Make room for the new bits of data." % nbits, + " data |= data_result.data;"]) + if footer: + code.extend([ + "", + " // Footer", + " if (!matchMark(results->rawbuf[offset++], k%sBitMark))" % name, + " return false;"]) + return code + + def add_data_byte_code(self, bin_str, name="", ambles=None): + """Add the code to send the data from an array.""" + # pylint: disable=no-self-use + code = [] + nbits = len(bin_str) + nbytes = nbits / 8 + if ambles is None: + ambles = {} + firstmark = ambles.get("firstmark", 0) + firstspace = ambles.get("firstspace", 0) + lastmark = ambles.get("lastmark", "k%sBitMark" % name) + lastspace = ambles.get("lastspace", "kDefaultMessageGap") + code.append( + " // Data Section #%d" % 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), + " // *(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]) + return code + + def add_data_byte_decode_code(self, bin_str, name="", ambles=None): + """Add the common byte-wise "data" sequence decode code.""" + # pylint: disable=no-self-use + code = [] + nbits = len(bin_str) + nbytes = nbits / 8 + if nbits % 8: + code.append(" // WARNING: Nr. of bits is not a multiple of 8. " + "This section won't work!") + if ambles is None: + ambles = {} + firstmark = ambles.get("firstmark", 0) + firstspace = ambles.get("firstspace", 0) + lastmark = ambles.get("lastmark", "k%sBitMark" % name) + lastspace = ambles.get("lastspace", "kDefaultMessageGap") + + code.extend([ + "", + " // Data Section #%d" % self.section_count, + " // e.g.", + " // bits = %d; bytes = %d;" % (nbits, nbytes), + " // *(results->state + pos) = {0x%s};" % ( + ", 0x".join("%02X" % int(bin_str[i:i + 8], 2) + for i in range(0, len(bin_str), 8))), + " 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), + " 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]) + 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))) + # The bit mark is likely to be the smallest mark. + self.bit_mark = self.marks[-1] + if len(self.marks) > 2: # Possible leader mark? + self.ldr_mark = self.marks[0] + self.hdr_mark = self.marks[1] + else: + # Largest mark is likely the kHdrMark + self.hdr_mark = self.marks[0] + + if self.is_space_encoded() and len(self.spaces) >= 3: + if self.verbose and len(self.marks) > 2: + self.output.write("DANGER: Unusual number of mark timings!") + # We should have 3 space candidates at least. + # They should be: zero_space (smallest), one_space, & hdr_space (largest) + spaces = list(self.spaces) + self.zero_space = spaces.pop() + self.one_space = spaces.pop() + self.hdr_space = spaces.pop() + # Rest are probably message gaps + self.gaps = spaces + + def is_space_encoded(self): + """Make an educated guess if the message is space encoded.""" + return len(self.spaces) > len(self.marks) + + def is_ldr_mark(self, usec): + """Is usec the leader mark?""" + if self.ldr_mark is None: + return False + return self._usec_compare(usec, self.ldr_mark) + + def is_hdr_mark(self, usec): + """Is usec the header mark?""" + return self._usec_compare(usec, self.hdr_mark) + + def is_hdr_space(self, usec): + """Is usec the header space?""" + return self._usec_compare(usec, self.hdr_space) + + def is_bit_mark(self, usec): + """Is usec the bit mark?""" + return self._usec_compare(usec, self.bit_mark) + + def is_one_space(self, usec): + """Is usec the one space?""" + return self._usec_compare(usec, self.one_space) + + def is_zero_space(self, usec): + """Is usec the zero_space?""" + return self._usec_compare(usec, self.zero_space) + + def is_gap(self, usec): + """Is usec the a space gap?""" + return self._usec_compares(usec, self.gaps) + + +def avg_list(items): + """Return the average of a list of numbers.""" + if items: + return int(sum(items) / len(items)) + return 0 + + +def add_bit(so_far, bit, output=sys.stdout): + """Add a bit to the end of the bits collected so far.""" + if bit == "reset": + return "" + output.write(str(bit)) # This effectively displays in LSB first order. + return so_far + str(bit) # Storing it in MSB first order. + + +def convert_rawdata(data_str): + """Parse a C++ rawdata declaration into a list of values.""" + start = data_str.find('{') + end = data_str.find('}') + if end == -1: + end = len(data_str) + if start > end: + raise ValueError("Raw Data not parsible due to parentheses placement.") + data_str = data_str[start + 1:end] + results = [] + for timing in [x.strip() for x in data_str.split(',')]: + try: + results.append(int(timing)) + except ValueError: + raise ValueError( + "Raw Data contains a non-numeric value of '%s'." % timing) + return results + + +def dump_constants(message, defines, name="", output=sys.stdout): + """Dump the key constants and generate the C++ #defines.""" + ldr_mark = None + if message.ldr_mark is not None: + ldr_mark = avg_list(message.mark_buckets[message.ldr_mark]) + hdr_mark = avg_list(message.mark_buckets[message.hdr_mark]) + bit_mark = avg_list(message.mark_buckets[message.bit_mark]) + hdr_space = avg_list(message.space_buckets[message.hdr_space]) + one_space = avg_list(message.space_buckets[message.one_space]) + 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)) + if ldr_mark: + output.write("k%sLdrMark = %d\n" % (name, ldr_mark)) + defines.append("const uint16_t k%sLdrMark = %d;" % (name, 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])) + 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) + + +def parse_and_report(rawdata_str, margin, gen_code=False, name="", + output=sys.stdout): + """Analyse the rawdata c++ definition of a IR message.""" + defines = [] + code = {} + code["send"] = [] + code["send64+"] = [] + code["recv"] = [] + code["recv64+"] = [] + + # Parse the input. + rawdata = convert_rawdata(rawdata_str) + + output.write("Found %d timing entries.\n" % len(rawdata)) + + message = RawIRMessage(margin, rawdata, output) + output.write("\nGuessing encoding type:\n") + if message.is_space_encoded(): + output.write("Looks like it uses space encoding. Yay!\n\n") + dump_constants(message, defines, name, output) + else: + output.write("Sorry, it looks like it is Mark encoded. " + "I can't do that yet. Exiting.\n") + sys.exit(1) + total_bits = decode_data(message, defines, code, name, output) + if gen_code: + generate_code(defines, code, total_bits, name, output) + + +def decode_data(message, defines, code, name="", output=sys.stdout): + """Decode the data sequence with the given values in mind.""" + # pylint: disable=too-many-branches,too-many-statements + + # Now we have likely candidates for the key values, go through the original + # sequence and break it up and indicate accordingly. + + output.write("\nDecoding protocol based on analysis so far:\n\n") + state = "" + code_info = {} + count = 1 + total_bits = "" + binary_value = binary64_value = add_bit("", "reset") + if name: + def_name = name + else: + def_name = "TBD" + + code["send"].extend([ + "#if SEND_%s" % def_name.upper(), + "// Function should be safe up to 64 bits.", + "void IRsend::send%s(const uint64_t data, const uint16_t" + " nbits, const uint16_t repeat) {" % def_name, + " enableIROut(k%sFreq);" % name, + " for (uint16_t r = 0; r <= repeat; r++) {", + " uint64_t send_data = data;"]) + code["send64+"].extend([ + "// Args:", + "// data: An array of bytes containing the IR command.", + "// It is assumed to be in MSB order for this code.\n" + "// nbytes: Nr. of bytes of data in the array." + " (>=k%sStateLength)" % name, + "// repeat: Nr. of times the message is to be repeated.", + "//", + "// Status: ALPHA / Untested.", + "void IRsend::send%s(const uint8_t data[], const uint16_t nbytes," + " const uint16_t repeat) {" % def_name, + " for (uint16_t r = 0; r <= repeat; r++) {", + " uint16_t pos = 0;"]) + code["recv"].extend([ + "#if DECODE_%s" % def_name.upper(), + "// Function should be safe up to 64 bits.", + "bool IRrecv::decode%s(decode_results *results, const uint16_t nbits," + " const bool strict) {" % def_name, + " if (results->rawlen < 2 * nbits + k%sOverhead)" % name, + " return false; // Too short a message to match.", + " if (strict && nbits != k%sBits)" % name, + " return false;", + "", + " uint16_t offset = kStartOffset;", + " uint64_t data = 0;", + " match_result_t data_result;"]) + code["recv64+"].extend([ + "#if DECODE_%s" % def_name.upper(), + "// Function should be safe over 64 bits.", + "bool IRrecv::decode%s(decode_results *results, const uint16_t nbits," + " const bool strict) {" % def_name, + " if (results->rawlen < 2 * nbits + k%sOverhead)" % name, + " return false; // Too short a message to match.", + " if (strict && nbits != k%sBits)" % name, + " return false;", + "", + " uint16_t offset = kStartOffset;", + " uint16_t pos = 0;", + " uint16_t used = 0;"]) + + # states are: + # HM: Header/Leader mark + # HS: Header space + # BM: Bit mark + # BS: Bit space + # GS: Gap space + # UNK: Unknown state. + for usec in message.timings: + # Handle header/leader marks. + if ((message.is_hdr_mark(usec) or message.is_ldr_mark(usec)) and + count % 2 and not message.is_bit_mark(usec)): + state = "HM" + if message.is_hdr_mark(usec): + mark_type = "H" # Header + else: + mark_type = "L" # Leader + if binary_value: + message.display_binary(binary_value) + code["send"].extend(message.add_data_code(binary_value, name, False)) + 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) + total_bits = total_bits + binary_value + code_info["firstmark"] = "k%s%sdrMark" % (name, mark_type) + 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)]) + code["recv"].extend([ + "", + " // %seader" % mark_type, + " if (!matchMark(results->rawbuf[offset++], k%s%sdrMark))" % ( + name, mark_type), + " 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 + message.section_count = message.section_count - 1 + code["send64+"].extend(message.add_data_byte_code(binary64_value, name, + code_info)) + code["recv64+"].extend(message.add_data_byte_decode_code(binary64_value, + name, + code_info)) + code_info.clear() + binary64_value = binary_value + message.section_count = message.section_count + 1 + if state != "HM": + if binary_value: # If we we are in a header and we have data, add it. + message.display_binary(binary_value) + 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 + 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) + code["recv"].extend([ + " if (!matchSpace(results->rawbuf[offset++], k%sHdrSpace))" % name, + " return false;"]) + code_info["firstspace"] = "k%sHdrSpace" % name + # Handle bit marks. + elif message.is_bit_mark(usec) and count % 2: + if state not in ("HS", "BS"): + output.write("k%sBitMark(UNEXPECTED)" % name) + state = "BM" + # Handle "zero" spaces + elif message.is_zero_space(usec): + if state != "BM": + output.write("k%sZeroSpace(UNEXPECTED)" % name) + 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) + 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 + if binary64_value: + code["send64+"].extend(message.add_data_byte_code(binary64_value, name, + code_info)) + code["recv64+"].extend(message.add_data_byte_decode_code(binary64_value, + name, + code_info)) + code_info.clear() + if binary_value: + message.display_binary(binary_value) + code["send"].extend(message.add_data_code(binary_value, name)) + code["recv"].extend(message.add_data_decode_code(binary_value, name)) + message.section_count = message.section_count + 1 + else: + code["recv"].extend(["", + " // Gap"]) + code["send"].extend([" // Gap"]) + if state == "BM": + code["send"].extend([" mark(k%sBitMark);" % name]) + code["recv"].extend([ + " if (!matchMark(results->rawbuf[offset++], k%sBitMark))" % name, + " return false;"]) + code["send"].append(" space(k%sSpaceGap);" % name) + code["recv"].extend([ + " if (!matchSpace(results->rawbuf[offset++], k%sSpaceGap))" % name, + " 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) + state = "UNK" + count = count + 1 + if binary64_value: + code["send64+"].extend(message.add_data_byte_code(binary64_value, name, + code_info)) + code["recv64+"].extend(message.add_data_byte_decode_code(binary64_value, + name, code_info)) + code_info.clear() + if binary_value: + message.display_binary(binary_value) + code["send"].extend(message.add_data_code(binary_value, name)) + code["recv"].extend(message.add_data_decode_code(binary_value, name)) + message.section_count = message.section_count + 1 + code["send"].extend([ + " space(kDefaultMessageGap); // A 100% made up guess of the gap" + " between messages.", + " }", + "}", + "#endif // SEND_%s" % def_name.upper()]) + code["send64+"].extend([ + " }", + "}", + "#endif // SEND_%s" % def_name.upper()]) + code["recv"].extend([ + "", + " // Success", + " results->decode_type = decode_type_t::%s;" % def_name.upper(), + " results->bits = nbits;", + " results->value = data;", + " results->command = 0;", + " results->address = 0;", + " return true;", + "}", + "#endif // DECODE_%s" % def_name.upper()]) + code["recv64+"].extend([ + "", + " // Success", + " results->decode_type = decode_type_t::%s;" % def_name.upper(), + " results->bits = nbits;", + " return true;", + "}", + "#endif // DECODE_%s" % def_name.upper()]) + + 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))) + 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))) + return total_bits + + +def generate_code(defines, code, bits_str, name="", output=sys.stdout): + """Output the estimated C++ code to reproduce & decode the IR message.""" + if name: + def_name = name + else: + def_name = "TBD" + output.write("\nGenerating a VERY rough code outline:\n\n" + "// Copyright 2019 David Conran (crankyoldgit)\n" + "// Support for %s protocol\n\n" + '#include "IRrecv.h"\n' + '#include "IRsend.h"\n' + '#include "IRutils.h"\n\n' + "// WARNING: This probably isn't directly usable." + " It's a guide only.\n\n" + "// 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) + for line in defines: + output.write("%s\n" % line) + + if len(bits_str) > 64: # Will it fit in a uint64_t? + output.write("// DANGER: More than 64 bits detected. A uint64_t for " + "'data' won't work!\n") + # Display the "normal" version's send code incase there are some + # oddities in it. + for line in code["send"]: + output.write("%s\n" % line) + + if len(bits_str) > 64: # Will it fit in a uint64_t? + code["send64+"] = [ + "", + "#if SEND_%s" % def_name.upper(), + "// Alternative >64bit function to send %s messages" % def_name.upper(), + "// Where data is:", + "// 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))), + "//"] + code["send64+"] + for line in code["send64+"]: + output.write("%s\n" % line) + output.write("\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 " + "'data' won't work!\n") + # Display the "normal" version's decode code incase there are some + # oddities in it. + for line in code["recv"]: + output.write("%s\n" % line) + # Display the > 64bit version's decode code + if len(bits_str) > 64: # Is it too big for a uint64_t? + output.write("\n// Note: This should be 64+ bit safe.\n") + if len(bits_str) % 8: + output.write("\n// WARNING: Data is not a multiple of bytes. " + "This won't work!\n") + for line in code["recv64+"]: + output.write("%s\n" % line) + + +def main(): + """Parse the commandline arguments and call the method.""" + arg_parser = argparse.ArgumentParser( + description="Read an IRremoteESP8266 rawData declaration and tries to " + "analyse it.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + arg_parser.add_argument( + "-g", + "--code", + action="store_true", + default=False, + dest="gen_code", + help="Generate a C++ code outline to aid making an IRsend function.") + arg_parser.add_argument( + "-n", + "--name", + help="Name of the protocol/device to use in code generation. E.g. Onkyo", + dest="name", + default="") + arg_group = arg_parser.add_mutually_exclusive_group(required=True) + arg_group.add_argument( + "rawdata", + help="A rawData line from IRrecvDumpV2. e.g. 'uint16_t rawbuf[37] = {" + "7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494, " + "520, 494, 1482, 494, 1482, 494, 3978, 494, 520, 494, 520, 494, 520, " + "494, 520, 520, 520, 494, 520, 494, 520, 494, 520, 494};'", + nargs="?") + arg_group.add_argument( + "-f", "--file", help="Read in a rawData line from the file.") + arg_parser.add_argument( + "-r", + "--range", + type=int, + help="Max number of micro-seconds difference between values to consider" + " it the same value.", + dest="margin", + default=200) + arg_group.add_argument( + "--stdin", + help="Read in a rawData line from STDIN.", + action="store_true", + default=False) + arg_options = arg_parser.parse_args() + + if arg_options.stdin: + data = sys.stdin.read() + elif arg_options.file: + with open(arg_options.file) as input_file: + data = input_file.read() + else: + data = arg_options.rawdata + parse_and_report(data, arg_options.margin, arg_options.gen_code, + arg_options.name) + + +if __name__ == '__main__': + main() diff --git a/lib/IRremoteESP8266-2.7.0/tools/auto_analyse_raw_data_test.py b/lib/IRremoteESP8266-2.7.0/tools/auto_analyse_raw_data_test.py new file mode 100755 index 000000000..c2fd7ba64 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/tools/auto_analyse_raw_data_test.py @@ -0,0 +1,1170 @@ +#!/usr/bin/python3 +"""Unit tests for auto_analyse_raw_data.py""" +from io import StringIO +import unittest +import auto_analyse_raw_data as analyse + +# pylint: disable=too-many-lines + +class TestRawIRMessage(unittest.TestCase): + """Unit tests for the RawIRMessage class.""" + + # pylint: disable=too-many-public-methods + + def test_display_binary(self): + """Test the display_binary() method.""" + output = StringIO() + message = analyse.RawIRMessage(100, [8000, 4000, 500, 500, 500], output, + False) + self.assertEqual(output.getvalue(), '') + message.display_binary("10101010") + message.display_binary("0000000000000000") + message.display_binary("00010010001101000101011001111000") + self.assertEqual( + output.getvalue(), '\n' + ' Bits: 8\n' + ' Hex: 0xAA (MSB first)\n' + ' 0x55 (LSB first)\n' + ' Dec: 170 (MSB first)\n' + ' 85 (LSB first)\n' + ' Bin: 0b10101010 (MSB first)\n' + ' 0b01010101 (LSB first)\n' + '\n' + ' Bits: 16\n' + ' Hex: 0x0000 (MSB first)\n' + ' 0x0000 (LSB first)\n' + ' Dec: 0 (MSB first)\n' + ' 0 (LSB first)\n' + ' Bin: 0b0000000000000000 (MSB first)\n' + ' 0b0000000000000000 (LSB first)\n' + '\n' + ' Bits: 32\n' + ' Hex: 0x12345678 (MSB first)\n' + ' 0x1E6A2C48 (LSB first)\n' + ' Dec: 305419896 (MSB first)\n' + ' 510274632 (LSB first)\n' + ' Bin: 0b00010010001101000101011001111000 (MSB first)\n' + ' 0b00011110011010100010110001001000 (LSB first)\n') + + +class TestAutoAnalyseRawData(unittest.TestCase): + """Unit tests for the functions in AutoAnalyseRawData.""" + + # pylint: disable=too-many-public-methods + + def test_avg_list(self): + """Tests for the avg_list method.""" + + self.assertEqual(0, analyse.avg_list([])) + self.assertEqual(23, analyse.avg_list([10, 20, 40])) + + def test_dump_constants_simple(self): + """Simple tests for the dump_constants() function.""" + ignore = StringIO() + output = StringIO() + defs = [] + message = analyse.RawIRMessage(200, [ + 7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494, + 520, 494, 1482, 494, 1482, 494, 3978, 494, 520, 494, 520, 494, 520, 494, + 520, 520, 520, 494, 520, 494, 520, 494, 1482, 494 + ], ignore) + analyse.dump_constants(message, defs, "BAR", output) + self.assertEqual(defs, [ + 'const uint16_t kBARHdrMark = 7930;', + 'const uint16_t kBARBitMark = 496;', + 'const uint16_t kBARHdrSpace = 3965;', + 'const uint16_t kBAROneSpace = 1485;', + 'const uint16_t kBARZeroSpace = 520;', + 'const uint16_t kBARFreq = 38000; // Hz. (Guessing the most common ' + 'frequency.)' + ]) + self.assertEqual( + output.getvalue(), 'Guessing key value:\n' + 'kBARHdrMark = 7930\n' + 'kBARHdrSpace = 3965\n' + 'kBARBitMark = 496\n' + 'kBAROneSpace = 1485\n' + 'kBARZeroSpace = 520\n') + + def test_dump_constants_aircon(self): + """More complex tests for the dump_constants() function.""" + ignore = StringIO() + output = StringIO() + defs = [] + message = analyse.RawIRMessage(200, [ + 9008, 4496, 644, 1660, 676, 530, 648, 558, 672, 1636, 646, 1660, 644, + 556, 650, 584, 626, 560, 644, 580, 628, 1680, 624, 560, 648, 1662, 644, + 582, 648, 536, 674, 530, 646, 580, 628, 560, 670, 532, 646, 562, 644, + 556, 672, 536, 648, 1662, 646, 1660, 652, 554, 644, 558, 672, 538, 644, + 560, 668, 560, 648, 1638, 668, 536, 644, 1660, 668, 532, 648, 560, 648, + 1660, 674, 554, 622, 19990, 646, 580, 624, 1660, 648, 556, 648, 558, + 674, 556, 622, 560, 644, 564, 668, 536, 646, 1662, 646, 1658, 672, 534, + 648, 558, 644, 562, 648, 1662, 644, 584, 622, 558, 648, 562, 668, 534, + 670, 536, 670, 532, 672, 536, 646, 560, 646, 558, 648, 558, 670, 534, + 650, 558, 646, 560, 646, 560, 668, 1638, 646, 1662, 646, 1660, 646, + 1660, 648 + ], ignore) + analyse.dump_constants(message, defs, "TEST", output) + self.assertEqual(defs, [ + 'const uint16_t kTESTHdrMark = 9008;', + 'const uint16_t kTESTBitMark = 650;', + 'const uint16_t kTESTHdrSpace = 4496;', + 'const uint16_t kTESTOneSpace = 1657;', + 'const uint16_t kTESTZeroSpace = 554;', + 'const uint16_t kTESTSpaceGap = 19990;', + 'const uint16_t kTESTFreq = 38000; // Hz. (Guessing the most common ' + 'frequency.)' + ]) + self.assertEqual( + output.getvalue(), 'Guessing key value:\n' + 'kTESTHdrMark = 9008\n' + 'kTESTHdrSpace = 4496\n' + 'kTESTBitMark = 650\n' + 'kTESTOneSpace = 1657\n' + 'kTESTZeroSpace = 554\n' + 'kTESTSpaceGap = 19990\n') + + def test_convert_rawdata(self): + """Tests for the convert_rawdata() function.""" + # trivial cases + self.assertEqual(analyse.convert_rawdata("0"), [0]) + with self.assertRaises(ValueError) as context: + analyse.convert_rawdata("") + self.assertEqual( + str(context.exception), "Raw Data contains a non-numeric value of ''.") + + # Single parenthesis + self.assertEqual(analyse.convert_rawdata("foo {10"), [10]) + self.assertEqual(analyse.convert_rawdata("20} bar"), [20]) + + # No parentheses + self.assertEqual(analyse.convert_rawdata("10,20 , 30"), [10, 20, 30]) + + # Dual parentheses + self.assertEqual(analyse.convert_rawdata("{10,20 , 30}"), [10, 20, 30]) + self.assertEqual(analyse.convert_rawdata("foo{10,20}bar"), [10, 20]) + + # Many parentheses + self.assertEqual(analyse.convert_rawdata("foo{10,20}{bar}"), [10, 20]) + self.assertEqual(analyse.convert_rawdata("foo{10,20}{bar}}{"), [10, 20]) + + # Bad parentheses + with self.assertRaises(ValueError) as context: + analyse.convert_rawdata("}10{") + self.assertEqual( + str(context.exception), + "Raw Data not parsible due to parentheses placement.") + + # Non base-10 values + with self.assertRaises(ValueError) as context: + analyse.convert_rawdata("10, 20, foo, bar, 30") + self.assertEqual( + str(context.exception), + "Raw Data contains a non-numeric value of 'foo'.") + + # A messy usual "good" case. + input_str = """uint16_t rawbuf[6] = { + 9008, 4496, 644, + 1660, 676, + + 530} + ;""" + self.assertEqual( + analyse.convert_rawdata(input_str), [9008, 4496, 644, 1660, 676, 530]) + + def test_parse_and_report(self): + """Tests for the parse_and_report() function.""" + + # Without code generation. + output = StringIO() + input_str = """ + uint16_t rawbuf[139] = {9008, 4496, 644, 1660, 676, 530, 648, 558, 672, + 1636, 646, 1660, 644, 556, 650, 584, 626, 560, 644, 580, 628, 1680, + 624, 560, 648, 1662, 644, 582, 648, 536, 674, 530, 646, 580, 628, + 560, 670, 532, 646, 562, 644, 556, 672, 536, 648, 1662, 646, 1660, + 652, 554, 644, 558, 672, 538, 644, 560, 668, 560, 648, 1638, 668, + 536, 644, 1660, 668, 532, 648, 560, 648, 1660, 674, 554, 622, 19990, + 646, 580, 624, 1660, 648, 556, 648, 558, 674, 556, 622, 560, 644, + 564, 668, 536, 646, 1662, 646, 1658, 672, 534, 648, 558, 644, 562, + 648, 1662, 644, 584, 622, 558, 648, 562, 668, 534, 670, 536, 670, + 532, 672, 536, 646, 560, 646, 558, 648, 558, 670, 534, 650, 558, + 646, 560, 646, 560, 668, 1638, 646, 1662, 646, 1660, 646, 1660, + 648};""" + analyse.parse_and_report(input_str, 200, False, "FOO", output) + self.assertEqual( + output.getvalue(), 'Found 139 timing entries.\n' + 'Potential Mark Candidates:\n' + '[9008, 676]\n' + 'Potential Space Candidates:\n' + '[19990, 4496, 1680, 584]\n' + '\n' + 'Guessing encoding type:\n' + 'Looks like it uses space encoding. Yay!\n' + '\n' + 'Guessing key value:\n' + 'kFOOHdrMark = 9008\n' + 'kFOOHdrSpace = 4496\n' + 'kFOOBitMark = 650\n' + 'kFOOOneSpace = 1657\n' + 'kFOOZeroSpace = 554\n' + 'kFOOSpaceGap = 19990\n' + '\n' + 'Decoding protocol based on analysis so far:\n' + '\n' + 'kFOOHdrMark+kFOOHdrSpace+10011000010100000000011000001010010GAP(19990)' + '\n' + ' Bits: 35\n' + ' Hex: 0x4C2803052 (MSB first)\n' + ' 0x250600A19 (LSB first)\n' + ' Dec: 20443050066 (MSB first)\n' + ' 9938405913 (LSB first)\n' + ' Bin: 0b10011000010100000000011000001010010 (MSB first)\n' + ' 0b01001010000011000000000101000011001 (LSB first)\n' + 'kFOOBitMark(UNEXPECTED)01000000110001000000000000001111\n' + ' Bits: 32\n' + ' Hex: 0x40C4000F (MSB first)\n' + ' 0xF0002302 (LSB first)\n' + ' Dec: 1086586895 (MSB first)\n' + ' 4026540802 (LSB first)\n' + ' Bin: 0b01000000110001000000000000001111 (MSB first)\n' + ' 0b11110000000000000010001100000010 (LSB first)\n' + '\n' + 'Total Nr. of suspected bits: 67\n') + + # With code generation. + output = StringIO() + input_str = """ + uint16_t rawbuf[37] = {7930, 3952, 494, 1482, 520, 1482, 494, + 1508, 494, 520, 494, 1482, 494, 520, 494, 1482, 494, 1482, 494, + 3978, 494, 520, 494, 520, 494, 520, 494, 520, 520, 520, 494, 520, + 494, 520, 494, 1482, 494};""" + analyse.parse_and_report(input_str, 200, True, "FOO", output) + self.assertEqual( + output.getvalue(), 'Found 37 timing entries.\n' + 'Potential Mark Candidates:\n' + '[7930, 520]\n' + 'Potential Space Candidates:\n' + '[3978, 1508, 520]\n' + '\n' + 'Guessing encoding type:\n' + 'Looks like it uses space encoding. Yay!\n' + '\n' + 'Guessing key value:\n' + 'kFOOHdrMark = 7930\n' + 'kFOOHdrSpace = 3965\n' + 'kFOOBitMark = 496\n' + 'kFOOOneSpace = 1485\n' + 'kFOOZeroSpace = 520\n' + '\n' + 'Decoding protocol based on analysis so far:\n' + '\n' + 'kFOOHdrMark+kFOOHdrSpace+11101011\n' + ' Bits: 8\n' + ' Hex: 0xEB (MSB first)\n' + ' 0xD7 (LSB first)\n' + ' Dec: 235 (MSB first)\n' + ' 215 (LSB first)\n' + ' Bin: 0b11101011 (MSB first)\n' + ' 0b11010111 (LSB first)\n' + 'UNEXPECTED->kFOOHdrSpace+00000001\n' + ' Bits: 8\n' + ' Hex: 0x01 (MSB first)\n' + ' 0x80 (LSB first)\n' + ' Dec: 1 (MSB first)\n' + ' 128 (LSB first)\n' + ' Bin: 0b00000001 (MSB first)\n' + ' 0b10000000 (LSB first)\n' + '\n' + 'Total Nr. of suspected bits: 16\n' + '\n' + 'Generating a VERY rough code outline:\n' + '\n' + '// Copyright 2019 David Conran (crankyoldgit)\n' + '// Support for FOO protocol\n' + '\n' + '#include "IRrecv.h"\n' + '#include "IRsend.h"\n' + '#include "IRutils.h"\n' + '\n' + "// WARNING: This probably isn't directly usable. It's a guide only.\n" + '\n' + '// 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' + 'const uint16_t kFOOHdrMark = 7930;\n' + 'const uint16_t kFOOBitMark = 496;\n' + 'const uint16_t kFOOHdrSpace = 3965;\n' + 'const uint16_t kFOOOneSpace = 1485;\n' + 'const uint16_t kFOOZeroSpace = 520;\n' + 'const uint16_t kFOOFreq = 38000; // Hz. (Guessing the most common' + ' frequency.)\n' + 'const uint16_t kFOOBits = 16; // Move to IRremoteESP8266.h\n' + 'const uint16_t kFOOOverhead = 5;\n' + '#if SEND_FOO\n' + '// Function should be safe up to 64 bits.\n' + 'void IRsend::sendFOO(const uint64_t data, const uint16_t nbits,' + ' const uint16_t repeat) {\n' + ' enableIROut(kFOOFreq);\n' + ' for (uint16_t r = 0; r <= repeat; r++) {\n' + ' uint64_t send_data = data;\n' + ' // Header\n' + ' mark(kFOOHdrMark);\n' + ' space(kFOOHdrSpace);\n' + ' // Data Section #1\n' + ' // e.g. data = 0xEB, nbits = 8\n' + ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' + ' send_data, 8, true);\n' + ' send_data >>= 8;\n' + ' // Footer\n' + ' mark(kFOOBitMark);\n' + ' space(kFOOHdrSpace);\n' + ' // Data Section #2\n' + ' // e.g. data = 0x1, nbits = 8\n' + ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' + ' send_data, 8, true);\n' + ' send_data >>= 8;\n' + ' // Footer\n' + ' mark(kFOOBitMark);\n' + ' space(kDefaultMessageGap); // A 100% made up guess of the gap' + ' between messages.\n' + ' }\n' + '}\n' + '#endif // SEND_FOO\n' + '\n' + '#if DECODE_FOO\n' + '// Function should be safe up to 64 bits.\n' + 'bool IRrecv::decodeFOO(decode_results *results, const uint16_t nbits,' + ' const bool strict) {\n' + ' if (results->rawlen < 2 * nbits + kFOOOverhead)\n' + ' return false; // Too short a message to match.\n' + ' if (strict && nbits != kFOOBits)\n' + ' return false;\n' + '\n' + ' uint16_t offset = kStartOffset;\n' + ' uint64_t data = 0;\n' + ' match_result_t data_result;\n' + '\n' + ' // Header\n' + ' if (!matchMark(results->rawbuf[offset++], kFOOHdrMark))\n' + ' return false;\n' + ' if (!matchSpace(results->rawbuf[offset++], kFOOHdrSpace))\n' + ' return false;\n' + '\n' + ' // Data Section #1\n' + ' // e.g. data_result.data = 0xEB, nbits = 8\n' + ' data_result = matchData(&(results->rawbuf[offset]), 8,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace);\n' + ' offset += data_result.used;\n' + ' if (data_result.success == false) return false; // Fail\n' + ' data <<= 8; // Make room for the new bits of data.\n' + ' data |= data_result.data;\n' + '\n' + ' // Footer\n' + ' if (!matchMark(results->rawbuf[offset++], kFOOBitMark))\n' + ' return false;\n' + ' if (!matchSpace(results->rawbuf[offset++], kFOOHdrSpace))\n' + ' return false;\n' + '\n' + ' // Data Section #2\n' + ' // e.g. data_result.data = 0x1, nbits = 8\n' + ' data_result = matchData(&(results->rawbuf[offset]), 8,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace);\n' + ' offset += data_result.used;\n' + ' if (data_result.success == false) return false; // Fail\n' + ' data <<= 8; // Make room for the new bits of data.\n' + ' data |= data_result.data;\n' + '\n' + ' // Footer\n' + ' if (!matchMark(results->rawbuf[offset++], kFOOBitMark))\n' + ' return false;\n' + '\n' + ' // Success\n' + ' results->decode_type = decode_type_t::FOO;\n' + ' results->bits = nbits;\n' + ' results->value = data;\n' + ' results->command = 0;\n' + ' results->address = 0;\n' + ' return true;\n' + '}\n' + '#endif // DECODE_FOO\n') + + def test_reduce_list(self): + """Tests for the reduce_list method.""" + + ignore = StringIO() + message = analyse.RawIRMessage(200, [ + 7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494, + 520, 494, 1482, 494, 1482, 494, 3978, 494, 520, 494, 520, 494, 520, 494, + 520, 520, 520, 494, 520, 494, 520, 494, 1482, 494 + ], ignore) + test_space_data = [4496, 1660, 530, 558, 1636, 1660, 556] + result_list, result_dict = message.reduce_list(test_space_data) + self.assertEqual([4496, 1660, 558], result_list) + self.assertEqual({ + 558: [558, 556, 530], + 1660: [1660, 1660, 1636], + 4496: [4496] + }, result_dict) + + def test_leader_marks(self): + """Tests for leader-type marks in parse_and_report() function.""" + + # Ref Issue #973 + output = StringIO() + input_str = """ + uint16_t rawData[853] = { + 29784, 49290, 3416, 1604, 464, 1210, 468, 372, 460, 374, 462, 374, + 466, 368, 464, 372, 462, 374, 464, 374, 464, 368, 464, 370, 464, 370, + 466, 370, 464, 1208, 464, 374, 462, 372, 466, 374, 464, 370, 462, 372, + 464, 370, 466, 370, 464, 372, 462, 374, 462, 374, 462, 378, 460, 370, + 460, 374, 464, 372, 462, 372, 464, 374, 466, 368, 464, 1210, 464, 374, + 466, 1202, 464, 1206, 464, 1210, 466, 1206, 468, 1204, 464, 1210, 466, + 370, 462, 1214, 460, 1208, 464, 1206, 464, 1208, 466, 1208, 464, 1206, + 466, 1208, 464, 1206, 466, 1212, 464, 370, 464, 370, 462, 374, 462, + 374, 462, 374, 462, 374, 462, 372, 464, 376, 460, 372, 462, 374, 466, + 1204, 464, 1210, 464, 372, 460, 374, 462, 1208, 464, 1212, 464, 1202, + 468, 1204, 464, 374, 460, 374, 466, 1208, 462, 1210, 462, 374, 462, + 376, 464, 368, 466, 1204, 462, 374, 466, 372, 464, 1206, 462, 376, + 460, 376, 464, 1210, 462, 1208, 462, 372, 466, 1206, 464, 1208, 466, + 372, 462, 1210, 462, 1210, 466, 374, 468, 1202, 464, 1206, 466, 374, + 462, 372, 464, 1208, 464, 374, 464, 372, 464, 376, 462, 370, 466, 368, + 464, 1208, 462, 1210, 460, 374, 464, 1208, 466, 1206, 464, 1214, 464, + 368, 462, 374, 462, 1212, 460, 1210, 466, 1206, 466, 370, 462, 1210, + 464, 416, 424, 1202, 466, 1220, 448, 376, 464, 372, 462, 372, 462, + 1212, 462, 374, 460, 1214, 468, 364, 468, 370, 462, 372, 462, 376, + 458, 374, 464, 372, 462, 376, 464, 376, 462, 1204, 464, 1210, 462, + 1210, 464, 1208, 466, 1208, 464, 1206, 462, 1210, 464, 1212, 464, 368, + 462, 372, 464, 372, 464, 372, 464, 372, 466, 370, 466, 370, 464, 376, + 464, 1202, 464, 1212, 464, 1204, 464, 1210, 462, 1208, 464, 1212, 462, + 1210, 464, 1212, 460, 372, 462, 374, 462, 374, 466, 370, 462, 374, 462, + 372, 464, 372, 462, 376, 462, 1206, 464, 1206, 466, 1210, 462, 1208, + 464, 1210, 466, 1204, 464, 1210, 462, 1214, 462, 368, 462, 374, 466, + 370, 462, 376, 466, 368, 466, 370, 462, 414, 424, 374, 464, 1206, 464, + 1206, 464, 1206, 468, 1206, 466, 1206, 466, 1210, 462, 1206, 464, 1214, + 468, 364, 466, 372, 466, 370, 462, 372, 462, 374, 464, 372, 462, 374, + 460, 376, 466, 1204, 464, 1208, 462, 1210, 464, 1206, 464, 1210, 464, + 1208, 464, 1208, 466, 1210, 462, 1206, 466, 1206, 466, 372, 462, 374, + 466, 1206, 466, 370, 464, 1206, 466, 376, 464, 368, 462, 372, 466, + 1206, 464, 1206, 464, 374, 466, 1204, 464, 374, 466, 1206, 466, 1204, + 468, 368, 466, 370, 466, 370, 462, 1212, 462, 1210, 462, 1210, 462, + 1214, 464, 368, 464, 1206, 466, 1206, 466, 1206, 464, 374, 464, 370, + 466, 370, 462, 378, 466, 366, 464, 372, 466, 368, 466, 370, 464, 370, + 462, 372, 462, 374, 464, 374, 464, 1202, 466, 1206, 462, 1208, 466, + 1208, 466, 1208, 464, 1210, 462, 1206, 464, 1212, 464, 368, 464, 372, + 464, 370, 468, 368, 462, 376, 462, 372, 466, 370, 464, 376, 462, 1206, + 464, 1210, 462, 1212, 462, 1208, 464, 1208, 462, 1212, 466, 1246, 424, + 1212, 464, 368, 464, 372, 466, 370, 464, 372, 462, 374, 464, 372, 464, + 370, 462, 1212, 466, 1206, 462, 1206, 464, 1210, 466, 1206, 462, 1208, + 464, 1250, 422, 1208, 468, 372, 464, 1204, 466, 1206, 466, 370, 462, + 374, 462, 376, 460, 374, 466, 370, 462, 376, 464, 368, 462, 376, 462, + 1210, 462, 1208, 464, 1206, 466, 1206, 464, 1208, 468, 1212, 460, 1206, + 464, 372, 464, 372, 466, 370, 462, 374, 466, 370, 466, 370, 466, 374, + 464, 368, 462, 1210, 462, 1210, 464, 1210, 462, 1208, 462, 1212, 464, + 1206, 466, 1208, 466, 366, 464, 374, 460, 374, 462, 1208, 466, 372, + 462, 374, 462, 374, 464, 1212, 468, 1202, 464, 1208, 466, 1204, 464, + 376, 460, 1208, 468, 1208, 462, 1208, 464, 378, 460, 372, 460, 372, + 462, 376, 464, 372, 462, 374, 460, 374, 464, 370, 462, 378, 464, 1202, + 468, 1204, 468, 1204, 466, 1208, 466, 1208, 464, 1210, 460, 1212, 462, + 1212, 464, 366, 466, 370, 464, 372, 466, 370, 464, 372, 462, 414, 424, + 372, 466, 372, 460, 1206, 466, 1206, 466, 1206, 466, 1208, 466, 1206, + 464, 1208, 466, 1208, 462, 1212, 468, 1202, 466, 1204, 470, 1204, 468, + 1204, 466, 1206, 466, 1206, 464, 1210, 462, 1212, 468, 366, 464, 372, + 462, 374, 460, 374, 460, 374, 466, 410, 424, 372, 460, 378, 466, 1200, + 464, 1212, 462, 1210, 464, 1210, 466, 1206, 462, 1208, 464, 1210, 464, + 1210, 464, 366, 462, 376, 462, 374, 460, 376, 462, 372, 466, 374, 460, + 372, 462, 378, 462, 1202, 468, 1206, 464, 1208, 466, 1208, 462, 1208, + 464, 1208, 468, 1204, 464, 1212, 466, 368, 462, 374, 466, 372, 464, + 370, 462, 374, 464, 370, 462, 376, 464, 374, 462, 1206, 464, 1208, 462, + 1210, 466, 1208, 460, 1210, 468, 1206, 462, 1210, 464, 1212, 466, 366, + 464, 374, 462, 372, 466, 370, 462, 374, 464, 372, 464, 370, 464, 374, + 462};""" + analyse.parse_and_report(input_str, 200, True, "Hitachi", output) + self.assertEqual( + output.getvalue(), 'Found 853 timing entries.\n' + 'Potential Mark Candidates:\n' + '[29784, 3416, 470]\n' + 'Potential Space Candidates:\n' + '[49290, 1604, 1250, 416]\n' + 'DANGER: Unusual number of mark timings!\n' + 'Guessing encoding type:\n' + 'Looks like it uses space encoding. Yay!\n' + '\n' + 'Guessing key value:\n' + 'kHitachiHdrMark = 3416\n' + 'kHitachiHdrSpace = 1604\n' + 'kHitachiBitMark = 463\n' + 'kHitachiOneSpace = 1208\n' + 'kHitachiZeroSpace = 372\n' + 'kHitachiLdrMark = 29784\n' + 'kHitachiSpaceGap = 49290\n' + '\n' + 'Decoding protocol based on analysis so far:\n' + '\n' + 'kHitachiLdrMark+UNEXPECTED->GAP(49290)kHitachiHdrMark+' + 'kHitachiHdrSpace+100000000000100000000000000000101111110111111111' + '0000000000110011110011000100100110110110110010000011011100111010110001' + '010000000011111111000000001111111100000000111111110000000011111111' + '0000000011111111110010100011010110001111011100000000000011111111' + '0000000011111111000000011111111011000000001111111000000001111111' + '0001000111101110000000001111111100000000111111111111111100000000' + '111111110000000011111111000000001111111100000000\n' + ' Bits: 424\n' + ' Hex: 0x80080002FDFF0033CC49B6C8373AC500FF00FF00FF00FF00FFCA358F7000' + 'FF00FF01FEC03F807F11EE00FF00FFFF00FF00FF00FF00 (MSB first)\n' + ' 0x00FF00FF00FF00FFFF00FF007788FE01FC037F80FF00FF000EF1AC53FF00' + 'FF00FF00FF00FF00A35CEC136D9233CC00FFBF40001001 (LSB first)\n' + ' Dec: 21666770463250971033249250747302630158357464218891161163035832' + '525825434564377831675503794869126268735511944198247894513495375616' + ' (MSB first)\n' + ' 16857184424372658669179408622645041920057617761062334415219526' + '0950249734545225589859643087812860908833344117446370839379316737' + ' (LSB first)\n' + ' Bin: 0b100000000000100000000000000000101111110111111111000000000011' + '00111100110001001001101101101100100000110111001110101100010100000000' + '1111111100000000111111110000000011111111000000001111111100000000' + '1111111111001010001101011000111101110000000000001111111100000000' + '1111111100000001111111101100000000111111100000000111111100010001' + '1110111000000000111111110000000011111111111111110000000011111111' + '0000000011111111000000001111111100000000 (MSB first)\n' + ' 0b000000001111111100000000111111110000000011111111000000001111' + '11111111111100000000111111110000000001110111100010001111111000000001' + '1111110000000011011111111000000011111111000000001111111100000000' + '0000111011110001101011000101001111111111000000001111111100000000' + '1111111100000000111111110000000011111111000000001010001101011100' + '1110110000010011011011011001001000110011110011000000000011111111' + '1011111101000000000000000001000000000001 (LSB first)\n' + '\n' + 'Total Nr. of suspected bits: 424\n' + '\n' + 'Generating a VERY rough code outline:\n' + '\n' + '// Copyright 2019 David Conran (crankyoldgit)\n' + '// Support for Hitachi protocol\n' + '\n' + '#include "IRrecv.h"\n' + '#include "IRsend.h"\n' + '#include "IRutils.h"\n' + '\n' + "// WARNING: This probably isn't directly usable. It's a guide only.\n" + '\n' + '// 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' + 'const uint16_t kHitachiHdrMark = 3416;\n' + 'const uint16_t kHitachiBitMark = 463;\n' + 'const uint16_t kHitachiHdrSpace = 1604;\n' + 'const uint16_t kHitachiOneSpace = 1208;\n' + 'const uint16_t kHitachiZeroSpace = 372;\n' + 'const uint16_t kHitachiLdrMark = 29784;\n' + 'const uint16_t kHitachiSpaceGap = 49290;\n' + 'const uint16_t kHitachiFreq = 38000; // Hz. (Guessing the most' + ' common frequency.)\n' + 'const uint16_t kHitachiBits = 424; // Move to IRremoteESP8266.h\n' + 'const uint16_t kHitachiStateLength = 53; // Move to IRremoteESP8266.h' + '\n' + 'const uint16_t kHitachiOverhead = 5;\n' + "// DANGER: More than 64 bits detected. A uint64_t for 'data' won't" + ' work!\n' + '#if SEND_HITACHI\n' + '// Function should be safe up to 64 bits.\n' + 'void IRsend::sendHitachi(const uint64_t data, const uint16_t nbits,' + ' const uint16_t repeat) {\n' + ' enableIROut(kHitachiFreq);\n' + ' for (uint16_t r = 0; r <= repeat; r++) {\n' + ' uint64_t send_data = data;\n' + ' // Leader\n' + ' mark(kHitachiLdrMark);\n' + ' // Gap\n' + ' space(kHitachiSpaceGap);\n' + ' // Header\n' + ' mark(kHitachiHdrMark);\n' + ' space(kHitachiHdrSpace);\n' + ' // Data Section #1\n' + ' // e.g. data = 0x80080002FDFF0033CC49B6C8373AC500FF00FF00FF00FF00' + 'FFCA358F7000FF00FF01FEC03F807F11EE00FF00FFFF00FF00FF00FF00,' + ' nbits = 424\n' + ' sendData(kHitachiBitMark, kHitachiOneSpace, kHitachiBitMark,' + ' kHitachiZeroSpace, send_data, 424, true);\n' + ' send_data >>= 424;\n' + ' // Footer\n' + ' mark(kHitachiBitMark);\n' + ' space(kDefaultMessageGap); // A 100% made up guess of the gap' + ' between messages.\n' + ' }\n' + '}\n' + '#endif // SEND_HITACHI\n' + '\n' + '#if SEND_HITACHI\n' + '// Alternative >64bit function to send HITACHI messages\n' + '// Where data is:\n' + '// uint8_t data[kHitachiStateLength] = {0x80, 0x08, 0x00, 0x02,' + ' 0xFD, 0xFF, 0x00, 0x33, 0xCC, 0x49, 0xB6, 0xC8, 0x37, 0x3A, 0xC5,' + ' 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xCA,' + ' 0x35, 0x8F, 0x70, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0xC0, 0x3F,' + ' 0x80, 0x7F, 0x11, 0xEE, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF,' + ' 0x00, 0xFF, 0x00, 0xFF, 0x00};\n' + '//\n' + '// Args:\n' + '// data: An array of bytes containing the IR command.\n' + '// It is assumed to be in MSB order for this code.\n' + '// nbytes: Nr. of bytes of data in the array.' + ' (>=kHitachiStateLength)\n' + '// repeat: Nr. of times the message is to be repeated.\n' + '//\n' + '// Status: ALPHA / Untested.\n' + 'void IRsend::sendHitachi(const uint8_t data[], const uint16_t nbytes,' + ' const uint16_t repeat) {\n' + ' for (uint16_t r = 0; r <= repeat; r++) {\n' + ' uint16_t pos = 0;\n' + ' // Data Section #1\n' + ' // e.g.\n' + ' // bits = 424; bytes = 53;\n' + ' // *(data + pos) = {0x80, 0x08, 0x00, 0x02, 0xFD, 0xFF, 0x00,' + ' 0x33, 0xCC, 0x49, 0xB6, 0xC8, 0x37, 0x3A, 0xC5, 0x00, 0xFF, 0x00,' + ' 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xCA, 0x35, 0x8F, 0x70,' + ' 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0xC0, 0x3F, 0x80, 0x7F, 0x11,' + ' 0xEE, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,' + ' 0xFF, 0x00};\n' + ' sendGeneric(kHitachiHdrMark, kHitachiHdrSpace,\n' + ' kHitachiBitMark, kHitachiOneSpace,\n' + ' kHitachiBitMark, kHitachiZeroSpace,\n' + ' kHitachiBitMark, kHitachiSpaceGap,\n' + ' data + pos, 53, // Bytes\n' + ' kHitachiFreq, true, kNoRepeat, kDutyDefault);\n' + ' pos += 53; // Adjust by how many bytes of data we sent\n' + ' }\n' + '}\n' + '#endif // SEND_HITACHI\n' + '\n' + "// DANGER: More than 64 bits detected. A uint64_t for 'data' won't" + ' work!\n' + '#if DECODE_HITACHI\n' + '// Function should be safe up to 64 bits.\n' + 'bool IRrecv::decodeHitachi(decode_results *results,' + ' const uint16_t nbits, const bool strict) {\n' + ' if (results->rawlen < 2 * nbits + kHitachiOverhead)\n' + ' return false; // Too short a message to match.\n' + ' if (strict && nbits != kHitachiBits)\n' + ' return false;\n' + '\n' + ' uint16_t offset = kStartOffset;\n' + ' uint64_t data = 0;\n' + ' match_result_t data_result;\n' + '\n' + ' // Leader\n' + ' if (!matchMark(results->rawbuf[offset++], kHitachiLdrMark))\n' + ' return false;\n' + '\n' + ' // Gap\n' + ' if (!matchSpace(results->rawbuf[offset++], kHitachiSpaceGap))\n' + ' return false;\n' + '\n' + ' // Header\n' + ' if (!matchMark(results->rawbuf[offset++], kHitachiHdrMark))\n' + ' return false;\n' + ' if (!matchSpace(results->rawbuf[offset++], kHitachiHdrSpace))\n' + ' return false;\n' + '\n' + ' // Data Section #1\n' + ' // e.g. data_result.data = 0x80080002FDFF0033CC49B6C8373AC500FF00FF' + '00FF00FF00FFCA358F7000FF00FF01FEC03F807F11EE00FF00FFFF00FF00FF00FF00,' + ' nbits = 424\n' + ' data_result = matchData(&(results->rawbuf[offset]), 424,\n' + ' kHitachiBitMark, kHitachiOneSpace,\n' + ' kHitachiBitMark, kHitachiZeroSpace);\n' + ' offset += data_result.used;\n' + ' if (data_result.success == false) return false; // Fail\n' + ' data <<= 424; // Make room for the new bits of data.\n' + ' data |= data_result.data;\n' + '\n' + ' // Footer\n' + ' if (!matchMark(results->rawbuf[offset++], kHitachiBitMark))\n' + ' return false;\n' + '\n' + ' // Success\n' + ' results->decode_type = decode_type_t::HITACHI;\n' + ' results->bits = nbits;\n' + ' results->value = data;\n' + ' results->command = 0;\n' + ' results->address = 0;\n' + ' return true;\n' + '}\n' + '#endif // DECODE_HITACHI\n' + '\n' + '// Note: This should be 64+ bit safe.\n' + '#if DECODE_HITACHI\n' + '// Function should be safe over 64 bits.\n' + 'bool IRrecv::decodeHitachi(decode_results *results,' + ' const uint16_t nbits, const bool strict) {\n' + ' if (results->rawlen < 2 * nbits + kHitachiOverhead)\n' + ' return false; // Too short a message to match.\n' + ' if (strict && nbits != kHitachiBits)\n' + ' return false;\n' + '\n' + ' uint16_t offset = kStartOffset;\n' + ' uint16_t pos = 0;\n' + ' uint16_t used = 0;\n' + '\n' + ' // Data Section #1\n' + ' // e.g.\n' + ' // bits = 424; bytes = 53;\n' + ' // *(results->state + pos) = {0x80, 0x08, 0x00, 0x02, 0xFD, 0xFF,' + ' 0x00, 0x33, 0xCC, 0x49, 0xB6, 0xC8, 0x37, 0x3A, 0xC5, 0x00, 0xFF,' + ' 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xCA, 0x35, 0x8F,' + ' 0x70, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFE, 0xC0, 0x3F, 0x80, 0x7F,' + ' 0x11, 0xEE, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF,' + ' 0x00, 0xFF, 0x00};\n' + ' used = matchGeneric(results->rawbuf + offset,' + ' results->state + pos,\n' + ' results->rawlen - offset, 424,\n' + ' kHitachiHdrMark, kHitachiHdrSpace,\n' + ' kHitachiBitMark, kHitachiOneSpace,\n' + ' kHitachiBitMark, kHitachiZeroSpace,\n' + ' kHitachiBitMark, kHitachiSpaceGap, true);\n' + ' if (used == 0) return false; // We failed to find any data.\n' + ' offset += used; // Adjust for how much of the message we read.\n' + ' pos += 53; // Adjust by how many bytes of data we read\n' + '\n' + ' // Success\n' + ' results->decode_type = decode_type_t::HITACHI;\n' + ' results->bits = nbits;\n' + ' return true;\n' + '}\n' + '#endif // DECODE_HITACHI\n') + + def test_unusual_gaps(self): + """Tests for unusual Space Gaps in parse_and_report() function.""" + + # Tests for unusual Gaps. (Issue #482) + output = StringIO() + input_str = """ + uint16_t rawbuf[272] = {3485, 3512, 864, 864, 864, 2620, 864, 864, + 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, + 864, 2620, 864, 864, 864, 2620, 864, 2620, 864, 2620, 864, 2620, + 864, 2620, 864, 864, 864, 2620, 864, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 864, 864, 864, 864, 2620, 864, 864, + 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, + 3485, 3512, 864, 864, 864, 2620, 864, 864, 864, 2620, 864, 2620, + 864, 2620, 864, 2620, 864, 2620, 864, 864, 864, 2620, 864, 864, + 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, + 864, 2620, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 2620, 864, 864, 864, 864, 864, 864, 864, 864, + 864, 864, 864, 864, + 3485, 3512, 864, 13996, + 3485, 3512, 864, 864, 864, 864, 864, 2620, 864, 864, 864, 2620, + 864, 2620, 864, 2620, 864, 2620, 864, 864, 864, 864, 864, 2620, + 864, 864, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, + 864, 2620, 864, 2620, 864, 864, 864, 2620, 864, 2620, 864, 864, + 864, 864, 864, 864, 864, 2620, 864, 2620, 864, 864, 864, 2620, + 864, 2620, 864, 864, 864, 864, + 3485, 3512, 864, 864, 864, 864, 864, 2620, 864, 864, 864, 2620, + 864, 2620, 864, 2620, 864, 2620, 864, 864, 864, 864, 864, 2620, + 864, 864, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, + 864, 2620, 864, 2620, 864, 864, 864, 2620, 864, 2620, 864, 864, + 864, 864, 864, 864, 864, 2620, 864, 2620, 864, 864, 864, 2620, + 864, 2620, 864, 864, 864, 864, 3485, 3512, 864, 13996};""" + analyse.parse_and_report(input_str, 200, True, "FOO", output) + self.assertEqual( + output.getvalue(), 'Found 272 timing entries.\n' + 'Potential Mark Candidates:\n' + '[3485, 864]\n' + 'Potential Space Candidates:\n' + '[13996, 3512, 2620, 864]\n' + '\n' + 'Guessing encoding type:\n' + 'Looks like it uses space encoding. Yay!\n' + '\n' + 'Guessing key value:\n' + 'kFOOHdrMark = 3485\n' + 'kFOOHdrSpace = 3512\n' + 'kFOOBitMark = 864\n' + 'kFOOOneSpace = 2620\n' + 'kFOOZeroSpace = 864\n' + 'kFOOSpaceGap = 13996\n' + '\n' + 'Decoding protocol based on analysis so far:\n' + '\n' + 'kFOOHdrMark+kFOOHdrSpace+01011111010111110100000001000000\n' + ' Bits: 32\n' + ' Hex: 0x5F5F4040 (MSB first)\n' + ' 0x0202FAFA (LSB first)\n' + ' Dec: 1600077888 (MSB first)\n' + ' 33749754 (LSB first)\n' + ' Bin: 0b01011111010111110100000001000000 (MSB first)\n' + ' 0b00000010000000101111101011111010 (LSB first)\n' + 'kFOOHdrMark+kFOOHdrSpace+01011111010111110100000001000000\n' + ' Bits: 32\n' + ' Hex: 0x5F5F4040 (MSB first)\n' + ' 0x0202FAFA (LSB first)\n' + ' Dec: 1600077888 (MSB first)\n' + ' 33749754 (LSB first)\n' + ' Bin: 0b01011111010111110100000001000000 (MSB first)\n' + ' 0b00000010000000101111101011111010 (LSB first)\n' + 'kFOOHdrMark+kFOOHdrSpace+GAP(13996)kFOOHdrMark+kFOOHdrSpace+0010111100' + '1011110110110001101100\n' + ' Bits: 32\n' + ' Hex: 0x2F2F6C6C (MSB first)\n' + ' 0x3636F4F4 (LSB first)\n' + ' Dec: 791637100 (MSB first)\n' + ' 909571316 (LSB first)\n' + ' Bin: 0b00101111001011110110110001101100 (MSB first)\n' + ' 0b00110110001101101111010011110100 (LSB first)\n' + 'kFOOHdrMark+kFOOHdrSpace+00101111001011110110110001101100\n' + ' Bits: 32\n' + ' Hex: 0x2F2F6C6C (MSB first)\n' + ' 0x3636F4F4 (LSB first)\n' + ' Dec: 791637100 (MSB first)\n' + ' 909571316 (LSB first)\n' + ' Bin: 0b00101111001011110110110001101100 (MSB first)\n' + ' 0b00110110001101101111010011110100 (LSB first)\n' + 'kFOOHdrMark+kFOOHdrSpace+GAP(13996)\n' + 'Total Nr. of suspected bits: 128\n' + '\n' + 'Generating a VERY rough code outline:\n' + '\n' + '// Copyright 2019 David Conran (crankyoldgit)\n' + '// Support for FOO protocol\n' + '\n' + '#include "IRrecv.h"\n' + '#include "IRsend.h"\n' + '#include "IRutils.h"\n' + '\n' + "// WARNING: This probably isn't directly usable. It's a guide only.\n" + '\n' + '// 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' + 'const uint16_t kFOOHdrMark = 3485;\n' + 'const uint16_t kFOOBitMark = 864;\n' + 'const uint16_t kFOOHdrSpace = 3512;\n' + 'const uint16_t kFOOOneSpace = 2620;\n' + 'const uint16_t kFOOZeroSpace = 864;\n' + 'const uint16_t kFOOSpaceGap = 13996;\n' + 'const uint16_t kFOOFreq = 38000; // Hz. (Guessing the most common' + ' frequency.)\n' + 'const uint16_t kFOOBits = 128; // Move to IRremoteESP8266.h\n' + 'const uint16_t kFOOStateLength = 16; // Move to IRremoteESP8266.h\n' + 'const uint16_t kFOOOverhead = 16;\n' + "// DANGER: More than 64 bits detected. A uint64_t for 'data' won't" + ' work!\n' + '#if SEND_FOO\n' + '// Function should be safe up to 64 bits.\n' + 'void IRsend::sendFOO(const uint64_t data, const uint16_t nbits,' + ' const uint16_t repeat) {\n' + ' enableIROut(kFOOFreq);\n' + ' for (uint16_t r = 0; r <= repeat; r++) {\n' + ' uint64_t send_data = data;\n' + ' // Header\n' + ' mark(kFOOHdrMark);\n' + ' space(kFOOHdrSpace);\n' + ' // Data Section #1\n' + ' // e.g. data = 0x5F5F4040, nbits = 32\n' + ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' + ' send_data, 32, true);\n' + ' send_data >>= 32;\n' + ' // Header\n' + ' mark(kFOOHdrMark);\n' + ' space(kFOOHdrSpace);\n' + ' // Data Section #2\n' + ' // e.g. data = 0x5F5F4040, nbits = 32\n' + ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' + ' send_data, 32, true);\n' + ' send_data >>= 32;\n' + ' // Header\n' + ' mark(kFOOHdrMark);\n' + ' space(kFOOHdrSpace);\n' + ' // Gap\n' + ' mark(kFOOBitMark);\n' + ' space(kFOOSpaceGap);\n' + ' // Header\n' + ' mark(kFOOHdrMark);\n' + ' space(kFOOHdrSpace);\n' + ' // Data Section #3\n' + ' // e.g. data = 0x2F2F6C6C, nbits = 32\n' + ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' + ' send_data, 32, true);\n' + ' send_data >>= 32;\n' + ' // Header\n' + ' mark(kFOOHdrMark);\n' + ' space(kFOOHdrSpace);\n' + ' // Data Section #4\n' + ' // e.g. data = 0x2F2F6C6C, nbits = 32\n' + ' sendData(kFOOBitMark, kFOOOneSpace, kFOOBitMark, kFOOZeroSpace,' + ' send_data, 32, true);\n' + ' send_data >>= 32;\n' + ' // Header\n' + ' mark(kFOOHdrMark);\n' + ' space(kFOOHdrSpace);\n' + ' // Gap\n' + ' mark(kFOOBitMark);\n' + ' space(kFOOSpaceGap);\n' + ' space(kDefaultMessageGap); // A 100% made up guess of the gap' + ' between messages.\n' + ' }\n' + '}\n' + '#endif // SEND_FOO\n' + '\n' + '#if SEND_FOO\n' + '// Alternative >64bit function to send FOO messages\n' + '// Where data is:\n' + '// uint8_t data[kFOOStateLength] = {0x5F, 0x5F, 0x40, 0x40, 0x5F,' + ' 0x5F, 0x40, 0x40, 0x2F, 0x2F, 0x6C, 0x6C, 0x2F, 0x2F, 0x6C, 0x6C};\n' + '//\n' + '// Args:\n' + '// data: An array of bytes containing the IR command.\n' + '// It is assumed to be in MSB order for this code.\n' + '// nbytes: Nr. of bytes of data in the array. (>=kFOOStateLength)\n' + '// repeat: Nr. of times the message is to be repeated.\n' + '//\n' + '// Status: ALPHA / Untested.\n' + 'void IRsend::sendFOO(const uint8_t data[], const uint16_t nbytes,' + ' const uint16_t repeat) {\n' + ' for (uint16_t r = 0; r <= repeat; r++) {\n' + ' uint16_t pos = 0;\n' + ' // Data Section #1\n' + ' // e.g.\n' + ' // bits = 32; bytes = 4;\n' + ' // *(data + pos) = {0x5F, 0x5F, 0x40, 0x40};\n' + ' sendGeneric(kFOOHdrMark, kFOOHdrSpace,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kFOOHdrMark, kFOOHdrSpace,\n' + ' data + pos, 4, // Bytes\n' + ' kFOOFreq, true, kNoRepeat, kDutyDefault);\n' + ' pos += 4; // Adjust by how many bytes of data we sent\n' + ' // Data Section #2\n' + ' // e.g.\n' + ' // bits = 32; bytes = 4;\n' + ' // *(data + pos) = {0x5F, 0x5F, 0x40, 0x40};\n' + ' sendGeneric(kFOOHdrMark, kFOOHdrSpace,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kFOOHdrMark, kFOOHdrSpace,\n' + ' data + pos, 4, // Bytes\n' + ' kFOOFreq, true, kNoRepeat, kDutyDefault);\n' + ' pos += 4; // Adjust by how many bytes of data we sent\n' + ' // Data Section #3\n' + ' // e.g.\n' + ' // bits = 32; bytes = 4;\n' + ' // *(data + pos) = {0x2F, 0x2F, 0x6C, 0x6C};\n' + ' sendGeneric(kFOOHdrMark, kFOOHdrSpace,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kFOOHdrMark, kFOOHdrSpace,\n' + ' data + pos, 4, // Bytes\n' + ' kFOOFreq, true, kNoRepeat, kDutyDefault);\n' + ' pos += 4; // Adjust by how many bytes of data we sent\n' + ' // Data Section #4\n' + ' // e.g.\n' + ' // bits = 32; bytes = 4;\n' + ' // *(data + pos) = {0x2F, 0x2F, 0x6C, 0x6C};\n' + ' sendGeneric(kFOOHdrMark, kFOOHdrSpace,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kFOOHdrMark, kFOOHdrSpace,\n' + ' data + pos, 4, // Bytes\n' + ' kFOOFreq, true, kNoRepeat, kDutyDefault);\n' + ' pos += 4; // Adjust by how many bytes of data we sent\n' + ' }\n' + '}\n' + '#endif // SEND_FOO\n' + '\n' + "// DANGER: More than 64 bits detected. A uint64_t for 'data' won't " + 'work!\n' + '#if DECODE_FOO\n' + '// Function should be safe up to 64 bits.\n' + 'bool IRrecv::decodeFOO(decode_results *results, const uint16_t nbits,' + ' const bool strict) {\n' + ' if (results->rawlen < 2 * nbits + kFOOOverhead)\n' + ' return false; // Too short a message to match.\n' + ' if (strict && nbits != kFOOBits)\n' + ' return false;\n' + '\n' + ' uint16_t offset = kStartOffset;\n' + ' uint64_t data = 0;\n' + ' match_result_t data_result;\n' + '\n' + ' // Header\n' + ' if (!matchMark(results->rawbuf[offset++], kFOOHdrMark))\n' + ' return false;\n' + ' if (!matchSpace(results->rawbuf[offset++], kFOOHdrSpace))\n' + ' return false;\n' + '\n' + ' // Data Section #1\n' + ' // e.g. data_result.data = 0x5F5F4040, nbits = 32\n' + ' data_result = matchData(&(results->rawbuf[offset]), 32,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace);\n' + ' offset += data_result.used;\n' + ' if (data_result.success == false) return false; // Fail\n' + ' data <<= 32; // Make room for the new bits of data.\n' + ' data |= data_result.data;\n' + '\n' + ' // Header\n' + ' if (!matchMark(results->rawbuf[offset++], kFOOHdrMark))\n' + ' return false;\n' + ' if (!matchSpace(results->rawbuf[offset++], kFOOHdrSpace))\n' + ' return false;\n' + '\n' + ' // Data Section #2\n' + ' // e.g. data_result.data = 0x5F5F4040, nbits = 32\n' + ' data_result = matchData(&(results->rawbuf[offset]), 32,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace);\n' + ' offset += data_result.used;\n' + ' if (data_result.success == false) return false; // Fail\n' + ' data <<= 32; // Make room for the new bits of data.\n' + ' data |= data_result.data;\n' + '\n' + ' // Header\n' + ' if (!matchMark(results->rawbuf[offset++], kFOOHdrMark))\n' + ' return false;\n' + ' if (!matchSpace(results->rawbuf[offset++], kFOOHdrSpace))\n' + ' return false;\n' + '\n' + ' // Gap\n' + ' if (!matchMark(results->rawbuf[offset++], kFOOBitMark))\n' + ' return false;\n' + ' if (!matchSpace(results->rawbuf[offset++], kFOOSpaceGap))\n' + ' return false;\n' + '\n' + ' // Header\n' + ' if (!matchMark(results->rawbuf[offset++], kFOOHdrMark))\n' + ' return false;\n' + ' if (!matchSpace(results->rawbuf[offset++], kFOOHdrSpace))\n' + ' return false;\n' + '\n' + ' // Data Section #3\n' + ' // e.g. data_result.data = 0x2F2F6C6C, nbits = 32\n' + ' data_result = matchData(&(results->rawbuf[offset]), 32,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace);\n' + ' offset += data_result.used;\n' + ' if (data_result.success == false) return false; // Fail\n' + ' data <<= 32; // Make room for the new bits of data.\n' + ' data |= data_result.data;\n' + '\n' + ' // Header\n' + ' if (!matchMark(results->rawbuf[offset++], kFOOHdrMark))\n' + ' return false;\n' + ' if (!matchSpace(results->rawbuf[offset++], kFOOHdrSpace))\n' + ' return false;\n' + '\n' + ' // Data Section #4\n' + ' // e.g. data_result.data = 0x2F2F6C6C, nbits = 32\n' + ' data_result = matchData(&(results->rawbuf[offset]), 32,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace);\n' + ' offset += data_result.used;\n' + ' if (data_result.success == false) return false; // Fail\n' + ' data <<= 32; // Make room for the new bits of data.\n' + ' data |= data_result.data;\n' + '\n' + ' // Header\n' + ' if (!matchMark(results->rawbuf[offset++], kFOOHdrMark))\n' + ' return false;\n' + ' if (!matchSpace(results->rawbuf[offset++], kFOOHdrSpace))\n' + ' return false;\n' + '\n' + ' // Gap\n' + ' if (!matchMark(results->rawbuf[offset++], kFOOBitMark))\n' + ' return false;\n' + ' if (!matchSpace(results->rawbuf[offset++], kFOOSpaceGap))\n' + ' return false;\n' + '\n' + ' // Success\n' + ' results->decode_type = decode_type_t::FOO;\n' + ' results->bits = nbits;\n' + ' results->value = data;\n' + ' results->command = 0;\n' + ' results->address = 0;\n' + ' return true;\n' + '}\n' + '#endif // DECODE_FOO\n' + '\n' + '// Note: This should be 64+ bit safe.\n' + '#if DECODE_FOO\n' + '// Function should be safe over 64 bits.\n' + 'bool IRrecv::decodeFOO(decode_results *results, const uint16_t nbits,' + ' const bool strict) {\n' + ' if (results->rawlen < 2 * nbits + kFOOOverhead)\n' + ' return false; // Too short a message to match.\n' + ' if (strict && nbits != kFOOBits)\n' + ' return false;\n' + '\n' + ' uint16_t offset = kStartOffset;\n' + ' uint16_t pos = 0;\n' + ' uint16_t used = 0;\n' + '\n' + ' // Data Section #1\n' + ' // e.g.\n' + ' // bits = 32; bytes = 4;\n' + ' // *(results->state + pos) = {0x5F, 0x5F, 0x40, 0x40};\n' + ' used = matchGeneric(results->rawbuf + offset, results->state + pos,' + '\n' + ' results->rawlen - offset, 32,\n' + ' kFOOHdrMark, kFOOHdrSpace,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kFOOHdrMark, kFOOHdrSpace, true);\n' + ' if (used == 0) return false; // We failed to find any data.\n' + ' offset += used; // Adjust for how much of the message we read.\n' + ' pos += 4; // Adjust by how many bytes of data we read\n' + '\n' + ' // Data Section #2\n' + ' // e.g.\n' + ' // bits = 32; bytes = 4;\n' + ' // *(results->state + pos) = {0x5F, 0x5F, 0x40, 0x40};\n' + ' used = matchGeneric(results->rawbuf + offset, results->state + pos,' + '\n' + ' results->rawlen - offset, 32,\n' + ' kFOOHdrMark, kFOOHdrSpace,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kFOOHdrMark, kFOOHdrSpace, true);\n' + ' if (used == 0) return false; // We failed to find any data.\n' + ' offset += used; // Adjust for how much of the message we read.\n' + ' pos += 4; // Adjust by how many bytes of data we read\n' + '\n' + ' // Data Section #3\n' + ' // e.g.\n' + ' // bits = 32; bytes = 4;\n' + ' // *(results->state + pos) = {0x2F, 0x2F, 0x6C, 0x6C};\n' + ' used = matchGeneric(results->rawbuf + offset, results->state + pos,' + '\n' + ' results->rawlen - offset, 32,\n' + ' kFOOHdrMark, kFOOHdrSpace,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kFOOHdrMark, kFOOHdrSpace, true);\n' + ' if (used == 0) return false; // We failed to find any data.\n' + ' offset += used; // Adjust for how much of the message we read.\n' + ' pos += 4; // Adjust by how many bytes of data we read\n' + '\n' + ' // Data Section #4\n' + ' // e.g.\n' + ' // bits = 32; bytes = 4;\n' + ' // *(results->state + pos) = {0x2F, 0x2F, 0x6C, 0x6C};\n' + ' used = matchGeneric(results->rawbuf + offset, results->state + pos,' + '\n' + ' results->rawlen - offset, 32,\n' + ' kFOOHdrMark, kFOOHdrSpace,\n' + ' kFOOBitMark, kFOOOneSpace,\n' + ' kFOOBitMark, kFOOZeroSpace,\n' + ' kFOOHdrMark, kFOOHdrSpace, true);\n' + ' if (used == 0) return false; // We failed to find any data.\n' + ' offset += used; // Adjust for how much of the message we read.\n' + ' pos += 4; // Adjust by how many bytes of data we read\n' + '\n' + ' // Success\n' + ' results->decode_type = decode_type_t::FOO;\n' + ' results->bits = nbits;\n' + ' return true;\n' + '}\n' + '#endif // DECODE_FOO\n') + + +if __name__ == '__main__': + unittest.main(verbosity=2) diff --git a/lib/IRremoteESP8266-2.6.5/tools/gc_decode.cpp b/lib/IRremoteESP8266-2.7.0/tools/gc_decode.cpp old mode 100755 new mode 100644 similarity index 65% rename from lib/IRremoteESP8266-2.6.5/tools/gc_decode.cpp rename to lib/IRremoteESP8266-2.7.0/tools/gc_decode.cpp index 52ffd17b7..a1d828d1c --- a/lib/IRremoteESP8266-2.6.5/tools/gc_decode.cpp +++ b/lib/IRremoteESP8266-2.7.0/tools/gc_decode.cpp @@ -1,4 +1,4 @@ -// Quick and dirty tool to decode GlobalCache (GC) codes +// Quick and dirty tool to decode Raw Codes, GlobalCache (GC) codes // and ProntoHex codes // Copyright 2017 Jorge Cisneros @@ -7,6 +7,7 @@ #include #include #include +#include "IRac.h" #include "IRsend.h" #include "IRsend_test.h" #include "IRutils.h" @@ -24,30 +25,38 @@ void str_to_uint16(char *str, uint16_t *res, uint8_t base) { } void usage_error(char *name) { - std::cerr << "Usage: " << name << " [-raw] " << std::endl - << "Usage: " << name << " -prontohex [-raw] " - << std::endl; + std::cerr << "Usage: " << name << " [-gc] [-rawdump] " + << std::endl + << "Usage: " << name << " -prontohex [-rawdump] " + << std::endl + << "Usage: " << name << " -raw [-rawdump] " << std::endl; } int main(int argc, char *argv[]) { int argv_offset = 1; bool dumpraw = false; - bool prontohex = false; - + enum decode_type_t input_type = GLOBALCACHE; + const uint16_t raw_freq = 38; // Check the invocation/calling usage. if (argc < 2 || argc > 4) { usage_error(argv[0]); return 1; } - if (strncmp("-prontohex", argv[argv_offset], 10) == 0) { - prontohex = true; + if (strncmp("-gc", argv[argv_offset], 3) == 0) { + argv_offset++; + } else if (strncmp("-prontohex", argv[argv_offset], 10) == 0) { + input_type = PRONTO; + argv_offset++; + } else if (strncmp("-raw", argv[argv_offset], 4) == 0) { + input_type = RAW; argv_offset++; } - if (strncmp("-raw", argv[argv_offset], 4) == 0) { + if (strncmp("-rawdump", argv[argv_offset], 7) == 0) { dumpraw = true; argv_offset++; } + if (argc - argv_offset != 1) { usage_error(argv[0]); return 1; @@ -59,8 +68,7 @@ int main(int argc, char *argv[]) { char *saveptr1; char *sep = const_cast(","); int codebase = 10; - - if (prontohex) { + if (input_type == PRONTO) { sep = const_cast(" "); codebase = 16; } @@ -77,10 +85,18 @@ int main(int argc, char *argv[]) { irsend.begin(); irsend.reset(); - if (prontohex) { - irsend.sendPronto(gc_test, index); - } else { - irsend.sendGC(gc_test, index); + switch (input_type) { + case GLOBALCACHE: + irsend.sendGC(gc_test, index); + break; + case PRONTO: + irsend.sendPronto(gc_test, index); + break; + case RAW: + irsend.sendRaw(gc_test, index, raw_freq); + break; + default: + break; } irsend.makeDecodeResult(); irrecv.decode(&irsend.capture); @@ -94,6 +110,10 @@ int main(int argc, char *argv[]) { for (uint16_t i = 0; i < irsend.capture.bits / 8; i++) printf("%02X", irsend.capture.state[i]); std::cout << std::endl; + String description = IRAcUtils::resultAcToString(&irsend.capture); + if (description.length()) { + std::cout << "Msg Description: " << description.c_str() << std::endl; + } } else { std::cout << "Code value 0x" << std::hex << irsend.capture.value << std::endl diff --git a/lib/IRremoteESP8266-2.7.0/tools/generate_irtext_h.sh b/lib/IRremoteESP8266-2.7.0/tools/generate_irtext_h.sh new file mode 100755 index 000000000..5b6e2e544 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.0/tools/generate_irtext_h.sh @@ -0,0 +1,36 @@ +#!/bin/bash +export INPUT="IRtext.cpp" +export OUTPUT="IRtext.h" + +if [[ ! -f ${INPUT} ]]; then + echo "Can't read file '${INPUT}'. Aborting!" + exit 1 +fi + +# Header +cat >${OUTPUT} << EOF +// Copyright 2019 - David Conran (@crankyoldgit) +// This header file is to be included in files **other than** 'IRtext.cpp'. +// +// WARNING: Do not edit this file! This file is automatically generated by +// 'tools/generate_irtext_h.sh'. + +#ifndef IRTEXT_H_ +#define IRTEXT_H_ + +#include "i18n.h" + +// Constant text to be shared across all object files. +// This means there is only one copy of the character/string/text etc. + +EOF + +# Parse and output contents of INPUT file. +egrep "^(String|char) " ${INPUT} | cut -f1 -d= | + sed 's/ PROGMEM//;s/ $/;/;s/^/extern const /' | sort -u >> ${OUTPUT} + +# Footer +cat >> ${OUTPUT} << EOF + +#endif // IRTEXT_H_ +EOF diff --git a/lib/IRremoteESP8266-2.6.5/tools/mkkeywords b/lib/IRremoteESP8266-2.7.0/tools/mkkeywords similarity index 100% rename from lib/IRremoteESP8266-2.6.5/tools/mkkeywords rename to lib/IRremoteESP8266-2.7.0/tools/mkkeywords diff --git a/lib/IRremoteESP8266-2.6.5/tools/mode2_decode.cpp b/lib/IRremoteESP8266-2.7.0/tools/mode2_decode.cpp old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.6.5/tools/mode2_decode.cpp rename to lib/IRremoteESP8266-2.7.0/tools/mode2_decode.cpp diff --git a/lib/IRremoteESP8266-2.6.5/tools/scrape_supported_devices.py b/lib/IRremoteESP8266-2.7.0/tools/scrape_supported_devices.py similarity index 100% rename from lib/IRremoteESP8266-2.6.5/tools/scrape_supported_devices.py rename to lib/IRremoteESP8266-2.7.0/tools/scrape_supported_devices.py diff --git a/tasmota/_changelog.ino b/tasmota/_changelog.ino index f609f4c89..39d230088 100644 --- a/tasmota/_changelog.ino +++ b/tasmota/_changelog.ino @@ -11,6 +11,7 @@ * Fix better control of RGB/White when SetOption37 >128, added Dimmer1 and Dimmer2 commands (#6714) * Add hide Alexa objects with friendlyname starting with '$' (#6722, #6762) * Add command SetOption75 0/1 to switch between grouptopic (0) using fulltopic replacing %topic% or (1) is cmnd/ (#6779) + * Change Update IRremoteESP8266 to v2.7.0 * * 6.7.1.1 20191026 * Change ArduinoSlave to TasmotaSlave (Experimental)