Merge pull request #6813 from s-hadinger/ir_270

Update IRremoteESP8266 to v2.7.0
This commit is contained in:
Theo Arends 2019-11-02 14:17:07 +01:00 committed by GitHub
commit 575107a3d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
271 changed files with 15901 additions and 8190 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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._

View File

@ -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

View File

@ -1,4 +0,0 @@
[submodule "lib/googletest"]
path = lib/googletest
url = https://github.com/google/googletest.git
branch = v1.8.x

View File

@ -1,3 +0,0 @@
[style]
based_on_style: google
indent_width: 2

View File

@ -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)

View File

@ -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 <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRac.h>
#include <IRutils.h>
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 ...");
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <algorithm>
#ifndef ARDUINO
#include <string>
#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)

View File

@ -1,811 +0,0 @@
// Copyright 2009 Ken Shirriff
// Copyright 2017-2018 David Conran
// Copyright 2018 Denes Varga
// Mitsubishi
#include "ir_Mitsubishi.h"
#include <algorithm>
#ifndef ARDUINO
#include <string>
#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:
// * <Add models (A/C & remotes) you've gotten it working with here>
// 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;
}

View File

@ -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 <stdint.h>
#ifndef UNIT_TEST
#include <Arduino.h>
#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_

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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.

View File

@ -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]**

View File

@ -1,6 +1,6 @@
<!--- WARNING: Do NOT edit this file directly.
It is generated by './tools/scrape_supported_devices.py'.
Last generated: Wed Aug 28 12:37:20 2019 --->
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<BR>53NGK009/012 Inverter<BR>619EGX0090E0 A/C<BR>619EGX0120E0 A/C<BR>619EGX0180E0 A/C<BR>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<BR>BINR 070/071 split-type A/C<BR>RG57K7(B)/BGEF Remote<BR>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<BR>MS12FU-10HRDN1-QRD0GW(B) A/C<BR>MSABAU-07HRFN1-QRD0GW A/C (circa 2016)<BR>MSABAU-07HRFN1-QRD0GW A/C (circa 2016)<BR>RG52D/BGE Remote<BR>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<BR>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)<BR>ARC423A5 remote<BR>ARC433** remote<BR>ARC433B69 remote<BR>ARC477A1 remote<BR>ARC480A5 remote (DAIKIN152)<BR>BRC4C153 remote<BR>BRC52B63 remote (DAIKIN128)<BR>FTE12HV2S A/C<BR>FTXB09AXVJU A/C (DAIKIN128)<BR>FTXB12AXVJU A/C (DAIKIN128)<BR>FTXZ25NV1B A/C<BR>FTXZ35NV1B A/C<BR>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<BR>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<BR>AR-RAE1E remote<BR>AR-RAH2E remote<BR>AR-REB1E remote<BR>AST9RSGCW A/C<BR>ASYG30LFCA A/C<BR>ASYG7LMCA A/C | ARDB1<BR>ARJW2<BR>ARRAH2E<BR>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<BR>ARJW2<BR>ARRAH2E<BR>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<BR>AR-DB1 remote<BR>AR-DL10 remote<BR>AR-RAC1E remote<BR>AR-RAE1E remote<BR>AR-RAH2E remote<BR>AR-REB1E remote<BR>AR-RY4 remote<BR>AST9RSGCW A/C<BR>ASTB09LBC A/C<BR>ASU30C1 A/C<BR>ASYG30LFCA A/C<BR>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<BR>YBOFB | Yes |
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YBOFB remote<BR>YBOFB2 remote | YAW1F<BR>YBOFB | Yes |
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[RusClimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | EACS/I-09HAR_X/N3 A/C<BR>YAW1F remote | YAW1F<BR>YBOFB | Yes |
| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Ultimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | Heat Pump | YAW1F<BR>YBOFB | Yes |
| [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<BR>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<BR>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<BR>HSU07-HEA03 remote<BR>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<BR>RAS-35THA6 remote<BR>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<BR>RAR-8P2 remote<BR>RAS-35THA6 remote<BR>RAS-AJ25H A/C<BR>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)<BR>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<BR>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<BR>KM14A 0179213 remote<BR>MS-GK24VA A/C<BR>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<BR>KPOA remote<BR>MSH-A24WV / MUH-A24WV A/C<BR>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<BR>RLA502A700B remote<BR>SRKxxZJ-S A/C<BR>SRKxxZM-S A/C<BR>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<BR>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<BR>NS-09AHTI A/C<BR>ZH/TY-01 remote<BR>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)<BR>A75C3704 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>CKP series A/C<BR>CS-ME10CKPG A/C<BR>CS-ME12CKPG A/C<BR>CS-ME14CKPG A/C<BR>CS-YW9MKD A/C<BR>CS-Z9RKR A/C<BR>DKE series A/C<BR>JKE series A/C<BR>NKE series A/C<BR>RKR series A/C<BR>TV | CKP<BR>DKE<BR>JKE<BR>LKE<BR>NKE<BR>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)<BR>A75C3704 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>CKP series A/C<BR>CS-ME10CKPG A/C<BR>CS-ME12CKPG A/C<BR>CS-ME14CKPG A/C<BR>CS-YW9MKD A/C<BR>CS-Z9RKR A/C<BR>DKE series A/C<BR>JKE series A/C<BR>NKE series A/C<BR>RKR series A/C<BR>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<BR>RAS 18SKP-ES<BR>RAS-B13N3KV2<BR>RAS-B13N3KVP-E<BR>WC-L03SE<BR>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<BR>DG11J1-3A remote<BR>DG11J1-91 remote<BR>SPIS409L A/C<BR>SPIS412L A/C<BR>SPIW409L A/C<BR>SPIW412L A/C<BR>SPIW418L A/C | DG11J13A<BR>DG11J191 | Yes |
| [Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.cpp) | **[Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.h)** | DG11J1-04 remote<BR>DG11J1-3A remote<BR>DG11J1-91 remote<BR>SPIS409L A/C<BR>SPIS412L A/C<BR>SPIW409L A/C<BR>SPIW412L A/C<BR>SPIW418L A/C | | 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

View File

@ -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 <Arduino.h>
#include <IRremoteESP8266.h>
#include <IRac.h>
#include <IRutils.h>
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 ...");
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
")<br>";
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_

View File

@ -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}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <IRrecv.h>
#include <IRremoteESP8266.h>
#include <IRac.h>
#include <IRtext.h>
#include <IRutils.h>
// ==================== 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

View File

@ -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

View File

@ -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

View File

@ -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() {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 <FS.h>
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h>
#include <ESP8266WebServer.h>
#endif // ESP8266
#if defined(ESP32)
#include <ESPmDNS.h>
#include <WebServer.h>
#include <WiFi.h>
#include <SPIFFS.h>
#include <Update.h>
#endif // ESP32
#include <WiFiUdp.h>
#include <WiFiManager.h>
#include <ArduinoJson.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
//// ###### User configuration space for AC library classes ##########
#include <ir_Coolix.h> // 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 = "<form method=\"post\" enctype=\"multipart/form-data\">";
html += "<input type=\"file\" name=\"name\">";
html += "<input class=\"button\" type=\"submit\" value=\"Upload\">";
html += "</form>";
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();
}

View File

@ -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}

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="250"
height="500"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient4457">
<stop
id="stop4459"
style="stop-color:#0000ff;stop-opacity:1"
offset="0" />
</linearGradient>
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-552.36218)"
id="layer1">
<rect
width="236.64082"
height="86.640839"
rx="15.946075"
ry="15.666504"
x="6.6795802"
y="959.03809"
id="rect2995"
style="opacity:0.87999998;fill:#46b8da;fill-opacity:0;stroke:#000000;stroke-width:13.35916042;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:35.90000153;stroke-opacity:1;stroke-dasharray:none" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="250"
height="500"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient4457">
<stop
id="stop4459"
style="stop-color:#0000ff;stop-opacity:1"
offset="0" />
</linearGradient>
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-552.36218)"
id="layer1">
<rect
width="236.64082"
height="86.640839"
rx="15.946075"
ry="15.666504"
x="6.6795802"
y="959.03809"
id="rect2995"
style="opacity:0.87999998;fill:#46b8da;fill-opacity:1;stroke:#000000;stroke-width:13.35916042;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:35.90000153;stroke-opacity:1;stroke-dasharray:none" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="250"
height="500"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient4457">
<stop
id="stop4459"
style="stop-color:#0000ff;stop-opacity:1"
offset="0" />
</linearGradient>
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-552.36218)"
id="layer1">
<rect
width="230.92926"
height="180.92929"
rx="22.392242"
ry="22.274536"
x="9.5353565"
y="861.89758"
id="rect2995"
style="opacity:0.87999998;fill:#46b8da;fill-opacity:0;stroke:#000000;stroke-width:19.07071304;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:35.90000153;stroke-opacity:1;stroke-dasharray:none" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="250"
height="500"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient4457">
<stop
id="stop4459"
style="stop-color:#0000ff;stop-opacity:1"
offset="0" />
</linearGradient>
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-552.36218)"
id="layer1">
<rect
width="230.92926"
height="180.92929"
rx="22.392242"
ry="22.274536"
x="9.5353565"
y="861.89758"
id="rect2995"
style="opacity:0.87999998;fill:#46b8da;fill-opacity:1;stroke:#000000;stroke-width:19.07071304;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:35.90000153;stroke-opacity:1;stroke-dasharray:none" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="250"
height="500"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient4457">
<stop
id="stop4459"
style="stop-color:#0000ff;stop-opacity:1"
offset="0" />
</linearGradient>
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-552.36218)"
id="layer1">
<rect
width="226.6387"
height="276.63873"
rx="36.69751"
ry="40.173462"
x="11.680637"
y="764.04285"
id="rect2995"
style="opacity:0.87999998;fill:#46b8da;fill-opacity:0;stroke:#000000;stroke-width:23.36127472;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:35.90000153;stroke-opacity:1;stroke-dasharray:none" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="250"
height="500"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient4457">
<stop
id="stop4459"
style="stop-color:#0000ff;stop-opacity:1"
offset="0" />
</linearGradient>
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-552.36218)"
id="layer1">
<rect
width="226.6387"
height="276.63873"
rx="36.69751"
ry="40.173462"
x="11.680637"
y="764.04285"
id="rect2995"
style="opacity:0.87999998;fill:#46b8da;fill-opacity:1;stroke:#000000;stroke-width:23.36127472;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:35.90000153;stroke-opacity:1;stroke-dasharray:none" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="250"
height="500"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient4457">
<stop
id="stop4459"
style="stop-color:#0000ff;stop-opacity:1"
offset="0" />
</linearGradient>
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-552.36218)"
id="layer1">
<rect
width="223.08398"
height="373.08401"
rx="40.059196"
ry="46.087463"
x="13.458"
y="665.82019"
id="rect2995"
style="opacity:0.87999998;fill:#46b8da;fill-opacity:0;stroke:#000000;stroke-width:26.91600037;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:35.90000153;stroke-opacity:1;stroke-dasharray:none" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="250"
height="500"
id="svg2">
<defs
id="defs4">
<linearGradient
id="linearGradient4457">
<stop
id="stop4459"
style="stop-color:#0000ff;stop-opacity:1"
offset="0" />
</linearGradient>
</defs>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-552.36218)"
id="layer1">
<rect
width="223.08398"
height="373.08401"
rx="40.059196"
ry="46.087463"
x="13.458"
y="665.82019"
id="rect2995"
style="opacity:0.87999998;fill:#46b8da;fill-opacity:1;stroke:#000000;stroke-width:26.91600037;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:35.90000153;stroke-opacity:1;stroke-dasharray:none" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

Some files were not shown because too many files have changed in this diff Show More