Merge pull request #1 from arendst/development

update to dev
This commit is contained in:
tammo0 2019-05-31 17:04:47 +02:00 committed by GitHub
commit 4a3fe89e99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
308 changed files with 26012 additions and 6255 deletions

5
API.md
View File

@ -1,4 +1,7 @@
## Sonoff-Tasmota basic API information
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
# Basic API information
Sonoff-Tasmota can easily be extended by developers using provided function pointers as callback Ids. This document lists the available callback function Ids. See the wiki (https://github.com/arendst/Sonoff-Tasmota/wiki/Sensor-API) for more information.
Callback availability can be checked by searching for either XdrvCall, XsnsCall, XdspCall and XnrgCall.

View File

@ -1,4 +1,6 @@
# Contributing to Sonoff-Tasmota
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
# Contributing
**Any contribution helps our team and makes Tasmota better for the entire community!**
@ -26,7 +28,7 @@ This document describes rules that are in effect for this repository, meant for
1. Any contributor to the project can participate in the triaging process, if he/she chooses to do so.
2. An issue that needs to be closed, either due to not complying with this policy, or for other reasons, should be closed by a contributor.
3. Issues that are accepted should be marked with appropriate labels.
4. Issues that could impact functionality for many users should be considered severe.
4. Issues that could impact functionality for many users should be considered severe.
5. Issues caused by the SDK or chip should not be marked severe, as there usually isnt much to be done. Common sense should be applied when deciding. Such issues should be documented in the Wiki, for reference by users.
6. Issues with feature requests should be discussed for viability/desirability.
7. Feature requests or changes that are meant to address a very specific/limited use case, especially if at the expense of increased code complexity, may be denied, or may be required to be redesigned, generalized, or simplified.
@ -100,7 +102,7 @@ A CLA is a legal document in which you state _you are entitled to contribute the
CLA is a safety because it also ensures that once you have provided a contribution, you cannot try to withdraw permission for its use at a later date. People can therefore use that software, confident that they will not be asked to stop using pieces of the code at a later date.
A __license__ grants "outbound" rights to the user of project.
A __license__ grants "outbound" rights to the user of project.
A __CLA__ enables a contributor to grant "inbound" rights to a project.

View File

@ -1,6 +1,6 @@
## Sonoff-Tasmota
# Sonoff-Tasmota
Alternative firmware for _ESP8266 based devices_ like [iTead](https://www.itead.cc/) _**Sonoff**_ with **web UI, rules and timers, OTA updates, custom device templates and sensor support**. Allows control over **MQTT**, **HTTP**, **Serial** and **KNX** for integrations with smart home systems. Written for Arduino IDE and PlatformIO.
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="90"/>Alternative firmware for _ESP8266 based devices_ like [iTead](https://www.itead.cc/) _**Sonoff**_ with **web UI, rules and timers, OTA updates, custom device templates and sensor support**. Allows control over **MQTT**, **HTTP**, **Serial** and **KNX** for integrations with smart home systems. Written for Arduino IDE and PlatformIO.
[![GitHub version](https://img.shields.io/github/release/arendst/Sonoff-Tasmota.svg)](https://github.com/arendst/Sonoff-Tasmota/releases/latest)
[![GitHub download](https://img.shields.io/github/downloads/arendst/Sonoff-Tasmota/total.svg)](https://github.com/arendst/Sonoff-Tasmota/releases/latest)
@ -15,7 +15,7 @@ If you like **Sonoff-Tasmota**, give it a star, or fork it and contribute!
See [RELEASENOTES.md](https://github.com/arendst/Sonoff-Tasmota/blob/development/RELEASENOTES.md) for release information.
In addition to the [release webpage](https://github.com/arendst/Sonoff-Tasmota/releases/latest), the binaries can also be OTA downloaded from http://thehackbox.org/tasmota/release/
In addition to the [release webpage](https://github.com/arendst/Sonoff-Tasmota/releases/latest), the binaries can be downloaded from http://thehackbox.org/tasmota/release/
### Development
[![Dev Version](https://img.shields.io/badge/development%20version-6.5.0.x-blue.svg)](https://github.com/arendst/Sonoff-Tasmota)
@ -34,10 +34,10 @@ A Sonoff device is not a toy. It uses Mains AC so there is a danger of electrocu
We don't take any responsibility nor liability for using this software nor for the installation or any tips, advice, videos, etc. given by any member of this site or any related site.
### Note
Please do not ask to add devices where you can't provide a basic working configuration (other than sonoff). Since there are thousands of them.
Please do not ask to add new devices unless it requires additional code for new features. If the device is not listed as a module, try using [Templates](https://github.com/arendst/Sonoff-Tasmota/wiki/Templates) first. If it is not listed in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates) create your own [Template](https://github.com/arendst/Sonoff-Tasmota/wiki/Templates#creating-your-template-).
### Quick Install
Download one of the released binaries from https://github.com/arendst/Sonoff-Tasmota/releases and flash it to your hardware as documented in the wiki.
Download one of the released binaries from https://github.com/arendst/Sonoff-Tasmota/releases and flash it to your hardware as [documented in the wiki](https://github.com/arendst/Sonoff-Tasmota/wiki/Flashing).
### Important User Compilation Information
If you want to compile Sonoff-Tasmota yourself keep in mind the following:
@ -48,7 +48,7 @@ If you want to compile Sonoff-Tasmota yourself keep in mind the following:
### Version Information
- Sonoff-Tasmota provides all (Sonoff) modules in one file and starts with module Sonoff Basic.
- Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```.
- Once uploaded, select [Module](https://github.com/arendst/Sonoff-Tasmota/wiki/Modules) using the configuration webpage, the commands ```Modules``` and ```Module``` or configure the [Template](https://github.com/arendst/Sonoff-Tasmota/wiki/Templates) for your device
- After reboot select config menu again or use commands ```GPIOs``` and ```GPIO``` to change GPIO with desired sensor.
### Migration Information
@ -62,52 +62,12 @@ See [wiki migration path](https://github.com/arendst/Sonoff-Tasmota/wiki/Upgrade
### Support Information
<img src="https://github.com/arendst/arendst.github.io/blob/master/media/sonoffbasic.jpg" width="250" align="right" />
See [Wiki](https://github.com/arendst/Sonoff-Tasmota/wiki) for more information.<br />
For a database of supported devices see [Tasmota Device Templates Repository](https://blakadder.github.io/templates)
See [Wiki](https://github.com/arendst/Sonoff-Tasmota/wiki) for use instructions and how-to's.<br />
See [Community](https://groups.google.com/d/forum/sonoffusers) for forum.<br />
Visit [Discord Chat](https://discord.gg/Ks2Kzd4) for discussions and troubleshooting.
The following devices are supported:
- [iTead Sonoff Basic (R2)](https://www.itead.cc/smart-home/sonoff-wifi-wireless-switch-1.html)
- [iTead Sonoff RF](https://www.itead.cc/smart-home/sonoff-rf.html)
- [iTead Sonoff SV](https://www.itead.cc/smart-home/sonoff-sv.html)<img src="https://github.com/arendst/arendst.github.io/blob/master/media/sonoff_th.jpg" width="250" align="right" />
- [iTead Sonoff TH10/TH16 with temperature sensor](https://www.itead.cc/smart-home/sonoff-th.html)
- [iTead Sonoff Dual (R2)](https://www.itead.cc/smart-home/sonoff-dual.html)
- [iTead Sonoff Pow with Energy Monitoring](https://www.itead.cc/smart-home/sonoff-pow.html)
- [iTead Sonoff Pow R2 with Energy Monitoring](https://www.itead.cc/sonoff-pow-r2.html)
- [iTead Sonoff 4CH (R2)](https://www.itead.cc/smart-home/sonoff-4ch.html)
- [iTead Sonoff 4CH Pro (R2)](https://www.itead.cc/smart-home/sonoff-4ch-pro.html)
- [iTead Sonoff S20 Smart Socket](https://www.itead.cc/smart-socket.html)
- [Sonoff S22 Smart Socket](https://github.com/arendst/Sonoff-Tasmota/issues/627)
- [iTead Sonoff S26 Smart Socket](https://www.itead.cc/sonoff-s26-wifi-smart-plug.html)
- [iTead Sonoff S31 Smart Socket with Energy Monitoring](https://www.itead.cc/sonoff-s31.html)
- [iTead Slampher](https://www.itead.cc/slampher.html)
- [iTead Sonoff Touch](https://www.itead.cc/sonoff-touch.html)
- [iTead Sonoff T1](https://www.itead.cc/sonoff-t1.html)
- [iTead Sonoff SC](https://www.itead.cc/sonoff-sc.html)
- [iTead Sonoff Led](https://www.itead.cc/sonoff-led.html)<img src="https://github.com/arendst/arendst.github.io/blob/master/media/sonoff4chpror2.jpg" height="250" align="right" />
- [iTead Sonoff BN-SZ01 Ceiling Led](https://www.itead.cc/bn-sz01.html)
- [iTead Sonoff B1](https://www.itead.cc/sonoff-b1.html)
- [iTead Sonoff iFan02](https://www.itead.cc/sonoff-ifan02-wifi-smart-ceiling-fan-with-light.html)
- [iTead Sonoff RF Bridge 433](https://www.itead.cc/sonoff-rf-bridge-433.html)
- [iTead Sonoff Dev](https://www.itead.cc/sonoff-dev.html)
- [iTead 1 Channel Switch 5V / 12V](https://www.itead.cc/smart-home/inching-self-locking-wifi-wireless-switch.html)
- [iTead Motor Clockwise/Anticlockwise](https://www.itead.cc/smart-home/motor-reversing-wifi-wireless-switch.html)
- [Electrodragon IoT Relay Board](http://www.electrodragon.com/product/wifi-iot-relay-board-based-esp8266/)
- AI Light or any my9291 compatible RGBW LED bulb
- H801 PWM LED controller
- [MagicHome PWM LED controller](https://github.com/arendst/Sonoff-Tasmota/wiki/MagicHome-LED-strip-controller)
- AriLux AL-LC01, AL-LC06 and AL-LC11 PWM LED controller
- [Supla device - Espablo-inCan mod. for electrical Installation box](https://forum.supla.org/viewtopic.php?f=33&t=2188)
- [BlitzWolf BW-SHP2 Smart Socket with Energy Monitoring](https://www.banggood.com/BlitzWolf-BW-SHP2-Smart-WIFI-Socket-EU-Plug-220V-16A-Work-with-Amazon-Alexa-Google-Assistant-p-1292899.html)<img src="https://github.com/arendst/arendst.github.io/blob/master/media/shelly2_small_250a.png" width="250" align="right" />
- [Luani HVIO board](https://luani.de/projekte/esp8266-hvio/)
- [Wemos D1 mini](https://wiki.wemos.cc/products:d1:d1_mini)
- [HuaFan Smart Socket](https://github.com/arendst/Sonoff-Tasmota/wiki/HuaFan-Smart-Socket)
- [Hyleton-313 Smart Plug](https://github.com/arendst/Sonoff-Tasmota/wiki/Hyleton-313-Smart-Plug)
- [Allterco Shelly 1](https://shelly.cloud/shelly1-open-source/)
- [Allterco Shelly 2 with Energy Monitoring](https://shelly.cloud/shelly2/)
- NodeMcu and Ledunia
- [KS-602 based switches like GresaTek, Jesiya, NewRice, Lyasi etc](https://ucexperiment.wordpress.com/2017/11/14/reprogramming-a-lyasi-wifi-wall-switch-with-esp8285/)
### Contribute
You can contribute to Sonoff-Tasmota by
- providing Pull Requests (Features, Proof of Concepts, Language files or Fixes)
@ -162,7 +122,7 @@ People helping to keep the show on the road:
- Emontnemery for his HomeAssistant Discovery concept and many code tuning tips
- Aidan Mountford for his HSB support
- Daniel Ztolnai for his Serial Bridge implementation
- Gerhard Mutz for his SGP30, Sunrise/Sunset and display support drivers
- Gerhard Mutz for multiple sensor & display drivers, Sunrise/Sunset, and scripting
- Nuno Ferreira for his HC-SR04 driver
- Adrian Scillato for his (security)fixes and implementing and maintaining KNX
- Gennaro Tortone for implementing and maintaining Eastron drivers
@ -173,6 +133,7 @@ People helping to keep the show on the road:
- Frogmore42 and Jason2866 for providing many issue answers
- Blakadder for editing the wiki and providing template management
- Stephan Hadinger for refactoring light driver and enhancing HueEmulation
- tmo for designing the official logo
- Many more providing Tips, Wips, Pocs or PRs
### License

View File

@ -1,4 +1,7 @@
## Tasmota Reference
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
# Reference
Tasmota backgound information.
## Supported Smart Switch with Energy Monitoring GPIO usage

View File

@ -1,3 +1,7 @@
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
# RELEASE NOTES
## Migration Information
See [wiki migration path](https://github.com/arendst/Sonoff-Tasmota/wiki/Upgrade#migration-path) for instructions how to migrate to a major version. Pay attention to the following version breaks due to dynamic settings updates:
@ -6,11 +10,10 @@ See [wiki migration path](https://github.com/arendst/Sonoff-Tasmota/wiki/Upgrade
3. Migrate to **Sonoff-Tasmota 5.14**
4. Migrate to **Sonoff-Tasmota 6.x**
## Release notes
### Core version 2.3.0 vs 2.4.2
## Core version 2.3.0 vs 2.4.2
This release is based on ESP8266/Arduino library core 2.3.0 (again) as some people encountered wifi related issues on core 2.4.2. For others core 2.4.2 is working just fine. Both version are available from http://thehackbox.org/tasmota/release/
### Change in default initial configuration tool
## Change in default initial configuration tool
Firmware binary **sonoff-classic.bin** supports **WifiManager, Wps and SmartConfig** for initial configuration. The default tool is **Wps**.
To save memory space all other binaries support **WifiManager only**.
@ -104,7 +107,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
Core version **2.4.2** binaries can be found at http://thehackbox.org/tasmota/release/020402/
### Available Features and Sensors
## Available Features and Sensors
| Feature or Sensor | minimal | basic | classic | sonoff | knx | sensors | display | Remarks
|-----------------------|---------|-------|---------|--------|------|---------|---------|--------

View File

@ -1,21 +1,23 @@
# Sonoff-Tasmota Support
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
# Support
If you're looking for support on **Sonoff-Tasmota** there are some options available:
### Documentation:
## Documentation:
* [Wiki Pages](https://github.com/arendst/Sonoff-Tasmota/wiki): For information on how to Flash Tasmota, configure and use it.
* [FAQ](https://github.com/arendst/Sonoff-Tasmota/wiki/FAQ): For information on common problems and solutions.
* [Troubleshooting Information](https://github.com/arendst/Sonoff-Tasmota/wiki/Troubleshooting): For ways to debug and troubleshoot.
* [Commands Information](https://github.com/arendst/Sonoff-Tasmota/wiki/Commands): For information on all the commands supported by Tasmota.
### Support's Community:
## Support's Community:
* [Tasmota Forum](https://groups.google.com/d/forum/sonoffusers): For usage and discussions.
* [Tasmota Support Chat](https://discord.gg/Ks2Kzd4): For support, troubleshooting and general questions. You have better chances to get fast answers from members of the Tasmota Community.
* [Search in Issues](https://github.com/arendst/Sonoff-Tasmota/issues): You might find an answer to your question by searching current or closed issues.
### Developers' Community:
## Developers' Community:
* [Bug Report](https://github.com/arendst/Sonoff-Tasmota/issues/new?template=Bug_report.md): For reporting Bugs of Tasmota Software.
* [Feature Request](https://github.com/arendst/Sonoff-Tasmota/issues/new?template=Feature_request.md): For requesting features/functions to Tasmota Software.

View File

@ -1,4 +1,7 @@
## Sonoff-Tasmota template information
<img src="/tools/logo/TASMOTA_FullLogo_Vector.svg" alt="Logo" align="right" height="76"/>
# Template information
Sonoff-Tasmota uses Device or Module information to control peripherals connected to GPIOs. This information is stored in the ``sonoff_template.h`` file as a device specific template. The template contains information about what GPIO should be connected to what peripheral and what GPIO may be configured online using the ``GPIO`` command or GUI Configure Module menu. In addition a device may need specific coding to process the data from these peripherals. The module number as provided by the ``Modules`` command is used to select this coding.
Starting with version 6.4.1.16 Sonoff-Tasmota Modules can be extended by users online using a template. To provide easy processing by Sonoff-Tasmota a user template is written as JSON text and could look like this:
@ -83,4 +86,4 @@ The following command will update the flag of a stored template
``Template {"FLAG":1}``
The following command will update the base of a stored template to Generic
``Template {"BASE":0}``
``Template {"BASE":0}``

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,17 +0,0 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,470 +0,0 @@
// Copyright 2017 David Conran
#include "IRutils.h"
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <algorithm>
#ifndef ARDUINO
#include <string>
#endif
#include "IRrecv.h"
#include "IRremoteESP8266.h"
// Reverse the order of the requested least significant nr. of bits.
// Args:
// input: Bit pattern/integer to reverse.
// nbits: Nr. of bits to reverse.
// Returns:
// The reversed bit pattern.
uint64_t reverseBits(uint64_t input, uint16_t nbits) {
if (nbits <= 1) return input; // Reversing <= 1 bits makes no change at all.
// Cap the nr. of bits to rotate to the max nr. of bits in the input.
nbits = std::min(nbits, (uint16_t)(sizeof(input) * 8));
uint64_t output = 0;
for (uint16_t i = 0; i < nbits; i++) {
output <<= 1;
output |= (input & 1);
input >>= 1;
}
// Merge any remaining unreversed bits back to the top of the reversed bits.
return (input << nbits) | output;
}
// Convert a uint64_t (unsigned long long) to a string.
// Arduino String/toInt/Serial.print() can't handle printing 64 bit values.
//
// Args:
// input: The value to print
// base: The output base.
// Returns:
// A string representation of the integer.
// Note: Based on Arduino's Print::printNumber()
#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist.
String uint64ToString(uint64_t input, uint8_t base) {
String result = "";
#else
std::string uint64ToString(uint64_t input, uint8_t base) {
std::string result = "";
#endif
// prevent issues if called with base <= 1
if (base < 2) base = 10;
// Check we have a base that we can actually print.
// i.e. [0-9A-Z] == 36
if (base > 36) base = 10;
do {
char c = input % base;
input /= base;
if (c < 10)
c += '0';
else
c += 'A' - 10;
result = c + result;
} while (input);
return result;
}
#ifdef ARDUINO
// Print a uint64_t/unsigned long long to the Serial port
// Serial.print() can't handle printing long longs. (uint64_t)
//
// Args:
// input: The value to print
// base: The output base.
void serialPrintUint64(uint64_t input, uint8_t base) {
Serial.print(uint64ToString(input, base));
}
#endif
// Convert a protocol type (enum etc) to a human readable string.
// Args:
// protocol: Nr. (enum) of the protocol.
// isRepeat: A flag indicating if it is a repeat message of the protocol.
// Returns:
// A string containing the protocol name.
#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist.
String typeToString(const decode_type_t protocol, const bool isRepeat) {
String result = "";
#else
std::string typeToString(const decode_type_t protocol, const bool isRepeat) {
std::string result = "";
#endif
switch (protocol) {
default:
case UNKNOWN:
result = "UNKNOWN";
break;
case UNUSED:
result = "UNUSED";
break;
case AIWA_RC_T501:
result = "AIWA_RC_T501";
break;
case ARGO:
result = "ARGO";
break;
case CARRIER_AC:
result = "CARRIER_AC";
break;
case COOLIX:
result = "COOLIX";
break;
case DAIKIN:
result = "DAIKIN";
break;
case DENON:
result = "DENON";
break;
case DISH:
result = "DISH";
break;
case ELECTRA_AC:
result = "ELECTRA_AC";
break;
case FUJITSU_AC:
result = "FUJITSU_AC";
break;
case GICABLE:
result = "GICABLE";
break;
case GLOBALCACHE:
result = "GLOBALCACHE";
break;
case GREE:
result = "GREE";
break;
case HAIER_AC:
result = "HAIER_AC";
break;
case HAIER_AC_YRW02:
result = "HAIER_AC_YRW02";
break;
case HITACHI_AC:
result = "HITACHI_AC";
break;
case HITACHI_AC1:
result = "HITACHI_AC1";
break;
case HITACHI_AC2:
result = "HITACHI_AC2";
break;
case JVC:
result = "JVC";
break;
case KELVINATOR:
result = "KELVINATOR";
break;
case LG:
result = "LG";
break;
case LG2:
result = "LG2";
break;
case LASERTAG:
result = "LASERTAG";
break;
case LUTRON:
result = "LUTRON";
break;
case MAGIQUEST:
result = "MAGIQUEST";
break;
case MIDEA:
result = "MIDEA";
break;
case MITSUBISHI:
result = "MITSUBISHI";
break;
case MITSUBISHI2:
result = "MITSUBISHI2";
break;
case MITSUBISHI_AC:
result = "MITSUBISHI_AC";
break;
case MWM:
result = "MWM";
break;
case NEC:
result = "NEC";
break;
case NEC_LIKE:
result = "NEC (non-strict)";
break;
case NIKAI:
result = "NIKAI";
break;
case PANASONIC:
result = "PANASONIC";
break;
case PANASONIC_AC:
result = "PANASONIC_AC";
break;
case PIONEER:
result = "PIONEER";
break;
case PRONTO:
result = "PRONTO";
break;
case RAW:
result = "RAW";
break;
case RC5:
result = "RC5";
break;
case RC5X:
result = "RC5X";
break;
case RC6:
result = "RC6";
break;
case RCMM:
result = "RCMM";
break;
case SAMSUNG:
result = "SAMSUNG";
break;
case SAMSUNG_AC:
result = "SAMSUNG_AC";
break;
case SANYO:
result = "SANYO";
break;
case SANYO_LC7461:
result = "SANYO_LC7461";
break;
case SHARP:
result = "SHARP";
break;
case SHERWOOD:
result = "SHERWOOD";
break;
case SONY:
result = "SONY";
break;
case TOSHIBA_AC:
result = "TOSHIBA_AC";
break;
case TROTEC:
result = "TROTEC";
break;
case WHIRLPOOL_AC:
result = "WHIRLPOOL_AC";
break;
case WHYNTER:
result = "WHYNTER";
break;
}
if (isRepeat) result += " (Repeat)";
return result;
}
// Does the given protocol use a complex state as part of the decode?
bool hasACState(const decode_type_t protocol) {
switch (protocol) {
case DAIKIN:
case ELECTRA_AC:
case FUJITSU_AC:
case GREE:
case HAIER_AC:
case HAIER_AC_YRW02:
case HITACHI_AC:
case HITACHI_AC1:
case HITACHI_AC2:
case KELVINATOR:
case MITSUBISHI_AC:
case MWM:
case PANASONIC_AC:
case SAMSUNG_AC:
case TOSHIBA_AC:
case WHIRLPOOL_AC:
return true;
default:
return false;
}
}
// Return the corrected length of a 'raw' format array structure
// after over-large values are converted into multiple entries.
// Args:
// results: A ptr to a decode result.
// Returns:
// A uint16_t containing the length.
uint16_t getCorrectedRawLength(const decode_results *results) {
uint16_t extended_length = results->rawlen - 1;
for (uint16_t i = 0; i < results->rawlen - 1; i++) {
uint32_t usecs = results->rawbuf[i] * kRawTick;
// Add two extra entries for multiple larger than UINT16_MAX it is.
extended_length += (usecs / (UINT16_MAX + 1)) * 2;
}
return extended_length;
}
// Return a string containing the key values of a decode_results structure
// in a C/C++ code style format.
#ifdef ARDUINO
String resultToSourceCode(const decode_results *results) {
String output = "";
#else
std::string resultToSourceCode(const decode_results *results) {
std::string output = "";
#endif
// Start declaration
output += "uint16_t "; // variable type
output += "rawData["; // array name
output += uint64ToString(getCorrectedRawLength(results), 10);
// array size
output += "] = {"; // Start declaration
// Dump data
for (uint16_t i = 1; i < results->rawlen; i++) {
uint32_t usecs;
for (usecs = results->rawbuf[i] * kRawTick; usecs > UINT16_MAX;
usecs -= UINT16_MAX) {
output += uint64ToString(UINT16_MAX);
if (i % 2)
output += ", 0, ";
else
output += ", 0, ";
}
output += uint64ToString(usecs, 10);
if (i < results->rawlen - 1)
output += ", "; // ',' not needed on the last one
if (i % 2 == 0) output += " "; // Extra if it was even.
}
// End declaration
output += "};";
// Comment
output += " // " + typeToString(results->decode_type, results->repeat);
// Only display the value if the decode type doesn't have an A/C state.
if (!hasACState(results->decode_type))
output += " " + uint64ToString(results->value, 16);
output += "\n";
// Now dump "known" codes
if (results->decode_type != UNKNOWN) {
if (hasACState(results->decode_type)) {
#if DECODE_AC
uint16_t nbytes = results->bits / 8;
output += "uint8_t state[" + uint64ToString(nbytes) + "] = {";
for (uint16_t i = 0; i < nbytes; i++) {
output += "0x";
if (results->state[i] < 0x10) output += "0";
output += uint64ToString(results->state[i], 16);
if (i < nbytes - 1) output += ", ";
}
output += "};\n";
#endif // DECODE_AC
} else {
// Simple protocols
// Some protocols have an address &/or command.
// NOTE: It will ignore the atypical case when a message has been
// decoded but the address & the command are both 0.
if (results->address > 0 || results->command > 0) {
output += "uint32_t address = 0x" +
uint64ToString(results->address, 16) + ";\n";
output += "uint32_t command = 0x" +
uint64ToString(results->command, 16) + ";\n";
}
// Most protocols have data
output +=
"uint64_t data = 0x" + uint64ToString(results->value, 16) + ";\n";
}
}
return output;
}
// Dump out the decode_results structure.
//
#ifdef ARDUINO
String resultToTimingInfo(const decode_results *results) {
String output = "";
String value = "";
#else
std::string resultToTimingInfo(const decode_results *results) {
std::string output = "";
std::string value = "";
#endif
output += "Raw Timing[" + uint64ToString(results->rawlen - 1, 10) + "]:\n";
for (uint16_t i = 1; i < results->rawlen; i++) {
if (i % 2 == 0)
output += "-"; // even
else
output += " +"; // odd
value = uint64ToString(results->rawbuf[i] * kRawTick);
// Space pad the value till it is at least 6 chars long.
while (value.length() < 6) value = " " + value;
output += value;
if (i < results->rawlen - 1) output += ", "; // ',' not needed for last one
if (!(i % 8)) output += "\n"; // Newline every 8 entries.
}
output += "\n";
return output;
}
// Convert the decode_results structure's value/state to simple hexadecimal.
//
#ifdef ARDUINO
String resultToHexidecimal(const decode_results *result) {
String output = "";
#else
std::string resultToHexidecimal(const decode_results *result) {
std::string output = "";
#endif
if (hasACState(result->decode_type)) {
#if DECODE_AC
for (uint16_t i = 0; result->bits > i * 8; i++) {
if (result->state[i] < 0x10) output += "0"; // Zero pad
output += uint64ToString(result->state[i], 16);
}
#endif // DECODE_AC
} else {
output += uint64ToString(result->value, 16);
}
return output;
}
// Dump out the decode_results structure.
//
#ifdef ARDUINO
String resultToHumanReadableBasic(const decode_results *results) {
String output = "";
#else
std::string resultToHumanReadableBasic(const decode_results *results) {
std::string output = "";
#endif
// Show Encoding standard
output +=
"Encoding : " + typeToString(results->decode_type, results->repeat) +
"\n";
// Show Code & length
output += "Code : ";
output += resultToHexidecimal(results);
output += " (" + uint64ToString(results->bits) + " bits)\n";
return output;
}
uint8_t sumBytes(uint8_t *start, const uint16_t length, const uint8_t init) {
uint8_t checksum = init;
uint8_t *ptr;
for (ptr = start; ptr - start < length; ptr++) checksum += *ptr;
return checksum;
}
uint64_t invertBits(const uint64_t data, const uint16_t nbits) {
// No change if we are asked to invert no bits.
if (nbits == 0) return data;
uint64_t result = ~data;
// If we are asked to invert all the bits or more than we have, it's simple.
if (nbits >= sizeof(data) * 8) return result;
// Mask off any unwanted bits and return the result.
return (result & ((1ULL << nbits) - 1));
}

View File

@ -1,750 +0,0 @@
/*
An Arduino sketch to emulate IR Daikin ARC433** remote control unit
Read more at:
http://harizanov.com/2012/02/control-daikin-air-conditioner-over-the-internet/
Copyright 2016 sillyfrog
Copyright 2017 sillyfrog, crankyoldgit
*/
#include "ir_Daikin.h"
#include <algorithm>
#ifndef ARDUINO
#include <string>
#endif
#include "IRrecv.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "IRutils.h"
// DDDDD AAA IIIII KK KK IIIII NN NN
// DD DD AAAAA III KK KK III NNN NN
// DD DD AA AA III KKKK III NN N NN
// DD DD AAAAAAA III KK KK III NN NNN
// DDDDDD AA AA IIIII KK KK IIIII NN NN
// Constants
// Ref:
// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
// http://rdlab.cdmt.vn/project-2013/daikin-ir-protocol
#if SEND_DAIKIN
// Original header
// static uint8_t header1[DAIKIN_HEADER1_LENGTH];
// header1[0] = 0b00010001;
// header1[1] = 0b11011010;
// header1[2] = 0b00100111;
// header1[3] = 0b00000000;
// header1[4] = 0b11000101;
// header1[5] = 0b00000000;
// header1[6] = 0b00000000;
// header1[7] = 0b11010111;
// Send a Daikin A/C message.
//
// Args:
// data: An array of kDaikinStateLength bytes containing the IR command.
//
// Status: STABLE
//
// Ref:
// IRDaikinESP.cpp
// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
void IRsend::sendDaikin(unsigned char data[], uint16_t nbytes,
uint16_t repeat) {
if (nbytes < kDaikinStateLength)
return; // Not enough bytes to send a proper message.
for (uint16_t r = 0; r <= repeat; r++) {
// Send the header, 0b00000
sendGeneric(0, 0, // No header for the header
kDaikinBitMark, kDaikinOneSpace, kDaikinBitMark,
kDaikinZeroSpace, kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
(uint64_t)0b00000, 5, 38, false, 0, 50);
// Leading header
// Do this as a constant to save RAM and keep in flash memory
sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
kDaikinBitMark, kDaikinZeroSpace + kDaikinGap,
kDaikinFirstHeader64, 64, 38, false, 0, 50);
// Data #1
sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
kDaikinBitMark, kDaikinZeroSpace + kDaikinGap, data, 8, 38,
false, 0, 50);
// Data #2
sendGeneric(kDaikinHdrMark, kDaikinHdrSpace, kDaikinBitMark,
kDaikinOneSpace, kDaikinBitMark, kDaikinZeroSpace,
kDaikinBitMark, kDaikinZeroSpace + kDaikinGap, data + 8,
nbytes - 8, 38, false, 0, 50);
}
}
#endif // SEND_DAIKIN
IRDaikinESP::IRDaikinESP(uint16_t pin) : _irsend(pin) { stateReset(); }
void IRDaikinESP::begin() { _irsend.begin(); }
#if SEND_DAIKIN
void IRDaikinESP::send() {
checksum();
_irsend.sendDaikin(daikin);
}
#endif // SEND_DAIKIN
// Calculate the checksum for a given data block.
// Args:
// block: Ptr to the start of the data block.
// length: Nr. of bytes to checksum.
// Returns:
// A byte containing the calculated checksum.
uint8_t IRDaikinESP::calcBlockChecksum(const uint8_t *block,
const uint16_t length) {
uint8_t sum = 0;
// Daikin checksum is just the addition of all the data bytes
// in the block but capped to 8 bits.
for (uint16_t i = 0; i < length; i++, block++) sum += *block;
return sum & 0xFFU;
}
// Verify the checksum is valid for a given state.
// Args:
// state: The array to verify the checksum of.
// length: The size of the state.
// Returns:
// A boolean.
bool IRDaikinESP::validChecksum(const uint8_t state[], const uint16_t length) {
if (length < 8 || state[7] != calcBlockChecksum(state, 7)) return false;
if (length < 10 ||
state[length - 1] != calcBlockChecksum(state + 8, length - 9))
return false;
return true;
}
// Calculate and set the checksum values for the internal state.
void IRDaikinESP::checksum() {
daikin[7] = calcBlockChecksum(daikin, 7);
daikin[26] = calcBlockChecksum(daikin + 8, 17);
}
void IRDaikinESP::stateReset() {
for (uint8_t i = 0; i < kDaikinStateLength; i++) daikin[i] = 0x0;
daikin[0] = 0x11;
daikin[1] = 0xDA;
daikin[2] = 0x27;
daikin[4] = 0x42;
// daikin[7] is a checksum byte, it will be set by checksum().
daikin[8] = 0x11;
daikin[9] = 0xDA;
daikin[10] = 0x27;
daikin[13] = 0x49;
daikin[14] = 0x1E;
daikin[16] = 0xB0;
daikin[19] = 0x06;
daikin[20] = 0x60;
daikin[23] = 0xC0;
// daikin[26] is a checksum byte, it will be set by checksum().
checksum();
}
uint8_t *IRDaikinESP::getRaw() {
checksum(); // Ensure correct settings before sending.
return daikin;
}
void IRDaikinESP::setRaw(uint8_t new_code[]) {
for (uint8_t i = 0; i < kDaikinStateLength; i++) daikin[i] = new_code[i];
}
void IRDaikinESP::on() {
// state = ON;
setBit(kDaikinBytePower, kDaikinBitPower);
}
void IRDaikinESP::off() {
// state = OFF;
clearBit(kDaikinBytePower, kDaikinBitPower);
}
void IRDaikinESP::setPower(bool state) {
if (state)
on();
else
off();
}
bool IRDaikinESP::getPower() {
return (getBit(kDaikinBytePower, kDaikinBitPower) > 0);
}
// Set the temp in deg C
void IRDaikinESP::setTemp(uint8_t temp) {
if (temp < kDaikinMinTemp)
temp = kDaikinMinTemp;
else if (temp > kDaikinMaxTemp)
temp = kDaikinMaxTemp;
daikin[14] = temp * 2;
}
uint8_t IRDaikinESP::getTemp() { return daikin[14] / 2; }
// Set the speed of the fan, 1-5 or kDaikinFanAuto or kDaikinFanQuiet
void IRDaikinESP::setFan(uint8_t fan) {
// Set the fan speed bits, leave low 4 bits alone
uint8_t fanset;
if (fan == kDaikinFanQuiet || fan == kDaikinFanAuto)
fanset = fan;
else if (fan < kDaikinFanMin || fan > kDaikinFanMax)
fanset = kDaikinFanAuto;
else
fanset = 2 + fan;
daikin[16] &= 0x0F;
daikin[16] |= (fanset << 4);
}
uint8_t IRDaikinESP::getFan() {
uint8_t fan = daikin[16] >> 4;
if (fan != kDaikinFanQuiet && fan != kDaikinFanAuto) fan -= 2;
return fan;
}
uint8_t IRDaikinESP::getMode() {
/*
kDaikinCool
kDaikinHeat
kDaikinFan
kDaikinAuto
kDaikinDry
*/
return daikin[13] >> 4;
}
void IRDaikinESP::setMode(uint8_t mode) {
switch (mode) {
case kDaikinCool:
case kDaikinHeat:
case kDaikinFan:
case kDaikinDry:
break;
default:
mode = kDaikinAuto;
}
mode <<= 4;
daikin[13] &= 0b10001111;
daikin[13] |= mode;
}
void IRDaikinESP::setSwingVertical(bool state) {
if (state)
daikin[16] |= 0x0F;
else
daikin[16] &= 0xF0;
}
bool IRDaikinESP::getSwingVertical() { return daikin[16] & 0x01; }
void IRDaikinESP::setSwingHorizontal(bool state) {
if (state)
daikin[17] |= 0x0F;
else
daikin[17] &= 0xF0;
}
bool IRDaikinESP::getSwingHorizontal() { return daikin[17] & 0x01; }
void IRDaikinESP::setQuiet(bool state) {
if (state) {
setBit(kDaikinByteSilent, kDaikinBitSilent);
// Powerful & Quiet mode being on are mutually exclusive.
setPowerful(false);
} else {
clearBit(kDaikinByteSilent, kDaikinBitSilent);
}
}
bool IRDaikinESP::getQuiet() {
return (getBit(kDaikinByteSilent, kDaikinBitSilent) > 0);
}
void IRDaikinESP::setPowerful(bool state) {
if (state) {
setBit(kDaikinBytePowerful, kDaikinBitPowerful);
// Powerful, Quiet, & Econo mode being on are mutually exclusive.
setQuiet(false);
setEcono(false);
} else {
clearBit(kDaikinBytePowerful, kDaikinBitPowerful);
}
}
bool IRDaikinESP::getPowerful() {
return (getBit(kDaikinBytePowerful, kDaikinBitPowerful) > 0);
}
void IRDaikinESP::setSensor(bool state) {
if (state)
setBit(kDaikinByteSensor, kDaikinBitSensor);
else
clearBit(kDaikinByteSensor, kDaikinBitSensor);
}
bool IRDaikinESP::getSensor() {
return (getBit(kDaikinByteSensor, kDaikinBitSensor) > 0);
}
void IRDaikinESP::setEcono(bool state) {
if (state) {
setBit(kDaikinByteEcono, kDaikinBitEcono);
// Powerful & Econo mode being on are mutually exclusive.
setPowerful(false);
} else {
clearBit(kDaikinByteEcono, kDaikinBitEcono);
}
}
bool IRDaikinESP::getEcono() {
return (getBit(kDaikinByteEcono, kDaikinBitEcono) > 0);
}
void IRDaikinESP::setEye(bool state) {
if (state)
setBit(kDaikinByteEye, kDaikinBitEye);
else
clearBit(kDaikinByteEye, kDaikinBitEye);
}
bool IRDaikinESP::getEye() {
return (getBit(kDaikinByteEye, kDaikinBitEye) > 0);
}
void IRDaikinESP::setMold(bool state) {
if (state)
setBit(kDaikinByteMold, kDaikinBitMold);
else
clearBit(kDaikinByteMold, kDaikinBitMold);
}
bool IRDaikinESP::getMold() {
return (getBit(kDaikinByteMold, kDaikinBitMold) > 0);
}
void IRDaikinESP::setBit(uint8_t byte, uint8_t bitmask) {
daikin[byte] |= bitmask;
}
void IRDaikinESP::clearBit(uint8_t byte, uint8_t bitmask) {
bitmask = ~bitmask;
daikin[byte] &= bitmask;
}
uint8_t IRDaikinESP::getBit(uint8_t byte, uint8_t bitmask) {
return daikin[byte] & bitmask;
}
// starttime: Number of minutes after midnight, in 10 minutes increments
void IRDaikinESP::enableOnTimer(uint16_t starttime) {
setBit(kDaikinByteOnTimer, kDaikinBitOnTimer);
daikin[18] = (uint8_t)(starttime & 0x00FF);
// only keep 4 bits
daikin[19] &= 0xF0;
daikin[19] |= (uint8_t)((starttime >> 8) & 0x0F);
}
void IRDaikinESP::disableOnTimer() {
enableOnTimer(0x600);
clearBit(kDaikinByteOnTimer, kDaikinBitOnTimer);
}
uint16_t IRDaikinESP::getOnTime() {
uint16_t ret;
ret = daikin[19] & 0x0F;
ret = ret << 8;
ret += daikin[18];
return ret;
}
bool IRDaikinESP::getOnTimerEnabled() {
return getBit(kDaikinByteOnTimer, kDaikinBitOnTimer);
}
// endtime: Number of minutes after midnight, in 10 minutes increments
void IRDaikinESP::enableOffTimer(uint16_t endtime) {
setBit(kDaikinByteOffTimer, kDaikinBitOffTimer);
daikin[20] = (uint8_t)((endtime >> 4) & 0xFF);
daikin[19] &= 0x0F;
daikin[19] |= (uint8_t)((endtime & 0x000F) << 4);
}
void IRDaikinESP::disableOffTimer() {
enableOffTimer(0x600);
clearBit(kDaikinByteOffTimer, kDaikinBitOffTimer);
}
uint16_t IRDaikinESP::getOffTime() {
uint16_t ret, tmp;
ret = daikin[20];
ret <<= 4;
tmp = daikin[19] & 0xF0;
tmp >>= 4;
ret += tmp;
return ret;
}
bool IRDaikinESP::getOffTimerEnabled() {
return getBit(kDaikinByteOffTimer, kDaikinBitOffTimer);
}
void IRDaikinESP::setCurrentTime(uint16_t numMins) {
if (numMins > 24 * 60) numMins = 0; // If > 23:59, set to 00:00
daikin[5] = (uint8_t)(numMins & 0x00FF);
// only keep 4 bits
daikin[6] &= 0xF0;
daikin[6] |= (uint8_t)((numMins >> 8) & 0x0F);
}
uint16_t IRDaikinESP::getCurrentTime() {
uint16_t ret;
ret = daikin[6] & 0x0F;
ret <<= 8;
ret += daikin[5];
return ret;
}
#ifdef ARDUINO
String IRDaikinESP::renderTime(uint16_t timemins) {
String ret;
#else // ARDUINO
std::string IRDaikinESP::renderTime(uint16_t timemins) {
std::string ret;
#endif // ARDUINO
uint16_t hours, mins;
hours = timemins / 60;
ret = uint64ToString(hours) + ":";
mins = timemins - (hours * 60);
if (mins < 10) ret += "0";
ret += uint64ToString(mins);
return ret;
}
// Convert the internal state into a human readable string.
#ifdef ARDUINO
String IRDaikinESP::toString() {
String result = "";
#else // ARDUINO
std::string IRDaikinESP::toString() {
std::string result = "";
#endif // ARDUINO
result += "Power: ";
if (getPower())
result += "On";
else
result += "Off";
result += ", Mode: " + uint64ToString(getMode());
switch (getMode()) {
case kDaikinAuto:
result += " (AUTO)";
break;
case kDaikinCool:
result += " (COOL)";
break;
case kDaikinHeat:
result += " (HEAT)";
break;
case kDaikinDry:
result += " (DRY)";
break;
case kDaikinFan:
result += " (FAN)";
break;
default:
result += " (UNKNOWN)";
}
result += ", Temp: " + uint64ToString(getTemp()) + "C";
result += ", Fan: " + uint64ToString(getFan());
switch (getFan()) {
case kDaikinFanAuto:
result += " (AUTO)";
break;
case kDaikinFanQuiet:
result += " (QUIET)";
break;
case kDaikinFanMin:
result += " (MIN)";
break;
case kDaikinFanMax:
result += " (MAX)";
break;
}
result += ", Powerful: ";
if (getPowerful())
result += "On";
else
result += "Off";
result += ", Quiet: ";
if (getQuiet())
result += "On";
else
result += "Off";
result += ", Sensor: ";
if (getSensor())
result += "On";
else
result += "Off";
result += ", Eye: ";
if (getEye())
result += "On";
else
result += "Off";
result += ", Mold: ";
if (getMold())
result += "On";
else
result += "Off";
result += ", Swing (Horizontal): ";
if (getSwingHorizontal())
result += "On";
else
result += "Off";
result += ", Swing (Vertical): ";
if (getSwingVertical())
result += "On";
else
result += "Off";
result += ", Current Time: " + renderTime(getCurrentTime());
result += ", On Time: ";
if (getOnTimerEnabled())
result += renderTime(getOnTime());
else
result += "Off";
result += ", Off Time: ";
if (getOffTimerEnabled())
result += renderTime(getOffTime());
else
result += "Off";
return result;
}
#if DAIKIN_DEBUG
// Print what we have
void IRDaikinESP::printState() {
#ifdef ARDUINO
String strbits;
#else // ARDUINO
std::string strbits;
#endif // ARDUINO
DPRINTLN("Raw Bits:");
for (uint8_t i = 0; i < kDaikinStateLength; i++) {
strbits = uint64ToString(daikin[i], BIN);
while (strbits.length() < 8) strbits = "0" + strbits;
DPRINT(strbits);
DPRINT(" ");
}
DPRINTLN("");
DPRINTLN(toString());
}
#endif // DAIKIN_DEBUG
/*
* Return most important bits to allow replay
* layout is:
* 0: Power
* 1-3: Mode
* 4-7: Fan speed/mode
* 8-14: Target Temperature
* 15: Econo
* 16: Powerful
* 17: Quiet
* 18: Sensor
* 19: Swing Vertical
* 20-31: Current time (mins since midnight)
* */
uint32_t IRDaikinESP::getCommand() {
uint32_t ret = 0;
uint32_t tmp = 0;
if (getPower()) ret |= 0b00000000000000000000000000000001;
tmp = getMode();
tmp = tmp << 1;
ret |= tmp;
tmp = getFan();
tmp <<= 4;
ret |= tmp;
tmp = getTemp();
tmp <<= 8;
ret |= tmp;
if (getEcono()) ret |= 0b00000000000000001000000000000000;
if (getPowerful()) ret |= 0b00000000000000010000000000000000;
if (getQuiet()) ret |= 0b00000000000000100000000000000000;
if (getSensor()) ret |= 0b00000000000001000000000000000000;
if (getSwingVertical()) ret |= 0b00000000000010000000000000000000;
ret |= (getCurrentTime() << 20);
return ret;
}
void IRDaikinESP::setCommand(uint32_t value) {
uint32_t tmp = 0;
if (value & 0b00000000000000000000000000000001) setPower(true);
tmp = value & 0b00000000000000000000000000001110;
tmp >>= 1;
setMode(tmp);
tmp = value & 0b00000000000000000000000011110000;
tmp >>= 4;
setFan(tmp);
tmp = value & 0b00000000000000000111111100000000;
tmp >>= 8;
setTemp(tmp);
if (value & 0b00000000000000001000000000000000) setEcono(true);
if (value & 0b00000000000000010000000000000000) setPowerful(true);
if (value & 0b00000000000000100000000000000000) setQuiet(true);
if (value & 0b00000000000001000000000000000000) setSensor(true);
if (value & 0b00000000000010000000000000000000) setSwingVertical(true);
value >>= 20;
setCurrentTime(value);
}
#if DECODE_DAIKIN
void addbit(bool val, unsigned char data[]) {
uint8_t curbit = data[kDaikinCurBit];
uint8_t curindex = data[kDaikinCurIndex];
if (val) {
unsigned char bit = 1;
bit = bit << curbit;
data[curindex] |= bit;
}
curbit++;
if (curbit == 8) {
curbit = 0;
curindex++;
}
data[kDaikinCurBit] = curbit;
data[kDaikinCurIndex] = curindex;
}
bool checkheader(decode_results *results, uint16_t *offset) {
if (!IRrecv::matchMark(results->rawbuf[(*offset)++], kDaikinBitMark,
kDaikinTolerance, kDaikinMarkExcess))
return false;
if (!IRrecv::matchSpace(results->rawbuf[(*offset)++],
kDaikinZeroSpace + kDaikinGap, kDaikinTolerance,
kDaikinMarkExcess))
return false;
if (!IRrecv::matchMark(results->rawbuf[(*offset)++], kDaikinHdrMark,
kDaikinTolerance, kDaikinMarkExcess))
return false;
if (!IRrecv::matchSpace(results->rawbuf[(*offset)++], kDaikinHdrSpace,
kDaikinTolerance, kDaikinMarkExcess))
return false;
return true;
}
bool readbits(decode_results *results, uint16_t *offset,
unsigned char daikin_code[], uint16_t countbits) {
for (uint16_t i = 0; i < countbits && *offset < results->rawlen - 1;
i++, (*offset)++) {
if (!IRrecv::matchMark(results->rawbuf[(*offset)++], kDaikinBitMark,
kDaikinTolerance, kDaikinMarkExcess))
return false;
if (IRrecv::matchSpace(results->rawbuf[*offset], kDaikinOneSpace,
kDaikinTolerance, kDaikinMarkExcess))
addbit(1, daikin_code);
else if (IRrecv::matchSpace(results->rawbuf[*offset], kDaikinZeroSpace,
kDaikinTolerance, kDaikinMarkExcess))
addbit(0, daikin_code);
else
return false;
}
return true;
}
// Decode the supplied Daikin A/C message.
// Args:
// results: Ptr to the data to decode and where to store the decode result.
// nbits: Nr. of bits to expect in the data portion. (kDaikinRawBits)
// strict: Flag to indicate if we strictly adhere to the specification.
// Returns:
// boolean: True if it can decode it, false if it can't.
//
// Status: BETA / Should be working.
//
// Notes:
// If DAIKIN_DEBUG enabled, will print all the set options and values.
//
// Ref:
// https://github.com/mharizanov/Daikin-AC-remote-control-over-the-Internet/tree/master/IRremote
bool IRrecv::decodeDaikin(decode_results *results, uint16_t nbits,
bool strict) {
if (results->rawlen < kDaikinRawBits) return false;
// Compliance
if (strict && nbits != kDaikinRawBits) return false;
uint16_t offset = kStartOffset;
unsigned char daikin_code[kDaikinStateLength + 2];
for (uint8_t i = 0; i < kDaikinStateLength + 2; i++) daikin_code[i] = 0;
// Header (#1)
for (uint8_t i = 0; i < 10; i++) {
if (!matchMark(results->rawbuf[offset++], kDaikinBitMark)) return false;
}
if (!checkheader(results, &offset)) return false;
// Data (#1)
if (!readbits(results, &offset, daikin_code, 8 * 8)) return false;
// Ignore everything that has just been captured as it is not needed.
// Some remotes may not send this portion, my remote did, but it's not
// required.
for (uint8_t i = 0; i < kDaikinStateLength + 2; i++) daikin_code[i] = 0;
// Header (#2)
if (!checkheader(results, &offset)) return false;
// Data (#2)
if (!readbits(results, &offset, daikin_code, 8 * 8)) return false;
// Header (#3)
if (!checkheader(results, &offset)) return false;
// Data (#3), read up everything else
if (!readbits(results, &offset, daikin_code, kDaikinBits - (8 * 8)))
return false;
// Footer
if (!matchMark(results->rawbuf[offset++], kDaikinBitMark)) return false;
if (offset < results->rawlen &&
!matchAtLeast(results->rawbuf[offset], kDaikinGap))
return false;
// Compliance
if (strict) {
if (!IRDaikinESP::validChecksum(daikin_code)) return false;
}
// Success
#if DAIKIN_DEBUG
IRDaikinESP dako = IRDaikinESP(0);
dako.setRaw(daikin_code);
#ifdef ARDUINO
yield();
#endif // ARDUINO
dako.printState();
#endif // DAIKIN_DEBUG
// Copy across the bits to state
for (uint8_t i = 0; i < kDaikinStateLength; i++)
results->state[i] = daikin_code[i];
results->bits = kDaikinStateLength * 8;
results->decode_type = DAIKIN;
return true;
}
#endif // DECODE_DAIKIN

View File

@ -1,208 +0,0 @@
// Copyright 2016 sillyfrog
// Copyright 2017 sillyfrog, crankyoldgit
#ifndef IR_DAIKIN_H_
#define IR_DAIKIN_H_
#ifndef UNIT_TEST
#include <Arduino.h>
#else
#include <string>
#endif
#include "IRrecv.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
// Option to disable the additional Daikin debug info to conserve memory
#define DAIKIN_DEBUG false
// DDDDD AAA IIIII KK KK IIIII NN NN
// DD DD AAAAA III KK KK III NNN NN
// DD DD AA AA III KKKK III NN N NN
// DD DD AAAAAAA III KK KK III NN NNN
// DDDDDD AA AA IIIII KK KK IIIII NN NN
/*
Daikin AC map
byte 5=Current time, mins past midnight, low bits
byte 6
b0-b3=Current time, mins past midnight, high bits
byte 7= checksum of the first part (and last byte before a 29ms pause)
byte 13=mode
b7 = 0
b6+b5+b4 = Mode
Modes: b6+b5+b4
011 = Cool
100 = Heat (temp 23)
110 = FAN (temp not shown, but 25)
000 = Fully Automatic (temp 25)
010 = DRY (temp 0xc0 = 96 degrees c)
b3 = 1
b2 = OFF timer set
b1 = ON timer set
b0 = Air Conditioner ON
byte 14=temp*2 (Temp should be between 10 - 32)
byte 16=Fan
FAN control
b7+b6+b5+b4 = Fan speed
Fan: b7+b6+b5+b4
0×3 = 1 bar
0×4 = 2 bar
0×5 = 3 bar
0×6 = 4 bar
0×7 = 5 bar
0xa = Auto
0xb = Quite
b3+b2+b1+b0 = Swing control up/down
Swing control up/down:
0000 = Swing up/down off
1111 = Swing up/down on
byte 17
Swing control left/right:
0000 = Swing left/right off
1111 = Swing left/right on
byte 18=On timer mins past midnight, low bits
byte 19
b0-b3=On timer mins past midnight, high bits
b4-b7=Off timer mins past midnight, low bits
byte 20=Off timer mins past midnight, high bits
byte 21=Aux -> Powerful (bit 1), Silent (bit 5)
byte 24=Aux2
b1: Sensor
b2: Econo mode
b7: Intelligent eye on
byte 25=Aux3
b1: Mold Proof
byte 26= checksum of the second part
*/
// Constants
const uint8_t kDaikinAuto = 0b000;
const uint8_t kDaikinDry = 0b010;
const uint8_t kDaikinCool = 0b011;
const uint8_t kDaikinHeat = 0b100;
const uint8_t kDaikinFan = 0b110;
const uint8_t kDaikinMinTemp = 10; // Celsius
const uint8_t kDaikinMaxTemp = 32; // Celsius
const uint8_t kDaikinFanMin = 1;
const uint8_t kDaikinFanMax = 5;
const uint8_t kDaikinFanAuto = 0b1010;
const uint8_t kDaikinFanQuiet = 0b1011;
const uint8_t kDaikinBytePower = 13;
const uint8_t kDaikinBitPower = 0b00000001;
const uint8_t kDaikinBytePowerful = 21;
const uint8_t kDaikinBitPowerful = 0b00000001;
const uint8_t kDaikinByteSilent = 21;
const uint8_t kDaikinBitSilent = 0b00100000;
const uint8_t kDaikinByteSensor = 24;
const uint8_t kDaikinBitSensor = 0b00000010;
const uint8_t kDaikinByteEcono = 24;
const uint8_t kDaikinBitEcono = 0b00000100;
const uint8_t kDaikinByteEye = 24;
const uint8_t kDaikinBitEye = 0b10000000;
const uint8_t kDaikinByteMold = 25;
const uint8_t kDaikinBitMold = 0b00000010;
const uint8_t kDaikinByteOffTimer = 13;
const uint8_t kDaikinBitOffTimer = 0b00000100;
const uint8_t kDaikinByteOnTimer = 13;
const uint8_t kDaikinBitOnTimer = 0b00000010;
const uint8_t kDaikinCurBit = kDaikinStateLength;
const uint8_t kDaikinCurIndex = kDaikinStateLength + 1;
const uint8_t kDaikinTolerance = 35;
const uint16_t kDaikinMarkExcess = kMarkExcess;
const uint16_t kDaikinHdrMark = 3650; // kDaikinBitMark * 8
const uint16_t kDaikinHdrSpace = 1623; // kDaikinBitMark * 4
const uint16_t kDaikinBitMark = 428;
const uint16_t kDaikinZeroSpace = 428;
const uint16_t kDaikinOneSpace = 1280;
const uint16_t kDaikinGap = 29000;
// Note bits in each octet swapped so can be sent as a single value
const uint64_t kDaikinFirstHeader64 =
0b1101011100000000000000001100010100000000001001111101101000010001;
// Legacy defines.
#define DAIKIN_COOL kDaikinCool
#define DAIKIN_HEAT kDaikinHeat
#define DAIKIN_FAN kDaikinFan
#define DAIKIN_AUTO kDaikinAuto
#define DAIKIN_DRY kDaikinDry
#define DAIKIN_MIN_TEMP kDaikinMinTemp
#define DAIKIN_MAX_TEMP kDaikinMaxTemp
#define DAIKIN_FAN_MIN kDaikinFanMin
#define DAIKIN_FAN_MAX kDaikinFanMax
#define DAIKIN_FAN_AUTO kDaikinFanAuto
#define DAIKIN_FAN_QUIET kDaikinFanQuiet
class IRDaikinESP {
public:
explicit IRDaikinESP(uint16_t pin);
#if SEND_DAIKIN
void send();
#endif
void begin();
void on();
void off();
void setPower(bool state);
bool getPower();
void setTemp(uint8_t temp);
uint8_t getTemp();
void setFan(uint8_t fan);
uint8_t getFan();
uint8_t getMode();
void setMode(uint8_t mode);
void setSwingVertical(bool state);
bool getSwingVertical();
void setSwingHorizontal(bool state);
bool getSwingHorizontal();
bool getQuiet();
void setQuiet(bool state);
bool getPowerful();
void setPowerful(bool state);
void setSensor(bool state);
bool getSensor();
void setEcono(bool state);
bool getEcono();
void setEye(bool state);
bool getEye();
void setMold(bool state);
bool getMold();
void enableOnTimer(uint16_t starttime);
void disableOnTimer();
uint16_t getOnTime();
bool getOnTimerEnabled();
void enableOffTimer(uint16_t endtime);
void disableOffTimer();
uint16_t getOffTime();
bool getOffTimerEnabled();
void setCurrentTime(uint16_t time);
uint16_t getCurrentTime();
uint8_t* getRaw();
void setRaw(uint8_t new_code[]);
#if DAIKIN_DEBUG
void printState();
#endif // DAIKIN_DEBUG
uint32_t getCommand();
void setCommand(uint32_t value);
static bool validChecksum(const uint8_t state[],
const uint16_t length = kDaikinStateLength);
#ifdef ARDUINO
String toString();
static String renderTime(uint16_t timemins);
#else
std::string toString();
static std::string renderTime(uint16_t timemins);
#endif
private:
// # of bytes per command
uint8_t daikin[kDaikinStateLength];
void stateReset();
static uint8_t calcBlockChecksum(const uint8_t* block, const uint16_t length);
void checksum();
void setBit(uint8_t byte, uint8_t bitmask);
void clearBit(uint8_t byte, uint8_t bitmask);
uint8_t getBit(uint8_t byte, uint8_t bitmask);
IRsend _irsend;
};
#endif // IR_DAIKIN_H_

View File

@ -1,127 +0,0 @@
// Copyright 2017 stufisher
#include "ir_Trotec.h"
#include "IRremoteESP8266.h"
#include "IRutils.h"
// Constants
const uint16_t kTrotecHdrMark = 5952;
const uint16_t kTrotecHdrSpace = 7364;
const uint16_t kTrotecOneMark = 592;
const uint16_t kTrotecOneSpace = 1560;
const uint16_t kTrotecZeroMark = 592;
const uint16_t kTrotecZeroSpace = 592;
const uint16_t kTrotecGap = 6184;
const uint16_t kTrotecGapEnd = 1500; // made up value
#if SEND_TROTEC
void IRsend::sendTrotec(unsigned char data[], uint16_t nbytes,
uint16_t repeat) {
if (nbytes < kTrotecStateLength) return;
for (uint16_t r = 0; r <= repeat; r++) {
sendGeneric(kTrotecHdrMark, kTrotecHdrSpace, kTrotecOneMark,
kTrotecOneSpace, kTrotecZeroMark, kTrotecZeroSpace,
kTrotecOneMark, kTrotecGap, data, nbytes, 36, false,
0, // Repeats handled elsewhere
50);
// More footer
enableIROut(36);
mark(kTrotecOneMark);
space(kTrotecGapEnd);
}
}
#endif // SEND_TROTEC
IRTrotecESP::IRTrotecESP(uint16_t pin) : _irsend(pin) { stateReset(); }
void IRTrotecESP::begin() { _irsend.begin(); }
#if SEND_TROTEC
void IRTrotecESP::send() {
checksum();
_irsend.sendTrotec(trotec);
}
#endif // SEND_TROTEC
void IRTrotecESP::checksum() {
uint8_t sum = 0;
uint8_t i;
for (i = 2; i < 8; i++) sum += trotec[i];
trotec[8] = sum & 0xFF;
}
void IRTrotecESP::stateReset() {
for (uint8_t i = 2; i < kTrotecStateLength; i++) trotec[i] = 0x0;
trotec[0] = kTrotecIntro1;
trotec[1] = kTrotecIntro2;
setPower(false);
setTemp(kTrotecDefTemp);
setSpeed(kTrotecFanMed);
setMode(kTrotecAuto);
}
uint8_t* IRTrotecESP::getRaw() {
checksum();
return trotec;
}
void IRTrotecESP::setPower(bool state) {
if (state)
trotec[2] |= (kTrotecOn << 3);
else
trotec[2] &= ~(kTrotecOn << 3);
}
uint8_t IRTrotecESP::getPower() { return trotec[2] & (kTrotecOn << 3); }
void IRTrotecESP::setSpeed(uint8_t speed) {
trotec[2] = (trotec[2] & 0xcf) | (speed << 4);
}
uint8_t IRTrotecESP::getSpeed() { return trotec[2] & 0x30; }
void IRTrotecESP::setMode(uint8_t mode) {
trotec[2] = (trotec[2] & 0xfc) | mode;
}
uint8_t IRTrotecESP::getMode() { return trotec[2] & 0x03; }
void IRTrotecESP::setTemp(uint8_t temp) {
if (temp < kTrotecMinTemp)
temp = kTrotecMinTemp;
else if (temp > kTrotecMaxTemp)
temp = kTrotecMaxTemp;
trotec[3] = (trotec[3] & 0x80) | (temp - kTrotecMinTemp);
}
uint8_t IRTrotecESP::getTemp() { return trotec[3] & 0x7f; }
void IRTrotecESP::setSleep(bool sleep) {
if (sleep)
trotec[3] |= (kTrotecSleepOn << 7);
else
trotec[3] &= ~(kTrotecSleepOn << 7);
}
bool IRTrotecESP::getSleep(void) { return trotec[3] & (kTrotecSleepOn << 7); }
void IRTrotecESP::setTimer(uint8_t timer) {
if (timer > kTrotecMaxTimer) timer = kTrotecMaxTimer;
if (timer) {
trotec[5] |= (kTrotecTimerOn << 6);
trotec[6] = timer;
} else {
trotec[5] &= ~(kTrotecTimerOn << 6);
trotec[6] = 0;
}
}
uint8_t IRTrotecESP::getTimer() { return trotec[6]; }

View File

@ -1,149 +0,0 @@
// Copyright 2018 David Conran
//
// Code to emulate Whirlpool protocol compatible devices.
// Should be compatible with:
// * SPIS409L, SPIS412L, SPIW409L, SPIW412L, SPIW418L
//
#include <algorithm>
#ifndef ARDUINO
#include <string>
#endif
#include "IRrecv.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "IRutils.h"
// WW WW HH HH IIIII RRRRRR LL PPPPPP OOOOO OOOOO LL
// WW WW HH HH III RR RR LL PP PP OO OO OO OO LL
// WW W WW HHHHHHH III RRRRRR LL PPPPPP OO OO OO OO LL
// WW WWW WW HH HH III RR RR LL PP OO OO OO OO LL
// WW WW HH HH IIIII RR RR LLLLLLL PP OOOO0 OOOO0 LLLLLLL
// Constants
// Ref: https://github.com/markszabo/IRremoteESP8266/issues/509
const uint16_t kWhirlpoolAcHdrMark = 8950;
const uint16_t kWhirlpoolAcHdrSpace = 4484;
const uint16_t kWhirlpoolAcBitMark = 597;
const uint16_t kWhirlpoolAcOneSpace = 1649;
const uint16_t kWhirlpoolAcZeroSpace = 533;
const uint16_t kWhirlpoolAcGap = 7920;
const uint32_t kWhirlpoolAcMinGap = 100000; // Completely made up value.
const uint8_t kWhirlpoolAcSections = 3;
#if SEND_WHIRLPOOL_AC
// Send a Whirlpool A/C message.
//
// Args:
// data: An array of bytes containing the IR command.
// nbytes: Nr. of bytes of data in the array. (>=kWhirlpoolAcStateLength)
// repeat: Nr. of times the message is to be repeated. (Default = 0).
//
// Status: ALPHA / Untested.
//
// Ref:
// https://github.com/markszabo/IRremoteESP8266/issues/509
void IRsend::sendWhirlpoolAC(unsigned char data[], uint16_t nbytes,
uint16_t repeat) {
if (nbytes < kWhirlpoolAcStateLength)
return; // Not enough bytes to send a proper message.
for (uint16_t r = 0; r <= repeat; r++) {
// Section 1
sendGeneric(kWhirlpoolAcHdrMark, kWhirlpoolAcHdrSpace, kWhirlpoolAcBitMark,
kWhirlpoolAcOneSpace, kWhirlpoolAcBitMark,
kWhirlpoolAcZeroSpace, kWhirlpoolAcBitMark, kWhirlpoolAcGap,
data, 6, // 6 bytes == 48 bits
38000, // Complete guess of the modulation frequency.
false, 0, 50);
// Section 2
sendGeneric(0, 0, kWhirlpoolAcBitMark, kWhirlpoolAcOneSpace,
kWhirlpoolAcBitMark, kWhirlpoolAcZeroSpace, kWhirlpoolAcBitMark,
kWhirlpoolAcGap, data + 6, 8, // 8 bytes == 64 bits
38000, // Complete guess of the modulation frequency.
false, 0, 50);
// Section 3
sendGeneric(0, 0, kWhirlpoolAcBitMark, kWhirlpoolAcOneSpace,
kWhirlpoolAcBitMark, kWhirlpoolAcZeroSpace, kWhirlpoolAcBitMark,
kWhirlpoolAcMinGap, data + 14, 7, // 7 bytes == 56 bits
38000, // Complete guess of the modulation frequency.
false, 0, 50);
}
}
#endif // SEND_WHIRLPOOL_AC
#if DECODE_WHIRLPOOL_AC
// Decode the supplied Whirlpool 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 kWhirlpoolAcBits
// 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.
//
//
// Ref:
// https://github.com/markszabo/IRremoteESP8266/issues/509
bool IRrecv::decodeWhirlpoolAC(decode_results *results, uint16_t nbits,
bool strict) {
if (results->rawlen < 2 * nbits + 4 + kHeader + kFooter - 1)
return false; // Can't possibly be a valid Whirlpool A/C message.
if (strict) {
if (nbits != kWhirlpoolAcBits) return false;
}
uint16_t offset = kStartOffset;
uint16_t dataBitsSoFar = 0;
uint16_t i = 0;
match_result_t data_result;
uint8_t sectionSize[kWhirlpoolAcSections] = {6, 8, 7};
// Header
if (!matchMark(results->rawbuf[offset++], kWhirlpoolAcHdrMark)) return false;
if (!matchSpace(results->rawbuf[offset++], kWhirlpoolAcHdrSpace))
return false;
// Data Section
// Keep reading bytes until we either run out of section or state to fill.
for (uint8_t section = 0, pos = 0; section < kWhirlpoolAcSections;
section++) {
pos += sectionSize[section];
for (; offset <= results->rawlen - 16 && i < pos;
i++, dataBitsSoFar += 8, offset += data_result.used) {
data_result =
matchData(&(results->rawbuf[offset]), 8, kWhirlpoolAcBitMark,
kWhirlpoolAcOneSpace, kWhirlpoolAcBitMark,
kWhirlpoolAcZeroSpace, kTolerance, kMarkExcess, false);
if (data_result.success == false) break; // Fail
// Data is in LSB order. We need to reverse it.
results->state[i] = (uint8_t)data_result.data;
}
// Section Footer
if (!matchMark(results->rawbuf[offset++], kWhirlpoolAcBitMark))
return false;
if (section < kWhirlpoolAcSections - 1) { // Inter-section gaps.
if (!matchSpace(results->rawbuf[offset++], kWhirlpoolAcGap)) return false;
} else { // Last section / End of message gap.
if (offset <= results->rawlen &&
!matchAtLeast(results->rawbuf[offset++], kWhirlpoolAcGap))
return false;
}
}
// Compliance
if (strict) {
// Re-check we got the correct size/length due to the way we read the data.
if (dataBitsSoFar != kWhirlpoolAcBits) return false;
}
// Success
results->decode_type = WHIRLPOOL_AC;
results->bits = dataBitsSoFar;
// 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 // WHIRLPOOL_AC

View File

@ -1,290 +0,0 @@
// Copyright 2017 David Conran
#include "IRsend_test.h"
#include "IRsend.h"
#include "gtest/gtest.h"
// Tests sendData().
// Test sending zero bits.
TEST(TestSendData, SendZeroBits) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0b1, 0, true);
EXPECT_EQ("", irsend.outputStr());
}
// Test sending zero and one.
TEST(TestSendData, SendSingleBit) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
EXPECT_EQ("m1s2", irsend.outputStr());
irsend.sendData(1, 2, 3, 4, 0b0, 1, true);
EXPECT_EQ("m3s4", irsend.outputStr());
}
// Test sending bit order.
TEST(TestSendData, TestingBitSendOrder) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0b10, 2, true);
EXPECT_EQ("m1s2m3s4", irsend.outputStr());
irsend.sendData(1, 2, 3, 4, 0b10, 2, false);
EXPECT_EQ("m3s4m1s2", irsend.outputStr());
irsend.sendData(1, 2, 3, 4, 0b0001, 4, false);
EXPECT_EQ("m1s2m3s4m3s4m3s4", irsend.outputStr());
}
// Test sending typical data.
TEST(TestSendData, SendTypicalData) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0b1010110011110000, 16, true);
EXPECT_EQ("m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4m3s4",
irsend.outputStr());
irsend.sendData(1, 2, 3, 4, 0x1234567890ABCDEF, 64, true);
EXPECT_EQ(
"m3s4m3s4m3s4m1s2m3s4m3s4m1s2m3s4m3s4m3s4m1s2m1s2m3s4m1s2m3s4m3s4"
"m3s4m1s2m3s4m1s2m3s4m1s2m1s2m3s4m3s4m1s2m1s2m1s2m1s2m3s4m3s4m3s4"
"m1s2m3s4m3s4m1s2m3s4m3s4m3s4m3s4m1s2m3s4m1s2m3s4m1s2m3s4m1s2m1s2"
"m1s2m1s2m3s4m3s4m1s2m1s2m3s4m1s2m1s2m1s2m1s2m3s4m1s2m1s2m1s2m1s2",
irsend.outputStr());
}
// Test sending more than expected bits.
TEST(TestSendData, SendOverLargeData) {
IRsendTest irsend(4);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0xFFFFFFFFFFFFFFFF, 70, true);
EXPECT_EQ(
"m3s4m3s4m3s4m3s4m3s4m3s4"
"m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
"m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
"m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2"
"m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2m1s2",
irsend.outputStr());
}
// Test inverting the output.
TEST(TestIRSend, InvertedOutput) {
IRsendTest irsend(4, true);
irsend.begin();
irsend.sendData(1, 2, 3, 4, 0b1, 1, true);
EXPECT_EQ("s1m2", irsend.outputStr());
irsend.sendData(1, 2, 3, 4, 0b0, 1, true);
EXPECT_EQ("s3m4", irsend.outputStr());
}
// Test typical use of sendRaw().
TEST(TestSendRaw, GeneralUse) {
IRsendTest irsend(4);
IRrecv irrecv(0);
irsend.begin();
// NEC C3E0E0E8 as measured in #204
uint16_t rawData[67] = {
8950, 4500, 550, 1650, 600, 1650, 550, 550, 600, 500, 600, 550,
550, 550, 600, 1650, 550, 1650, 600, 1650, 600, 1650, 550, 1700,
550, 550, 600, 550, 550, 550, 600, 500, 600, 550, 550, 1650,
600, 1650, 600, 1650, 550, 550, 600, 500, 600, 500, 600, 550,
550, 550, 600, 1650, 550, 1650, 600, 1650, 600, 500, 650, 1600,
600, 500, 600, 550, 550, 550, 600};
irsend.sendRaw(rawData, 67, 38);
EXPECT_EQ(
"m8950s4500"
"m550s1650m600s1650m550s550m600s500m600s550m550s550m600s1650m550s1650"
"m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550"
"m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550"
"m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550"
"m600",
irsend.outputStr());
irsend.reset();
irsend.sendRaw(rawData, 67, 38);
irsend.makeDecodeResult();
ASSERT_TRUE(irrecv.decodeNEC(&irsend.capture, kNECBits, false));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(32, irsend.capture.bits);
EXPECT_EQ(0xC3E0E0E8, irsend.capture.value);
EXPECT_EQ(
"m8950s4500"
"m550s1650m600s1650m550s550m600s500m600s550m550s550m600s1650m550s1650"
"m600s1650m600s1650m550s1700m550s550m600s550m550s550m600s500m600s550"
"m550s1650m600s1650m600s1650m550s550m600s500m600s500m600s550m550s550"
"m600s1650m550s1650m600s1650m600s500m650s1600m600s500m600s550m550s550"
"m600",
irsend.outputStr());
}
// Incorrect handling of decodes from Raw. i.e. There is no gap recorded at
// the end of a command when using the interrupt code. sendRaw() best emulates
// this for unit testing purposes. sendGC() and sendXXX() will add the trailing
// gap. Users won't see this in normal use.
TEST(TestSendRaw, NoTrailingGap) {
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
irsend.reset();
uint16_t rawData[67] = {
9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550, 600, 1650,
650, 550, 600, 1650, 650, 1650, 650, 1650, 600, 550, 650, 1650,
650, 1650, 650, 550, 600, 1650, 650, 1650, 650, 550, 650, 550,
650, 1650, 650, 550, 650, 550, 650, 550, 600, 550, 650, 550,
650, 550, 650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650,
650, 1650, 650, 1650, 650, 1650, 600};
irsend.sendRaw(rawData, 67, 38);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decodeNEC(&irsend.capture));
EXPECT_EQ(NEC, irsend.capture.decode_type);
EXPECT_EQ(kNECBits, irsend.capture.bits);
}
TEST(TestLowLevelSend, MarkFrequencyModulationAt38kHz) {
IRsendLowLevelTest irsend(0);
irsend.begin();
irsend.reset();
irsend.enableIROut(38000, 50);
EXPECT_EQ(5, irsend.mark(100));
EXPECT_EQ(
"[On]10usecs[Off]11usecs[On]10usecs[Off]11usecs[On]10usecs[Off]11usecs"
"[On]10usecs[Off]11usecs[On]10usecs[Off]6usecs",
irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(38000, 33);
EXPECT_EQ(5, irsend.mark(100));
EXPECT_EQ(
"[On]6usecs[Off]15usecs[On]6usecs[Off]15usecs[On]6usecs[Off]15usecs"
"[On]6usecs[Off]15usecs[On]6usecs[Off]10usecs",
irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(38000, 100);
EXPECT_EQ(1, irsend.mark(1000));
EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
}
TEST(TestLowLevelSend, MarkFrequencyModulationAt36_7kHz) {
IRsendLowLevelTest irsend(0);
irsend.begin();
irsend.reset();
irsend.enableIROut(36700, 50);
EXPECT_EQ(5, irsend.mark(100));
EXPECT_EQ(
"[On]11usecs[Off]11usecs[On]11usecs[Off]11usecs[On]11usecs[Off]11usecs"
"[On]11usecs[Off]11usecs[On]11usecs[Off]1usecs",
irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(36700, 33);
EXPECT_EQ(5, irsend.mark(100));
EXPECT_EQ(
"[On]7usecs[Off]15usecs[On]7usecs[Off]15usecs[On]7usecs[Off]15usecs"
"[On]7usecs[Off]15usecs[On]7usecs[Off]5usecs",
irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(36700, 100);
EXPECT_EQ(1, irsend.mark(1000));
EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
}
TEST(TestLowLevelSend, MarkFrequencyModulationAt40kHz) {
IRsendLowLevelTest irsend(0);
irsend.begin();
irsend.reset();
irsend.enableIROut(40000, 50);
EXPECT_EQ(5, irsend.mark(100));
EXPECT_EQ(
"[On]10usecs[Off]10usecs[On]10usecs[Off]10usecs[On]10usecs[Off]10usecs"
"[On]10usecs[Off]10usecs[On]10usecs[Off]10usecs",
irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(40000, 33);
EXPECT_EQ(5, irsend.mark(100));
EXPECT_EQ(
"[On]6usecs[Off]14usecs[On]6usecs[Off]14usecs[On]6usecs[Off]14usecs"
"[On]6usecs[Off]14usecs[On]6usecs[Off]14usecs",
irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(40000, 100);
EXPECT_EQ(1, irsend.mark(1000));
EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
}
TEST(TestLowLevelSend, MarkNoModulation) {
IRsendLowLevelTest irsend(0, false, false);
irsend.begin();
irsend.reset();
irsend.enableIROut(38000, 50);
EXPECT_EQ(1, irsend.mark(1000));
EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(36700, 25);
EXPECT_EQ(1, irsend.mark(1000));
EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(40000, 75);
EXPECT_EQ(1, irsend.mark(1000));
EXPECT_EQ("[On]1000usecs[Off]", irsend.low_level_sequence);
}
TEST(TestLowLevelSend, SpaceFrequencyModulation) {
IRsendLowLevelTest irsend(0);
irsend.reset();
irsend.enableIROut(38000);
irsend.space(1000);
EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(40000, 75);
irsend.space(1000);
EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(38000, 100);
irsend.space(1000);
EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(38000, 33);
irsend.space(1000);
EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
}
TEST(TestLowLevelSend, SpaceNoModulation) {
IRsendLowLevelTest irsend(0, false, false);
irsend.begin();
irsend.reset();
irsend.enableIROut(38000, 50);
irsend.space(1000);
EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(36700, 25);
irsend.space(1000);
EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
irsend.reset();
irsend.enableIROut(40000, 75);
irsend.space(1000);
EXPECT_EQ("[Off]1000usecs", irsend.low_level_sequence);
}

View File

@ -1,838 +0,0 @@
// Copyright 2017 David Conran
#include "ir_Daikin.h"
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for sendDaikin().
// Test sending typical data only.
TEST(TestSendDaikin, SendDataOnly) {
IRsendTest irsend(4);
irsend.begin();
uint8_t daikin_code[kDaikinStateLength] = {
0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11,
0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3};
irsend.reset();
irsend.sendDaikin(daikin_code);
EXPECT_EQ(
"m428s428m428s428m428s428m428s428m428s428"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
"m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
"m428s29428",
irsend.outputStr());
}
// Test sending with repeats.
TEST(TestSendDaikin, SendWithRepeats) {
IRsendTest irsend(4);
irsend.begin();
irsend.reset();
uint8_t daikin_code[kDaikinStateLength] = {
0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11,
0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3};
irsend.reset();
irsend.sendDaikin(daikin_code, kDaikinStateLength, 1);
EXPECT_EQ(
"m428s428m428s428m428s428m428s428m428s428"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
"m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
"m428s29428"
"m428s428m428s428m428s428m428s428m428s428"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
"m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
"m428s29428",
irsend.outputStr());
}
// Test sending atypical sizes.
TEST(TestSendDaikin, SendUnexpectedSizes) {
IRsendTest irsend(4);
irsend.begin();
uint8_t daikin_short_code[kDaikinStateLength - 1] = {
0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11,
0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00};
irsend.reset();
irsend.sendDaikin(daikin_short_code, kDaikinStateLength - 1);
ASSERT_EQ("", irsend.outputStr());
uint8_t daikin_long_code[kDaikinStateLength + 1] = {
0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x20, 0x11, 0xDA,
0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE3, 0x11};
irsend.reset();
irsend.sendDaikin(daikin_long_code, kDaikinStateLength + 1);
ASSERT_EQ(
"m428s428m428s428m428s428m428s428m428s428"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s1280m428s428m428s428"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s428m428s428m428s428m428s428m428s1280m428s428"
"m428s428m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s428m428s428m428s428m428s1280m428s1280m428s1280"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s29428",
irsend.outputStr());
}
// Tests for IRDaikinESP class.
TEST(TestDaikinClass, Power) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.on();
EXPECT_TRUE(irdaikin.getPower());
irdaikin.off();
EXPECT_FALSE(irdaikin.getPower());
irdaikin.setPower(true);
EXPECT_TRUE(irdaikin.getPower());
irdaikin.setPower(false);
EXPECT_FALSE(irdaikin.getPower());
}
TEST(TestDaikinClass, Temperature) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setTemp(0);
EXPECT_EQ(kDaikinMinTemp, irdaikin.getTemp());
irdaikin.setTemp(255);
EXPECT_EQ(kDaikinMaxTemp, irdaikin.getTemp());
irdaikin.setTemp(kDaikinMinTemp);
EXPECT_EQ(kDaikinMinTemp, irdaikin.getTemp());
irdaikin.setTemp(kDaikinMaxTemp);
EXPECT_EQ(kDaikinMaxTemp, irdaikin.getTemp());
irdaikin.setTemp(kDaikinMinTemp - 1);
EXPECT_EQ(kDaikinMinTemp, irdaikin.getTemp());
irdaikin.setTemp(kDaikinMaxTemp + 1);
EXPECT_EQ(kDaikinMaxTemp, irdaikin.getTemp());
irdaikin.setTemp(kDaikinMinTemp + 1);
EXPECT_EQ(kDaikinMinTemp + 1, irdaikin.getTemp());
irdaikin.setTemp(21);
EXPECT_EQ(21, irdaikin.getTemp());
irdaikin.setTemp(25);
EXPECT_EQ(25, irdaikin.getTemp());
irdaikin.setTemp(29);
EXPECT_EQ(29, irdaikin.getTemp());
}
TEST(TestDaikinClass, OperatingMode) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setMode(kDaikinAuto);
EXPECT_EQ(kDaikinAuto, irdaikin.getMode());
irdaikin.setMode(kDaikinCool);
EXPECT_EQ(kDaikinCool, irdaikin.getMode());
irdaikin.setMode(kDaikinHeat);
EXPECT_EQ(kDaikinHeat, irdaikin.getMode());
irdaikin.setMode(kDaikinDry);
EXPECT_EQ(kDaikinDry, irdaikin.getMode());
irdaikin.setMode(kDaikinFan);
EXPECT_EQ(kDaikinFan, irdaikin.getMode());
irdaikin.setMode(kDaikinFan + 1);
EXPECT_EQ(kDaikinAuto, irdaikin.getMode());
irdaikin.setMode(kDaikinAuto + 1);
EXPECT_EQ(kDaikinAuto, irdaikin.getMode());
irdaikin.setMode(255);
EXPECT_EQ(kDaikinAuto, irdaikin.getMode());
}
TEST(TestDaikinClass, VaneSwing) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setSwingHorizontal(true);
irdaikin.setSwingVertical(false);
irdaikin.setSwingHorizontal(true);
EXPECT_TRUE(irdaikin.getSwingHorizontal());
EXPECT_FALSE(irdaikin.getSwingVertical());
irdaikin.setSwingVertical(true);
EXPECT_TRUE(irdaikin.getSwingHorizontal());
EXPECT_TRUE(irdaikin.getSwingVertical());
irdaikin.setSwingHorizontal(false);
EXPECT_FALSE(irdaikin.getSwingHorizontal());
EXPECT_TRUE(irdaikin.getSwingVertical());
irdaikin.setSwingVertical(false);
EXPECT_FALSE(irdaikin.getSwingHorizontal());
EXPECT_FALSE(irdaikin.getSwingVertical());
}
TEST(TestDaikinClass, QuietMode) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setQuiet(true);
EXPECT_TRUE(irdaikin.getQuiet());
irdaikin.setQuiet(false);
EXPECT_FALSE(irdaikin.getQuiet());
irdaikin.setQuiet(true);
EXPECT_TRUE(irdaikin.getQuiet());
// Setting Econo mode should NOT change out of quiet mode.
irdaikin.setEcono(true);
EXPECT_TRUE(irdaikin.getQuiet());
irdaikin.setEcono(false);
EXPECT_TRUE(irdaikin.getQuiet());
// But setting Powerful mode should exit out of quiet mode.
irdaikin.setPowerful(true);
EXPECT_FALSE(irdaikin.getQuiet());
}
TEST(TestDaikinClass, PowerfulMode) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setPowerful(true);
EXPECT_TRUE(irdaikin.getPowerful());
irdaikin.setPowerful(false);
EXPECT_FALSE(irdaikin.getPowerful());
irdaikin.setPowerful(true);
EXPECT_TRUE(irdaikin.getPowerful());
irdaikin.setQuiet(true);
EXPECT_FALSE(irdaikin.getPowerful());
irdaikin.setPowerful(true);
irdaikin.setEcono(true);
EXPECT_FALSE(irdaikin.getPowerful());
}
TEST(TestDaikinClass, EconoMode) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setEcono(true);
EXPECT_TRUE(irdaikin.getEcono());
irdaikin.setEcono(false);
EXPECT_FALSE(irdaikin.getEcono());
irdaikin.setEcono(true);
EXPECT_TRUE(irdaikin.getEcono());
// Setting Quiet mode should NOT change out of Econo mode.
irdaikin.setQuiet(true);
EXPECT_TRUE(irdaikin.getEcono());
irdaikin.setQuiet(false);
EXPECT_TRUE(irdaikin.getEcono());
// But setting Powerful mode should exit out of Econo mode.
irdaikin.setPowerful(true);
EXPECT_FALSE(irdaikin.getEcono());
}
TEST(TestDaikinClass, FanSpeed) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
// Unexpected value should default to Auto.
irdaikin.setFan(0);
EXPECT_EQ(kDaikinFanAuto, irdaikin.getFan());
// Unexpected value should default to Auto.
irdaikin.setFan(255);
EXPECT_EQ(kDaikinFanAuto, irdaikin.getFan());
irdaikin.setFan(kDaikinFanMax);
EXPECT_EQ(kDaikinFanMax, irdaikin.getFan());
// Beyond Max should default to Auto.
irdaikin.setFan(kDaikinFanMax + 1);
EXPECT_EQ(kDaikinFanAuto, irdaikin.getFan());
irdaikin.setFan(kDaikinFanMax - 1);
EXPECT_EQ(kDaikinFanMax - 1, irdaikin.getFan());
irdaikin.setFan(kDaikinFanMin);
EXPECT_EQ(kDaikinFanMin, irdaikin.getFan());
irdaikin.setFan(kDaikinFanMin + 1);
EXPECT_EQ(kDaikinFanMin + 1, irdaikin.getFan());
// Beyond Min should default to Auto.
irdaikin.setFan(kDaikinFanMin - 1);
EXPECT_EQ(kDaikinFanAuto, irdaikin.getFan());
irdaikin.setFan(3);
EXPECT_EQ(3, irdaikin.getFan());
irdaikin.setFan(kDaikinFanAuto);
EXPECT_EQ(kDaikinFanAuto, irdaikin.getFan());
irdaikin.setFan(kDaikinFanQuiet);
EXPECT_EQ(kDaikinFanQuiet, irdaikin.getFan());
}
TEST(TestDaikinClass, CurrentTime) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setCurrentTime(0); // 00:00
EXPECT_EQ(0, irdaikin.getCurrentTime());
irdaikin.setCurrentTime(754); // 12:34
EXPECT_EQ(754, irdaikin.getCurrentTime());
irdaikin.setCurrentTime(1439); // 23:59
EXPECT_EQ(1439, irdaikin.getCurrentTime());
}
TEST(TestDaikinClass, OnOffTimers) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
// Both timers turned off.
irdaikin.disableOnTimer();
irdaikin.disableOffTimer();
EXPECT_FALSE(irdaikin.getOnTimerEnabled());
EXPECT_EQ(0x600, irdaikin.getOnTime());
EXPECT_FALSE(irdaikin.getOffTimerEnabled());
EXPECT_EQ(0x600, irdaikin.getOffTime());
// Turn on just the On Timer.
irdaikin.enableOnTimer(123);
EXPECT_TRUE(irdaikin.getOnTimerEnabled());
EXPECT_EQ(123, irdaikin.getOnTime());
EXPECT_FALSE(irdaikin.getOffTimerEnabled());
EXPECT_EQ(0x600, irdaikin.getOffTime());
// Now turn on the Off Timer.
irdaikin.enableOffTimer(754);
EXPECT_TRUE(irdaikin.getOffTimerEnabled());
EXPECT_EQ(754, irdaikin.getOffTime());
EXPECT_TRUE(irdaikin.getOnTimerEnabled());
EXPECT_EQ(123, irdaikin.getOnTime());
// Turn off the just the On Timer.
irdaikin.disableOnTimer();
EXPECT_FALSE(irdaikin.getOnTimerEnabled());
EXPECT_EQ(0x600, irdaikin.getOnTime());
EXPECT_TRUE(irdaikin.getOffTimerEnabled());
EXPECT_EQ(754, irdaikin.getOffTime());
// Now turn off the Off Timer.
irdaikin.disableOffTimer();
EXPECT_FALSE(irdaikin.getOffTimerEnabled());
EXPECT_EQ(0x600, irdaikin.getOffTime());
EXPECT_FALSE(irdaikin.getOnTimerEnabled());
EXPECT_EQ(0x600, irdaikin.getOnTime());
// Use some canary values around the timers to ensure no accidental
// bit flips happen. i.e. Neighbouring bytes in the state.
// (Found some during testing on systems with different endian-ness)
// Tests here to make sure it never happens again.
irdaikin.setSwingHorizontal(true);
irdaikin.setPowerful(true);
irdaikin.disableOffTimer();
irdaikin.disableOnTimer();
ASSERT_TRUE(irdaikin.getSwingHorizontal());
ASSERT_TRUE(irdaikin.getPowerful());
irdaikin.enableOnTimer(123);
irdaikin.enableOffTimer(456);
ASSERT_TRUE(irdaikin.getSwingHorizontal());
ASSERT_TRUE(irdaikin.getPowerful());
irdaikin.disableOffTimer();
irdaikin.disableOnTimer();
ASSERT_TRUE(irdaikin.getSwingHorizontal());
ASSERT_TRUE(irdaikin.getPowerful());
irdaikin.setSwingHorizontal(false);
irdaikin.setPowerful(false);
irdaikin.disableOffTimer();
irdaikin.disableOnTimer();
ASSERT_FALSE(irdaikin.getSwingHorizontal());
ASSERT_FALSE(irdaikin.getPowerful());
irdaikin.enableOnTimer(123);
irdaikin.enableOffTimer(456);
ASSERT_FALSE(irdaikin.getSwingHorizontal());
ASSERT_FALSE(irdaikin.getPowerful());
irdaikin.disableOffTimer();
irdaikin.disableOnTimer();
ASSERT_FALSE(irdaikin.getSwingHorizontal());
ASSERT_FALSE(irdaikin.getPowerful());
}
// Test Eye mode.
TEST(TestDaikinClass, EyeSetting) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
// The Eye setting is stored in the same byte as Econo mode.
// Econo mode tests are there to make sure it isn't harmed and vice-versa.
irdaikin.setEcono(false);
irdaikin.setEye(false);
ASSERT_FALSE(irdaikin.getEye());
EXPECT_FALSE(irdaikin.getEcono());
irdaikin.setEye(true);
ASSERT_TRUE(irdaikin.getEye());
EXPECT_FALSE(irdaikin.getEcono());
irdaikin.setEcono(false);
ASSERT_TRUE(irdaikin.getEye());
EXPECT_FALSE(irdaikin.getEcono());
irdaikin.setEcono(true);
ASSERT_TRUE(irdaikin.getEye());
EXPECT_TRUE(irdaikin.getEcono());
irdaikin.setEye(false);
ASSERT_FALSE(irdaikin.getEye());
EXPECT_TRUE(irdaikin.getEcono());
}
// Test Mold mode.
TEST(TestDaikinClass, MoldSetting) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setMold(false);
ASSERT_FALSE(irdaikin.getMold());
irdaikin.setMold(true);
ASSERT_TRUE(irdaikin.getMold());
irdaikin.setMold(false);
ASSERT_FALSE(irdaikin.getMold());
}
// Test Sensor mode.
TEST(TestDaikinClass, SensorSetting) {
IRDaikinESP irdaikin(0);
irdaikin.begin();
irdaikin.setSensor(false);
ASSERT_FALSE(irdaikin.getSensor());
irdaikin.setSensor(true);
ASSERT_TRUE(irdaikin.getSensor());
irdaikin.setSensor(false);
ASSERT_FALSE(irdaikin.getSensor());
}
TEST(TestDaikinClass, RenderTime) {
EXPECT_EQ("0:00", IRDaikinESP::renderTime(0));
EXPECT_EQ("0:10", IRDaikinESP::renderTime(10));
EXPECT_EQ("1:00", IRDaikinESP::renderTime(1 * 60 + 0));
EXPECT_EQ("23:59", IRDaikinESP::renderTime(23 * 60 + 59));
}
TEST(TestDaikinClass, SetAndGetRaw) {
IRDaikinESP irdaikin(0);
uint8_t initialState[kDaikinStateLength] = {
0x11, 0xDA, 0x27, 0x00, 0x42, 0x00, 0x00, 0x54, 0x11,
0xDA, 0x27, 0x00, 0x00, 0x49, 0x1E, 0x00, 0xB0, 0x00,
0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x4F};
uint8_t expectedState[kDaikinStateLength] = {
0x11, 0xDA, 0x27, 0x00, 0x42, 0x00, 0x00, 0x54, 0x11,
0xDA, 0x27, 0x00, 0x00, 0x48, 0x2A, 0x00, 0xB0, 0x00,
0x00, 0x06, 0x60, 0x00, 0x00, 0xC0, 0x00, 0x02, 0x5A};
EXPECT_STATE_EQ(initialState, irdaikin.getRaw(), kDaikinBits);
// toggle the power state.
irdaikin.setPower(!irdaikin.getPower());
irdaikin.setTemp(21);
irdaikin.setMold(true);
EXPECT_STATE_EQ(expectedState, irdaikin.getRaw(), kDaikinBits);
irdaikin.setRaw(initialState);
EXPECT_STATE_EQ(initialState, irdaikin.getRaw(), kDaikinBits);
}
TEST(TestDaikinClass, ChecksumValidation) {
uint8_t daikin_code[kDaikinStateLength] = {
0x11, 0xDA, 0x27, 0xF0, 0x00, 0x00, 0x00, 0x02, 0x11,
0xDA, 0x27, 0x00, 0x00, 0x41, 0x1E, 0x00, 0xB0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xE1};
EXPECT_TRUE(IRDaikinESP::validChecksum(daikin_code));
// Change the array so the checksum is invalid.
daikin_code[0] ^= 0xFF;
EXPECT_FALSE(IRDaikinESP::validChecksum(daikin_code));
// Restore the previous change, and change another byte.
daikin_code[0] ^= 0xFF;
daikin_code[4] ^= 0xFF;
EXPECT_FALSE(IRDaikinESP::validChecksum(daikin_code));
daikin_code[4] ^= 0xFF;
// Change something in the 2nd block.
daikin_code[10] ^= 0xFF;
EXPECT_FALSE(IRDaikinESP::validChecksum(daikin_code));
daikin_code[10] ^= 0xFF;
EXPECT_TRUE(IRDaikinESP::validChecksum(daikin_code));
}
// Test human readable output.
TEST(TestDaikinClass, HumanReadable) {
IRDaikinESP irdaikin(0);
EXPECT_EQ(
"Power: On, Mode: 4 (HEAT), Temp: 15C, Fan: 11 (QUIET), "
"Powerful: Off, Quiet: Off, Sensor: Off, Eye: Off, Mold: Off, "
"Swing (Horizontal): Off, Swing (Vertical): Off, "
"Current Time: 0:00, On Time: Off, Off Time: Off",
irdaikin.toString());
irdaikin.setMode(kDaikinAuto);
irdaikin.setTemp(25);
irdaikin.setFan(kDaikinFanAuto);
irdaikin.setQuiet(true);
irdaikin.setSensor(true);
irdaikin.setEye(true);
irdaikin.setMold(true);
irdaikin.setSwingVertical(true);
irdaikin.setSwingHorizontal(true);
irdaikin.setCurrentTime(9 * 60 + 15);
irdaikin.enableOnTimer(8 * 60 + 0);
irdaikin.enableOffTimer(17 * 60 + 30);
irdaikin.off();
EXPECT_EQ(
"Power: Off, Mode: 0 (AUTO), Temp: 25C, Fan: 10 (AUTO), "
"Powerful: Off, Quiet: On, Sensor: On, Eye: On, Mold: On, "
"Swing (Horizontal): On, Swing (Vertical): On, "
"Current Time: 9:15, On Time: 8:00, Off Time: 17:30",
irdaikin.toString());
}
// Test general message construction after tweaking some settings.
TEST(TestDaikinClass, MessageConstuction) {
IRDaikinESP irdaikin(0);
IRsendTest irsend(4);
irdaikin.begin();
irsend.begin();
irdaikin.setFan(kDaikinFanMin);
irdaikin.setMode(kDaikinCool);
irdaikin.setTemp(27);
irdaikin.setSwingVertical(false);
irdaikin.setSwingHorizontal(true);
irdaikin.setQuiet(false);
irdaikin.setPower(true);
// Check everything for kicks.
EXPECT_EQ(kDaikinFanMin, irdaikin.getFan());
EXPECT_EQ(kDaikinCool, irdaikin.getMode());
EXPECT_EQ(27, irdaikin.getTemp());
EXPECT_FALSE(irdaikin.getSwingVertical());
EXPECT_TRUE(irdaikin.getSwingHorizontal());
EXPECT_FALSE(irdaikin.getQuiet());
EXPECT_TRUE(irdaikin.getPower());
irsend.reset();
irsend.sendDaikin(irdaikin.getRaw());
EXPECT_EQ(
"m428s428m428s428m428s428m428s428m428s428"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s1280m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s1280m428s1280m428s428m428s1280m428s428m428s1280m428s1280"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s428m428s428m428s428m428s1280m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s1280m428s428m428s1280m428s428m428s1280m428s428"
"m428s29428m3650s1623"
"m428s1280m428s428m428s428m428s428m428s1280m428s428m428s428m428s428"
"m428s428m428s1280m428s428m428s1280m428s1280m428s428m428s1280m428s1280"
"m428s1280m428s1280m428s1280m428s428m428s428m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s1280m428s428m428s428m428s1280m428s1280m428s1280m428s428m428s428"
"m428s428m428s1280m428s1280m428s428m428s1280m428s1280m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428m428s428"
"m428s1280m428s1280m428s1280m428s1280m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s1280m428s1280m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s1280m428s1280"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s428m428s428m428s428m428s428m428s428m428s428m428s428"
"m428s428m428s1280m428s1280m428s428m428s428m428s1280m428s1280m428s1280"
"m428s29428",
irsend.outputStr());
}
// Tests for decodeDaikin().
// Test decoding a message captured from a real IR remote.
TEST(TestDecodeDaikin, RealExample) {
IRDaikinESP irdaikin(0);
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
uint8_t expectedState[kDaikinStateLength] = {
0x11, 0xDA, 0x27, 0x00, 0x42, 0x3A, 0x05, 0x93, 0x11,
0xDA, 0x27, 0x00, 0x00, 0x3F, 0x3A, 0x00, 0xA0, 0x00,
0x0A, 0x25, 0x17, 0x01, 0x00, 0xC0, 0x00, 0x00, 0x32};
uint16_t rawData[kDaikinRawBits] = {
416, 446, 416, 446, 416, 446, 418, 446, 416, 446, 416, 25434,
3436, 1768, 390, 1336, 390, 446, 416, 446, 416, 446, 416, 1336,
390, 446, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 448,
416, 1336, 390, 1336, 390, 448, 416, 1336, 390, 1336, 390, 1338,
388, 1338, 390, 1336, 390, 446, 416, 446, 416, 1336, 390, 446,
416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 448,
416, 446, 416, 446, 416, 446, 416, 1336, 390, 446, 416, 1336,
390, 448, 416, 446, 416, 446, 416, 1336, 390, 1336, 390, 446,
416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446,
416, 446, 416, 446, 416, 448, 416, 446, 416, 446, 416, 446,
416, 448, 414, 448, 416, 448, 416, 1336, 390, 1336, 390, 1336,
390, 446, 414, 1336, 390, 448, 414, 1336, 390, 1336, 390, 34878,
3436, 1768, 390, 1336, 390, 446, 416, 448, 416, 446, 416, 1336,
390, 446, 416, 448, 416, 446, 416, 446, 416, 1336, 390, 446,
416, 1336, 390, 1336, 390, 446, 416, 1336, 390, 1336, 390, 1336,
390, 1336, 390, 1336, 392, 446, 414, 448, 416, 1336, 390, 446,
416, 446, 416, 446, 416, 446, 414, 448, 416, 446, 416, 448,
414, 448, 416, 446, 416, 446, 416, 446, 414, 1336, 390, 448,
416, 446, 416, 446, 416, 448, 416, 1336, 390, 446, 416, 446,
416, 1336, 390, 446, 416, 1336, 390, 1336, 390, 1336, 390, 446,
416, 446, 414, 1338, 390, 446, 416, 1336, 390, 446, 416, 446,
416, 446, 416, 446, 416, 446, 416, 1336, 390, 1336, 390, 446,
416, 446, 416, 1336, 390, 446, 416, 446, 416, 1336, 390, 34876,
3436, 1768, 388, 1336, 390, 446, 416, 446, 416, 448, 416, 1336,
390, 446, 416, 446, 416, 446, 416, 448, 416, 1336, 390, 448,
414, 1336, 390, 1336, 390, 446, 416, 1336, 388, 1338, 388, 1336,
390, 1336, 390, 1336, 390, 446, 416, 446, 416, 1336, 390, 446,
420, 442, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446,
416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 448,
416, 446, 416, 448, 416, 446, 416, 448, 416, 446, 416, 1336,
390, 1336, 390, 1336, 388, 1338, 390, 1336, 390, 1336, 392, 446,
416, 446, 416, 448, 416, 1334, 390, 446, 416, 1338, 388, 1336,
390, 1336, 390, 446, 416, 446, 416, 448, 414, 446, 416, 446,
416, 446, 416, 448, 416, 446, 416, 446, 416, 446, 416, 446,
416, 446, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 446,
416, 1336, 390, 446, 414, 448, 416, 446, 416, 446, 416, 446,
416, 448, 416, 446, 416, 446, 416, 446, 416, 1336, 390, 446,
416, 1336, 390, 446, 416, 446, 416, 446, 416, 448, 416, 1338,
390, 444, 418, 1336, 390, 448, 416, 446, 416, 1336, 390, 446,
416, 446, 416, 1336, 390, 1336, 388, 1336, 390, 446, 416, 1336,
390, 448, 414, 448, 414, 448, 416, 1334, 390, 446, 416, 446,
416, 446, 416, 448, 416, 446, 416, 446, 416, 448, 416, 446,
416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446,
416, 446, 416, 446, 416, 446, 416, 446, 416, 446, 416, 446,
416, 448, 416, 1336, 390, 1336, 390, 446, 416, 446, 416, 446,
416, 446, 414, 446, 416, 448, 416, 446, 416, 448, 414, 446,
418, 446, 416, 446, 416, 448, 416, 446, 416, 448, 416, 446,
416, 448, 416, 446, 416, 1336, 390, 446, 416, 446, 416, 1338,
390, 1336, 390, 446, 416, 446, 416}; // Captured by @sillyfrog
irsend.reset();
irsend.sendRaw(rawData, kDaikinRawBits, 38000);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(DAIKIN, irsend.capture.decode_type);
ASSERT_EQ(kDaikinBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
}
// Decoding a message we entirely constructed based solely on a given state.
TEST(TestDecodeDaikin, SyntheticExample) {
IRDaikinESP irdaikin(0);
IRsendTest irsend(4);
IRrecv irrecv(4);
irsend.begin();
uint8_t expectedState[kDaikinStateLength] = {
0x11, 0xDA, 0x27, 0x00, 0x42, 0x3A, 0x05, 0x93, 0x11,
0xDA, 0x27, 0x00, 0x00, 0x3F, 0x3A, 0x00, 0xA0, 0x00,
0x0A, 0x25, 0x17, 0x01, 0x00, 0xC0, 0x00, 0x00, 0x32};
irsend.reset();
irsend.sendDaikin(expectedState);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decode(&irsend.capture));
ASSERT_EQ(DAIKIN, irsend.capture.decode_type);
ASSERT_EQ(kDaikinBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
}

View File

@ -1,118 +0,0 @@
// Copyright 2018 David Conran
#include "IRrecv.h"
#include "IRrecv_test.h"
#include "IRsend.h"
#include "IRsend_test.h"
#include "gtest/gtest.h"
// Tests for sendWhirlpoolAC().
// Test sending typical data only.
TEST(TestSendWhirlpoolAC, SendDataOnly) {
IRsendTest irsend(0);
irsend.begin();
uint8_t data[kWhirlpoolAcStateLength] = {
0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00,
0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
irsend.sendWhirlpoolAC(data);
EXPECT_EQ(
"m8950s4484"
"m597s1649m597s1649m597s533m597s533m597s533m597s533m597s533m597s1649"
"m597s533m597s1649m597s1649m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s533m597s533m597s533m597s1649m597s533m597s533m597s533"
"m597s1649m597s533m597s533m597s533m597s1649m597s1649m597s1649m597s533"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s7920"
"m597s1649m597s533m597s533m597s533m597s1649m597s533m597s533m597s1649"
"m597s1649m597s1649m597s1649m597s1649m597s1649m597s533m597s533m597s533"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s1649m597s1649m597s1649m597s1649m597s533m597s1649m597s1649m597s1649"
"m597s7920"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s1649m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s533m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s533m597s1649m597s533m597s533m597s533m597s533m597s533m597s533"
"m597s100000",
irsend.outputStr());
}
// Tests for decodeWhirlpoolAC().
// Decode normal WhirlpoolAC messages.
TEST(TestDecodeWhirlpoolAC, SyntheticDecode) {
IRsendTest irsend(0);
IRrecv irrecv(0);
irsend.begin();
// Synthesised Normal WhirlpoolAC message.
irsend.reset();
uint8_t expectedState[kWhirlpoolAcStateLength] = {
0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00,
0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
irsend.sendWhirlpoolAC(expectedState);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(WHIRLPOOL_AC, irsend.capture.decode_type);
EXPECT_EQ(kWhirlpoolAcBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
}
// Decode a recorded example
TEST(TestDecodeWhirlpoolAC, RealExampleDecode) {
IRsendTest irsend(0);
IRrecv irrecv(0);
irsend.begin();
// Real WhirlpoolAC message.
// Ref: https://github.com/markszabo/IRremoteESP8266/issues/509
uint16_t rawData[343] = {
8950, 4484, 598, 1642, 598, 1646, 594, 534, 594, 538, 602, 532,
598, 540, 600, 542, 598, 1650, 600, 522, 598, 1644, 596, 1650,
600, 532, 598, 538, 602, 536, 594, 548, 592, 538, 602, 518,
600, 524, 596, 532, 598, 532, 598, 1654, 596, 544, 596, 544,
596, 536, 594, 1644, 596, 528, 600, 528, 592, 538, 602, 1648,
602, 1654, 596, 1664, 598, 534, 594, 526, 594, 530, 598, 528,
602, 530, 600, 534, 596, 542, 598, 542, 598, 534, 596, 526,
594, 530, 600, 528, 602, 530, 600, 534, 596, 542, 598, 544,
596, 518, 602, 7916, 598, 1642, 598, 528, 600, 528, 602, 530,
600, 1652, 598, 542, 598, 544, 596, 1654, 596, 1644, 596, 1648,
602, 1644, 596, 1654, 596, 1656, 604, 536, 594, 548, 602, 528,
600, 520, 600, 524, 596, 532, 598, 532, 596, 538, 602, 536,
594, 546, 594, 538, 602, 518, 600, 524, 596, 532, 598, 532,
598, 536, 594, 544, 596, 544, 596, 536, 594, 526, 592, 530,
600, 528, 600, 530, 602, 532, 596, 542, 598, 542, 598, 534,
596, 524, 596, 528, 600, 526, 592, 538, 592, 542, 598, 540,
600, 540, 600, 530, 598, 522, 598, 526, 594, 534, 596, 534,
594, 540, 602, 536, 592, 548, 592, 538, 600, 1636, 594, 1648,
602, 1642, 598, 1652, 598, 538, 602, 1680, 570, 1662, 598, 1634,
596, 7924, 600, 520, 598, 526, 592, 534, 596, 534, 596, 540,
600, 536, 604, 538, 602, 530, 600, 520, 598, 1640, 600, 528,
600, 530, 600, 534, 594, 544, 596, 544, 596, 534, 596, 526,
594, 528, 600, 526, 594, 536, 592, 542, 598, 538, 602, 538,
602, 528, 600, 520, 600, 524, 596, 530, 600, 532, 598, 534,
596, 542, 598, 542, 598, 532, 598, 524, 596, 528, 602, 526,
594, 536, 594, 540, 600, 536, 594, 548, 592, 538, 602, 518,
602, 522, 596, 530, 600, 530, 600, 534, 596, 542, 598, 544,
596, 534, 596, 524, 594, 1644, 596, 532, 596, 534, 596, 538,
602, 536, 594, 546, 594, 520, 600};
uint8_t expectedState[kWhirlpoolAcStateLength] = {
0x83, 0x06, 0x10, 0x71, 0x00, 0x00, 0x91, 0x1F, 0x00, 0x00, 0x00,
0x00, 0x00, 0xEF, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02};
irsend.reset();
irsend.sendRaw(rawData, 343, 38000);
irsend.makeDecodeResult();
EXPECT_TRUE(irrecv.decode(&irsend.capture));
EXPECT_EQ(WHIRLPOOL_AC, irsend.capture.decode_type);
EXPECT_EQ(kWhirlpoolAcBits, irsend.capture.bits);
EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits);
}

View File

@ -12,7 +12,9 @@
- [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/markszabo/IRremoteESP8266/graphs/contributors).
All contributors can be found on the [contributors site](https://github.com/markszabo/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,20 +1,21 @@
language: c
env:
- BD=esp8266:esp8266:nodemcuv2:CpuFrequency=80,FlashSize=4M3M
- BD=esp8266:esp8266:d1_mini:CpuFrequency=80,FlashSize=4M3M
- 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.2-linux64.tar.xz
- tar xf arduino-1.8.2-linux64.tar.xz
- sudo mv arduino-1.8.2 /usr/local/share/arduino
- 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
@ -40,6 +41,10 @@ script:
- arduino --verify --board $BD $PWD/examples/TurnOnArgoAC/TurnOnArgoAC.ino
- arduino --verify --board $BD $PWD/examples/IRMQTTServer/IRMQTTServer.ino
- arduino --verify --board $BD $PWD/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino
- arduino --verify --board $BD $PWD/examples/ControlSamsungAC/ControlSamsungAC.ino
- arduino --verify --board $BD $PWD/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino
- arduino --verify --board $BD $PWD/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino
# Also check the tools programs compile.
- (cd tools; make all)
# Check for lint issues.

View File

@ -1,14 +1,15 @@
# IRremote ESP8266 Library
[![Build Status](https://travis-ci.org/markszabo/IRremoteESP8266.svg?branch=master)](https://travis-ci.org/markszabo/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/markszabo/IRremoteESP8266.svg)](http://isitmaintained.com/project/markszabo/IRremoteESP8266 "Average time to resolve an issue")
[![Percentage of issues still open](http://isitmaintained.com/badge/open/markszabo/IRremoteESP8266.svg)](http://isitmaintained.com/project/markszabo/IRremoteESP8266 "Percentage of issues still open")
[![GitLicense](https://gitlicense.com/badge/markszabo/IRremoteESP8266)](https://gitlicense.com/license/markszabo/IRremoteESP8266)
This library enables you to **send _and_ receive** infra-red signals on an [ESP8266 using the Arduino framework](https://github.com/esp8266/Arduino) using common 940nm IR LEDs and common IR receiver modules. e.g. TSOP{17,22,24,36,38,44,48}* etc.
## v2.5.2 Now Available
Version 2.5.2 of the library is now [available](https://github.com/markszabo/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes.
## v2.6.0 Now Available
Version 2.6.0 of the library is now [available](https://github.com/markszabo/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/markszabo/IRremoteESP8266/wiki/Upgrading-to-v2.0) page.

View File

@ -1,5 +1,107 @@
# Release Notes
## _v2.6.0 (20190430)_
**[Bug Fixes]**
- Fixed problem where LG protocol used wrong duty cycle for repeat. (#687)
- Fix checksum calculation for Daikin protocols. (#678)
- Fix the byte array version of sendGree() (#684, #685)
- Fix artificial vs. real state creation on HaierAC. (#668, #671)
- Fix issues caused by having `MQTT_ENABLE` set to false. (#677)
- Fix compile problem when DEBUG is defined. (#673, #674)
- Fix Minor bug with MQTT_ENABLE False condition (#654)
**[Features]**
- Experimental support for DAIKIN216 (ARC433B69) (#690)
- Experimental support for Mitsubishi Heavy Industries A/Cs. (#660, #665, #667)
- Support more features of TCL A/C (#656)
- Add LEGO(TM) Power Functions IR protocol. (#655)
- Add Panasonic AC RKR model & Example (#649)
- DAIKIN/IRDaikinESP overhaul and add Comfort mode support. (#678)
**WARNING**: Previous `sendDaikin()` calls may not work.
Please recapture codes or use `kDaikinStateLengthShort` for
`nbytes` in those calls.
- IRMQTTServer: Move MQTT server and other parameters to WifiManager. (#680)
**WARNING**: Previous users may need to fully wipe/reset the
SPIFFS/WifiManager settings by visiting
`http://<your_esp8266's_ip_address>/reset` prior to or
after update.
- Add Wifi filtering options to IRMQTTServer. (#679)
- Add advanced aircon/climate functionality to IRMQTTServer (#677)
- Initial prototype of a common interface for all A/Cs. (#664)
- Improve MQTT topic usage for feedback messages. (#663)
- Add multiple independent GPIO sending support via MQTT. (#661)
**[Misc]**
- Adjust kGreeHdrSpace to 4500 (#684, #686)
- Add Home Assistant mqtt climate instructions. (#682)
- Implement htmlEscape() to prevent XSS etc. (#681)
- Add F() Macros (#670)
- Update Daikin2's Cool mode min temp to 18C (#658)
- Change per byte bit-order in Electra protocol. (#648)
- Improve Daikin2 power on/off. (#647)
## _v2.5.6 (20190316)_
**[Bug Fixes]**
- Fix Coolix A/C Class to handle special states better. (#633, #624)
**[Features]**
- Fix case style for recent A/C protocols. (#631)
- Update `IRsend::send()` to include all simple protocols. (#629, #628)
- Experimental basic support for 112 bit TCL AC messages (#627, #619)
- Add support for TECO AC (#622)
- Experimental support for Samsung 36 bit protocol (#625, #621)
**[Misc]**
- Set Coolix to default to 1 repeat. (#637, #636, #624, #439)
- Set Daikin2 modulation to 36.7kHz. (#635)
- Refactor IRVestelAC class to use portable code. (#617)
- Adjust Daikin2 timings and tolerance. (#616, #582)
## _v2.5.5 (20190207)_
**[Bug Fixes]**
- Fix decoding of Samsung A/C Extended messages. (#610)
- Fix IRMQTTServer example to work with GPIO0 as IR_RX (#608)
- Fix incorrect #define usage. (#597, #596)
**[Features]**
- Add deep decoding/construction of Daikin2 messages (#600)
- Added Old Vestel A/C support (56 Bits) with full functions. (#607)
**[Misc]**
- Add ControlSamsungAC example code. (#599)
- Add how to send a state/air-con to IRsendDemo.ino (#594)
## _v2.5.4 (20190102)_
**[Features]**
- Experimental basic support for 39 Byte Daikin A/C (#583)
- Handle send() repeats in A/C classes. Improve Coolix support. (#580)
- Add optional RX pin pullup and dump raw messages in IRMQTTServer.ino (#589)
**[Misc]**
- Make auto_analyse_raw_data.py work with Python3 (#581)
- Update CI/travis config due to esp8266 core 2.5.0 changes (#591)
## _v2.5.3 (20181123)_
**[Features]**
- Add deep support for the Hitachi 28-Byte A/C Protocol (#563)
- Deep decoding for Whirlpool A/C (#572)
- Improve security options for IRMQTTServer example. (#575)
- Require a changed firmware password before upload. (#576)
**[Misc]**
- Add missing '}' in output of Auto analyse. (#562)
- Make A/C example code a bit more simple. (#571)
## _v2.5.2 (20181021)_
**[Bug Fixes]**

View File

@ -0,0 +1,99 @@
/* Copyright 2019 David Conran
*
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
* as specified by kIrLed below.
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_Samsung.h>
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
IRSamsungAc ac(kIrLed); // Set the GPIO used for sending messages.
void printState() {
// Display the settings.
Serial.println("Samsung A/C remote is in the following state:");
Serial.printf(" %s\n", ac.toString().c_str());
}
void setup() {
ac.begin();
Serial.begin(115200);
delay(200);
// Set up what we want to send. See ir_Samsung.cpp for all the options.
Serial.println("Default state of the remote.");
printState();
Serial.println("Setting initial state for A/C.");
ac.off();
ac.setFan(kSamsungAcFanLow);
ac.setMode(kSamsungAcCool);
ac.setTemp(25);
ac.setSwing(false);
printState();
}
void loop() {
// Turn the A/C unit on and set to cooling mode.
// Power changes require we send an extended message.
Serial.println("Sending an extended IR command to A/C ...");
ac.on();
ac.setMode(kSamsungAcCool);
ac.sendExtended();
printState();
delay(15000); // wait 15 seconds
// Increase the fan speed.
Serial.println("Sending a normal IR command to A/C ...");
ac.setFan(kSamsungAcFanHigh);
ac.send();
printState();
delay(15000);
// Change to swing the fan.
Serial.println("Sending a normal IR command to A/C ...");
ac.setSwing(true);
ac.send();
printState();
delay(15000);
// Change to Fan mode, lower the speed, and stop the swing.
Serial.println("Sending a normal IR command to A/C ...");
ac.setSwing(false);
ac.setMode(kSamsungAcFan);
ac.setFan(kSamsungAcFanLow);
ac.send();
printState();
delay(15000);
// Turn the A/C unit off.
// Power changes require we send an extended message.
Serial.println("Sending an extended IR command to A/C ...");
ac.off();
ac.sendExtended();
printState();
delay(15000); // wait 15 seconds
}

View File

@ -6,11 +6,13 @@ src_dir=.
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}

View File

@ -6,11 +6,13 @@ src_dir=.
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}

View File

@ -6,11 +6,13 @@ src_dir=.
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}

View File

@ -0,0 +1,258 @@
/*
* Send & receive arbitrary IR codes via a web server or MQTT.
* Copyright David Conran 2016, 2017, 2018, 2019
*/
#ifndef EXAMPLES_IRMQTTSERVER_IRMQTTSERVER_H_
#define EXAMPLES_IRMQTTSERVER_IRMQTTSERVER_H_
#include <IRremoteESP8266.h>
#include <IRrecv.h>
#include <IRsend.h>
#include <IRtimer.h>
#include <IRutils.h>
#include <IRac.h>
// ---------------- Start of User Configuration Section ------------------------
#ifndef MQTT_ENABLE
#define MQTT_ENABLE true // Whether or not MQTT is used at all.
#endif // MQTT_ENABLE
// ---------------------- Board Related Settings -------------------------------
// NOTE: Make sure you set your Serial Monitor to the same speed.
#define BAUD_RATE 115200 // Serial port Baud rate.
// GPIO the IR LED is connected to/controlled by. GPIO 4 = D2.
#define IR_LED 4 // <=- CHANGE_ME (optional)
// define IR_LED 3 // For an ESP-01 we suggest you use RX/GPIO3/Pin 7.
// GPIO the IR RX module is connected to/controlled by. e.g. GPIO 14 = D5.
// Comment this out to disable receiving/decoding IR messages entirely.
#define IR_RX 14 // <=- CHANGE_ME (optional)
#define IR_RX_PULLUP false
// --------------------- Network Related Settings ------------------------------
const uint16_t kHttpPort = 80; // The TCP port the HTTP server is listening on.
// Change to 'true'/'false' if you do/don't want these features or functions.
#define USE_STATIC_IP false // Change to 'true' if you don't want to use DHCP.
// We obtain our network config via DHCP by default but allow an easy way to
// use a static IP config.
#if USE_STATIC_IP
const IPAddress kIPAddress = IPAddress(10, 0, 1, 78);
const IPAddress kGateway = IPAddress(10, 0, 1, 1);
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 MIN_SIGNAL_STRENGTH 20 // Minimum WiFi signal stength (percentage)
// before we will connect.
// The unset default is 8%.
// (Uncomment to enable)
// ----------------------- HTTP Related Settings -------------------------------
#define FIRMWARE_OTA true // Allow remote update of the firmware via http.
// Less secure if enabled.
// Note: Firmware OTA is also disabled until
// a password is set.
#define HTML_PASSWORD_ENABLE false // Protect access to the HTML interface.
// Note: OTA update is always passworded.
// If you do not set a password, Firmware OTA updates will be blocked.
// ----------------------- MQTT Related Settings -------------------------------
#if MQTT_ENABLE
const uint32_t kMqttReconnectTime = 5000; // Delay(ms) between reconnect tries.
#define MQTT_ACK "sent" // Sub-topic we send back acknowledgements on.
#define MQTT_SEND "send" // Sub-topic we get new commands from.
#define MQTT_RECV "received" // Topic we send received IRs to.
#define MQTT_LOG "log" // Topic we send log messages to.
#define MQTT_LWT "status" // Topic for the Last Will & Testament.
#define MQTT_CLIMATE "ac" // Sub-topic for the climate topics.
#define MQTT_CLIMATE_CMND "cmnd" // Sub-topic for the climate command topics.
#define MQTT_CLIMATE_STAT "stat" // Sub-topic for the climate stat topics.
#define MQTTbroadcastInterval 10 * 60 // Seconds between rebroadcasts
#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.
#endif // MQTT_ENABLE
// ------------------------ IR Capture Settings --------------------------------
// Let's use a larger than normal buffer so we can handle AirCon remote codes.
const uint16_t kCaptureBufferSize = 1024;
#if DECODE_AC
// Some A/C units have gaps in their protocols of ~40ms. e.g. Kelvinator
// A value this large may swallow repeats of some protocols
const uint8_t kCaptureTimeout = 50; // Milliseconds
#else // DECODE_AC
// Suits most messages, while not swallowing many repeats.
const uint8_t kCaptureTimeout = 15; // Milliseconds
#endif // DECODE_AC
// Ignore unknown messages with <10 pulses (see also REPORT_UNKNOWNS)
const uint16_t kMinUnknownSize = 2 * 10;
#define REPORT_UNKNOWNS false // Report inbound IR messages that we don't know.
#define REPORT_RAW_UNKNOWNS false // Report the whole buffer, recommended:
// MQTT_MAX_PACKET_SIZE of 1024 or more
// ------------------------ Advanced Usage Only --------------------------------
// Change if you need multiple independent send gpio/topics.
const uint8_t gpioTable[] = {
IR_LED, // Default GPIO. e.g. ir_server/send or ir_server/send_0
// Uncomment the following as needed.
// NOTE: Remember to disable DEBUG if you are using one of the serial pins.
// 5, // GPIO 5 / D1 e.g. ir_server/send_1
// 14, // GPIO 14 / D5 e.g. ir_server/send_2
// 16, // GPIO 16 / D0 e.g. ir_server/send_3
};
#define KEY_PROTOCOL "protocol"
#define KEY_MODEL "model"
#define KEY_POWER "power"
#define KEY_MODE "mode"
#define KEY_TEMP "temp"
#define KEY_FANSPEED "fanspeed"
#define KEY_SWINGV "swingv"
#define KEY_SWINGH "swingh"
#define KEY_QUIET "quiet"
#define KEY_TURBO "turbo"
#define KEY_LIGHT "light"
#define KEY_BEEP "beep"
#define KEY_ECONO "econo"
#define KEY_SLEEP "sleep"
#define KEY_CLOCK "clock"
#define KEY_FILTER "filter"
#define KEY_CLEAN "clean"
#define KEY_CELSIUS "use_celsius"
// HTML arguments we will parse for IR code information.
#define KEY_TYPE "type" // KEY_PROTOCOL is also checked too.
#define KEY_CODE "code"
#define KEY_BITS "bits"
#define KEY_REPEAT "repeats"
// Text for Last Will & Testament status messages.
const char* kLwtOnline = "Online";
const char* kLwtOffline = "Offline";
const uint8_t kHostnameLength = 30;
const uint8_t kPortLength = 5; // Largest value of uint16_t is "65535".
const uint8_t kUsernameLength = 15;
const uint8_t kPasswordLength = 20;
// -------------------------- Debug Settings -----------------------------------
// Disable debug output if any of the IR pins are on the TX (D1) pin.
// Note: This is a crude method to catch the common use cases.
// See `isSerialGpioUsedByIr()` for the better method.
#if (IR_LED != 1 && IR_RX != 1)
#ifndef DEBUG
#define DEBUG true // Change to 'false' to disable all serial output.
#endif // DEBUG
#else // (IR_LED != 1 && IR_RX != 1)
#undef DEBUG
#define DEBUG false
#endif
// ----------------- End of User Configuration Section -------------------------
// Constants
#define _MY_VERSION_ "v1.0.0"
const uint8_t kSendTableSize = sizeof(gpioTable);
// JSON stuff
// Name of the json config file in SPIFFS.
const char* kConfigFile = "/config.json";
const char* kMqttServerKey = "mqtt_server";
const char* kMqttPortKey = "mqtt_port";
const char* kMqttUserKey = "mqtt_user";
const char* kMqttPassKey = "mqtt_pass";
const char* kMqttPrefixKey = "mqtt_prefix";
const char* kHostnameKey = "hostname";
const char* kHttpUserKey = "http_user";
const char* kHttpPassKey = "http_pass";
#if MQTT_ENABLE
const uint32_t kBroadcastPeriodMs = MQTTbroadcastInterval * 1000; // mSeconds.
const uint32_t kStatListenPeriodMs = 5 * 1000; // mSeconds
void mqttCallback(char* topic, byte* payload, unsigned int length);
String listOfCommandTopics(void);
void handleSendMqttDiscovery(void);
void subscribing(const String topic_name);
void unsubscribing(const String topic_name);
void mqttLog(const String mesg);
bool reconnect(void);
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 commonAcState_t state, const bool retain,
const bool force);
#endif // MQTT_ENABLE
bool isSerialGpioUsedByIr(void);
void debug(const char *str);
void saveWifiConfigCallback(void);
void saveWifiConfig(void);
void loadWifiConfigFile(void);
String msToHumanString(uint32_t const msecs);
String timeElapsed(uint32_t const msec);
String timeSince(uint32_t const start);
String listOfSendGpios(void);
bool hasUnsafeHTMLChars(String input);
String htmlMenu(void);
void handleRoot(void);
String addJsReloadUrl(const String url, const uint16_t timeout_s,
const bool notify);
void handleExamples(void);
String boolToString(const bool value);
String opmodeToString(const stdAc::opmode_t mode);
String fanspeedToString(const stdAc::fanspeed_t speed);
String swingvToString(const stdAc::swingv_t swingv);
String swinghToString(const stdAc::swingh_t swingh);
String htmlSelectBool(const String name, const bool def);
String htmlSelectProtocol(const String name, const decode_type_t def);
String htmlSelectModel(const String name, const int16_t def);
String htmlSelectMode(const String name, const stdAc::opmode_t def);
String htmlSelectFanspeed(const String name, const stdAc::fanspeed_t def);
String htmlSelectSwingv(const String name, const stdAc::swingv_t def);
String htmlSelectSwingh(const String name, const stdAc::swingh_t def);
void handleAirCon(void);
void handleAirConSet(void);
void handleAdmin(void);
void handleInfo(void);
void handleReset(void);
void handleReboot(void);
bool parseStringAndSendAirCon(IRsend *irsend, const uint16_t irType,
const String str);
uint16_t countValuesInStr(const String str, char sep);
uint16_t * newCodeArray(const uint16_t size);
#if SEND_GLOBALCACHE
bool parseStringAndSendGC(IRsend *irsend, const String str);
#endif // SEND_GLOBALCACHE
#if SEND_PRONTO
bool parseStringAndSendPronto(IRsend *irsend, const String str,
uint16_t repeats);
#endif // SEND_PRONTO
#if SEND_RAW
bool parseStringAndSendRaw(IRsend *irsend, const String str);
#endif // SEND_RAW
void handleIr(void);
void handleNotFound(void);
void setup_wifi(void);
void init_vars(void);
void setup(void);
void loop(void);
uint64_t getUInt64fromHex(char const *str);
bool sendIRCode(IRsend *irsend, int const ir_type,
uint64_t const code, char const * code_str, uint16_t bits,
uint16_t repeat);
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);
commonAcState_t updateClimate(commonAcState_t current, const String str,
const String prefix, const String payload);
bool cmpClimate(const commonAcState_t a, const commonAcState_t b);
bool sendClimate(const commonAcState_t prev, const commonAcState_t next,
const String topic_prefix, const bool retain,
const bool forceMQTT, const bool forceIR);
#endif // EXAMPLES_IRMQTTSERVER_IRMQTTSERVER_H_

File diff suppressed because it is too large Load Diff

View File

@ -3,16 +3,19 @@ lib_extra_dirs = ../../
src_dir=.
[common]
build_flags = -DMQTT_MAX_PACKET_SIZE=512
build_flags = -DMQTT_MAX_PACKET_SIZE=768
lib_ldf_mode = chain+
lib_deps_builtin =
lib_deps_external =
PubSubClient
WifiManager@0.14
ArduinoJson
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
@ -22,7 +25,18 @@ lib_deps =
platform=espressif8266
framework=arduino
board=d1_mini
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}
[env:d1_mini_no_mqtt]
platform=espressif8266
framework=arduino
board=d1_mini
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags} -DMQTT_ENABLE=false
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -6,11 +6,13 @@ src_dir=.
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -35,9 +35,15 @@
#include <ir_Kelvinator.h>
#include <ir_Midea.h>
#include <ir_Mitsubishi.h>
#include <ir_MitsubishiHeavy.h>
#include <ir_Panasonic.h>
#include <ir_Samsung.h>
#include <ir_Tcl.h>
#include <ir_Teco.h>
#include <ir_Toshiba.h>
#include <ir_Vestel.h>
#include <ir_Whirlpool.h>
// ==================== start of TUNEABLE PARAMETERS ====================
// An IR detector/demodulator is connected to GPIO pin 14
@ -121,6 +127,20 @@ void dumpACInfo(decode_results *results) {
description = ac.toString();
}
#endif // DECODE_DAIKIN
#if DECODE_DAIKIN2
if (results->decode_type == DAIKIN2) {
IRDaikin2 ac(0);
ac.setRaw(results->state);
description = ac.toString();
}
#endif // DECODE_DAIKIN2
#if DECODE_DAIKIN216
if (results->decode_type == DAIKIN216) {
IRDaikin216 ac(0);
ac.setRaw(results->state);
description = ac.toString();
}
#endif // DECODE_DAIKIN216
#if DECODE_FUJITSU_AC
if (results->decode_type == FUJITSU_AC) {
IRFujitsuAC ac(0);
@ -142,6 +162,18 @@ void dumpACInfo(decode_results *results) {
description = ac.toString();
}
#endif // DECODE_MITSUBISHI_AC
#if DECODE_MITSUBISHIHEAVY
if (results->decode_type == MITSUBISHI_HEAVY_88) {
IRMitsubishiHeavy88Ac ac(0);
ac.setRaw(results->state);
description = ac.toString();
}
if (results->decode_type == MITSUBISHI_HEAVY_152) {
IRMitsubishiHeavy152Ac ac(0);
ac.setRaw(results->state);
description = ac.toString();
}
#endif // DECODE_MITSUBISHIHEAVY
#if DECODE_TOSHIBA_AC
if (results->decode_type == TOSHIBA_AC) {
IRToshibaAC ac(0);
@ -180,7 +212,7 @@ void dumpACInfo(decode_results *results) {
#if DECODE_SAMSUNG_AC
if (results->decode_type == SAMSUNG_AC) {
IRSamsungAc ac(0);
ac.setRaw(results->state);
ac.setRaw(results->state, results->bits / 8);
description = ac.toString();
}
#endif // DECODE_SAMSUNG_AC
@ -206,6 +238,34 @@ void dumpACInfo(decode_results *results) {
description = ac.toString();
}
#endif // DECODE_HITACHI_AC
#if DECODE_WHIRLPOOL_AC
if (results->decode_type == WHIRLPOOL_AC) {
IRWhirlpoolAc ac(0);
ac.setRaw(results->state);
description = ac.toString();
}
#endif // DECODE_WHIRLPOOL_AC
#if DECODE_VESTEL_AC
if (results->decode_type == VESTEL_AC) {
IRVestelAc ac(0);
ac.setRaw(results->value); // Like Coolix, use value instead of state.
description = ac.toString();
}
#endif // DECODE_VESTEL_AC
#if DECODE_TECO
if (results->decode_type == TECO) {
IRTecoAc ac(0);
ac.setRaw(results->value); // Like Coolix, use value instead of state.
description = ac.toString();
}
#endif // DECODE_TECO
#if DECODE_TCL112AC
if (results->decode_type == TCL112AC) {
IRTcl112Ac ac(0);
ac.setRaw(results->state);
description = ac.toString();
}
#endif // DECODE_TCL112AC
// If we got a human-readable description of the message, display it.
if (description != "") Serial.println("Mesg Desc.: " + description);
}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -1,6 +1,6 @@
/* IRremoteESP8266: IRsendDemo - demonstrates sending IR codes with IRsend.
*
* Version 1.0 April, 2017
* Version 1.1 January, 2019
* Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009,
* Copyright 2009 Ken Shirriff, http://arcfn.com
*
@ -46,6 +46,10 @@ uint16_t rawData[67] = {9000, 4500, 650, 550, 650, 1650, 600, 550, 650, 550,
650, 550, 650, 550, 600, 550, 650, 550, 650, 550,
650, 1650, 600, 550, 650, 1650, 650, 1650, 650, 1650,
650, 1650, 650, 1650, 650, 1650, 600};
// Example Samsung A/C state captured from IRrecvDumpV2.ino
uint8_t samsungState[kSamsungAcStateLength] = {
0x02, 0x92, 0x0F, 0x00, 0x00, 0x00, 0xF0,
0x01, 0xE2, 0xFE, 0x71, 0x40, 0x11, 0xF0};
void setup() {
irsend.begin();
@ -53,19 +57,16 @@ void setup() {
}
void loop() {
#if SEND_NEC
Serial.println("NEC");
irsend.sendNEC(0x00FFE01FUL, 32);
#endif // SEND_NEC
irsend.sendNEC(0x00FFE01FUL);
delay(2000);
#if SEND_SONY
Serial.println("Sony");
irsend.sendSony(0xa90, 12, 2);
#endif // SEND_SONY
irsend.sendSony(0xa90, 12, 2); // 12 bits & 2 repeats
delay(2000);
#if SEND_RAW
Serial.println("a rawData capture from IRrecvDumpV2");
irsend.sendRaw(rawData, 67, 38); // Send a raw data capture at 38kHz.
#endif // SEND_RAW
delay(2000);
Serial.println("a Samsung A/C state from IRrecvDumpV2");
irsend.sendSamsungAC(samsungState);
delay(2000);
}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,72 @@
/* Copyright 2019 David Conran
*
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
* as specified by kIrLed below.
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_MitsubishiHeavy.h>
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
IRMitsubishiHeavy152Ac ac(kIrLed); // Set the GPIO used for sending messages.
void printState() {
// Display the settings.
Serial.println("Mitsubishi Heavy A/C remote is in the following state:");
Serial.printf(" %s\n", ac.toString().c_str());
// Display the encoded IR sequence.
unsigned char* ir_code = ac.getRaw();
Serial.print("IR Code: 0x");
for (uint8_t i = 0; i < kMitsubishiHeavy152StateLength; i++)
Serial.printf("%02X", ir_code[i]);
Serial.println();
}
void setup() {
ac.begin();
Serial.begin(115200);
delay(200);
// Set up what we want to send. See ir_MitsubishiHeavy.(cpp|h) for all the
// options.
Serial.println("Default state of the remote.");
printState();
Serial.println("Setting desired state for A/C.");
ac.setPower(true); // Turn it on.
ac.setFan(kMitsubishiHeavy152FanMed); // Medium Fan
ac.setMode(kMitsubishiHeavyCool); // Cool mode
ac.setTemp(26); // Celsius
ac.setSwingVertical(kMitsubishiHeavy152SwingVAuto); // Swing vertically
ac.setSwingHorizontal(kMitsubishiHeavy152SwingHMiddle); // Swing Horizontally
}
void loop() {
// Now send the IR signal.
Serial.println("Sending IR command to A/C ...");
ac.send();
printState();
delay(5000);
}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,74 @@
/* Copyright 2017, 2018 David Conran
*
* An IR LED circuit *MUST* be connected to the ESP8266 on a pin
* as specified by kIrLed below.
*
* TL;DR: The IR LED needs to be driven by a transistor for a good result.
*
* Suggested circuit:
* https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
*
* Common mistakes & tips:
* * Don't just connect the IR LED directly to the pin, it won't
* have enough current to drive the IR LED effectively.
* * Make sure you have the IR LED polarity correct.
* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
* * Typical digital camera/phones can be used to see if the IR LED is flashed.
* Replace the IR LED with a normal LED if you don't have a digital camera
* when debugging.
* * Avoid using the following pins unless you really know what you are doing:
* * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
* for your first time. e.g. ESP-12 etc.
*/
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_Panasonic.h>
const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2).
IRPanasonicAc ac(kIrLed); // Set the GPIO used for sending messages.
void printState() {
// Display the settings.
Serial.println("Panasonic A/C remote is in the following state:");
Serial.printf(" %s\n", ac.toString().c_str());
// Display the encoded IR sequence.
unsigned char* ir_code = ac.getRaw();
Serial.print("IR Code: 0x");
for (uint8_t i = 0; i < kPanasonicAcStateLength; i++)
Serial.printf("%02X", ir_code[i]);
Serial.println();
}
void setup() {
ac.begin();
Serial.begin(115200);
delay(200);
// Set up what we want to send. See ir_Panasonic.cpp for all the options.
Serial.println("Default state of the remote.");
printState();
Serial.println("Setting desired state for A/C.");
ac.setModel(kPanasonicRkr);
ac.on();
ac.setFan(kPanasonicAcFanAuto);
ac.setMode(kPanasonicAcCool);
ac.setTemp(26);
ac.setSwingVertical(kPanasonicAcSwingVAuto);
ac.setSwingHorizontal(kPanasonicAcSwingHAuto);
}
void loop() {
// Now send the IR signal.
#if SEND_PANASONIC_AC
Serial.println("Sending IR command to A/C ...");
ac.send();
#endif // SEND_PANASONIC_AC
printState();
delay(5000);
}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

@ -0,0 +1,19 @@
[platformio]
lib_extra_dirs = ../../
src_dir=.
[common]
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
${common.lib_deps_external}

View File

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

View File

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

View File

@ -6,11 +6,13 @@ src_dir = examples/IRrecvDumpV2
build_flags =
lib_deps_builtin =
lib_deps_external =
lib_ldf_mode = chain+
[env:nodemcuv2]
platform = espressif8266
framework = arduino
board = nodemcuv2
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}
@ -20,6 +22,7 @@ lib_deps =
platform = espressif8266
framework = arduino
board = d1_mini
lib_ldf_mode = ${common.lib_ldf_mode}
build_flags = ${common.build_flags}
lib_deps =
${common.lib_deps_builtin}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,248 @@
#ifndef IRAC_H_
#define IRAC_H_
// Copyright 2019 David Conran
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#ifndef ARDUINO
#include <string>
#endif
#include "IRremoteESP8266.h"
#include "ir_Argo.h"
#include "ir_Coolix.h"
#include "ir_Daikin.h"
#include "ir_Fujitsu.h"
#include "ir_Gree.h"
#include "ir_Haier.h"
#include "ir_Hitachi.h"
#include "ir_Kelvinator.h"
#include "ir_Midea.h"
#include "ir_Mitsubishi.h"
#include "ir_MitsubishiHeavy.h"
#include "ir_Panasonic.h"
#include "ir_Samsung.h"
#include "ir_Tcl.h"
#include "ir_Teco.h"
#include "ir_Toshiba.h"
#include "ir_Trotec.h"
#include "ir_Vestel.h"
#include "ir_Whirlpool.h"
class IRac {
public:
explicit IRac(uint8_t pin);
static bool isProtocolSupported(const decode_type_t protocol);
bool sendAc(const decode_type_t vendor, const int16_t model,
const bool power, const stdAc::opmode_t mode, const float degrees,
const bool celsius, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet, const bool turbo, const bool econo,
const bool light, const bool filter, const bool clean,
const bool beep, const int16_t sleep = -1,
const int16_t clock = -1);
static bool strToBool(const char *str, const bool def = false);
static int16_t strToModel(const char *str, const int16_t def = -1);
static stdAc::opmode_t strToOpmode(
const char *str, const stdAc::opmode_t def = stdAc::opmode_t::kAuto);
static stdAc::fanspeed_t strToFanspeed(
const char *str,
const stdAc::fanspeed_t def = stdAc::fanspeed_t::kAuto);
static stdAc::swingv_t strToSwingV(
const char *str, const stdAc::swingv_t def = stdAc::swingv_t::kOff);
static stdAc::swingh_t strToSwingH(
const char *str, const stdAc::swingh_t def = stdAc::swingh_t::kOff);
#ifndef UNIT_TEST
private:
#endif
uint8_t _pin;
#if SEND_ARGO
void argo(IRArgoAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool turbo, const int16_t sleep = -1);
#endif // SEND_ARGO
#if SEND_COOLIX
void coolix(IRCoolixAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool turbo, const bool light, const bool clean,
const int16_t sleep = -1);
#endif // SEND_COOLIX
#if SEND_DAIKIN
void daikin(IRDaikinESP *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet, const bool turbo, const bool econo,
const bool clean);
#endif // SEND_DAIKIN
#if SEND_DAIKIN2
void daikin2(IRDaikin2 *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet, const bool turbo, const bool light,
const bool econo, const bool filter, const bool clean,
const bool beep, const int16_t sleep = -1,
const int16_t clock = -1);
#endif // SEND_DAIKIN2
#if SEND_DAIKIN216
void daikin216(IRDaikin216 *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet);
#endif // SEND_DAIKIN216
#if SEND_FUJITSU_AC
void fujitsu(IRFujitsuAC *ac, const fujitsu_ac_remote_model_t model,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet);
#endif // SEND_FUJITSU_AC
#if SEND_GREE
void gree(IRGreeAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool turbo, const bool light, const bool clean,
const int16_t sleep = -1);
#endif // SEND_GREE
#if SEND_HAIER_AC
void haier(IRHaierAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool filter, const int16_t sleep = -1,
const int16_t clock = -1);
#endif // SEND_HAIER_AC
#if SEND_HAIER_AC_YRW02
void haierYrwo2(IRHaierACYRW02 *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv,
const bool turbo, const bool filter,
const int16_t sleep = -1);
#endif // SEND_HAIER_AC_YRW02
#if SEND_HITACHI_AC
void hitachi(IRHitachiAc *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh);
#endif // SEND_HITACHI_AC
#if SEND_KELVINATOR
void kelvinator(IRKelvinatorAC *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet, const bool turbo, const bool light,
const bool filter, const bool clean);
#endif // SEND_KELVINATOR
#if SEND_MIDEA
void midea(IRMideaAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const int16_t sleep = -1);
#endif // SEND_MIDEA
#if SEND_MITSUBISHI_AC
void mitsubishi(IRMitsubishiAC *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool quiet, const int16_t clock = -1);
#endif // SEND_MITSUBISHI_AC
#if SEND_MITSUBISHIHEAVY
void mitsubishiHeavy88(IRMitsubishiHeavy88Ac *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv,
const stdAc::swingh_t swingh,
const bool turbo, const bool econo, const bool clean);
void mitsubishiHeavy152(IRMitsubishiHeavy152Ac *ac,
const bool on, const stdAc::opmode_t mode,
const float degrees, const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv,
const stdAc::swingh_t swingh,
const bool quiet, const bool turbo, const bool econo,
const bool filter, const bool clean,
const int16_t sleep = -1);
#endif // SEND_MITSUBISHIHEAVY
#if SEND_PANASONIC_AC
void panasonic(IRPanasonicAc *ac, const panasonic_ac_remote_model_t model,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool quiet, const bool turbo, const int16_t clock = -1);
#endif // SEND_PANASONIC_AC
#if SEND_SAMSUNG_AC
void samsung(IRSamsungAc *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool quiet, const bool turbo, const bool clean,
const bool beep, const bool sendOnOffHack = true);
#endif // SEND_SAMSUNG_AC
#if SEND_TCL112AC
void tcl112(IRTcl112Ac *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan,
const stdAc::swingv_t swingv, const stdAc::swingh_t swingh,
const bool turbo, const bool light, const bool econo,
const bool filter);
#endif // SEND_TCL112AC
#if SEND_TECO
void teco(IRTecoAc *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const int16_t sleep = -1);
#endif // SEND_TECO
#if SEND_TOSHIBA_AC
void toshiba(IRToshibaAC *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan);
#endif // SEND_TOSHIBA_AC
#if SEND_TROTEC
void trotec(IRTrotecESP *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const int16_t sleep = -1);
#endif // SEND_TROTEC
#if SEND_VESTEL_AC
void vestel(IRVestelAc *ac,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool turbo, const bool filter,
const int16_t sleep = -1, const int16_t clock = -1,
const bool sendNormal = true);
#endif // SEND_VESTEL_AC
#if SEND_WHIRLPOOL_AC
void whirlpool(IRWhirlpoolAc *ac, const whirlpool_ac_remote_model_t model,
const bool on, const stdAc::opmode_t mode, const float degrees,
const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv,
const bool turbo, const bool light,
const int16_t sleep = -1, const int16_t clock = -1);
#endif // SEND_WHIRLPOOL_AC
}; // IRac class
// Structure to hold a common A/C state.
typedef struct {
decode_type_t protocol;
int16_t model;
bool power;
stdAc::opmode_t mode;
float degrees;
bool celsius;
stdAc::fanspeed_t fanspeed;
stdAc::swingv_t swingv;
stdAc::swingh_t swingh;
bool quiet;
bool turbo;
bool econo;
bool light;
bool filter;
bool clean;
bool beep;
int16_t sleep;
int16_t clock;
} commonAcState_t;
#endif // IRAC_H_

View File

@ -364,6 +364,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
DPRINTLN("Attempting SAMSUNG decode");
if (decodeSAMSUNG(results)) return true;
#endif
#if DECODE_SAMSUNG36
DPRINTLN("Attempting Samsung36 decode");
if (decodeSamsung36(results)) return true;
#endif
#if DECODE_WHYNTER
DPRINTLN("Attempting Whynter decode");
if (decodeWhynter(results)) return true;
@ -394,6 +398,14 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
DPRINTLN("Attempting Daikin decode");
if (decodeDaikin(results)) return true;
#endif
#if DECODE_DAIKIN2
DPRINTLN("Attempting Daikin2 decode");
if (decodeDaikin2(results)) return true;
#endif
#if DECODE_DAIKIN216
DPRINTLN("Attempting Daikin216 decode");
if (decodeDaikin216(results)) return true;
#endif
#if DECODE_TOSHIBA_AC
DPRINTLN("Attempting Toshiba AC decode");
if (decodeToshibaAC(results)) return true;
@ -489,6 +501,28 @@ bool IRrecv::decode(decode_results *results, irparams_t *save) {
DPRINTLN("Attempting MWM decode");
if (decodeMWM(results)) return true;
#endif
#if DECODE_VESTEL_AC
DPRINTLN("Attempting Vestel AC decode");
if (decodeVestelAc(results)) return true;
#endif
#if DECODE_TCL112AC
DPRINTLN("Attempting TCL112AC decode");
if (decodeTcl112Ac(results)) return true;
#endif
#if DECODE_TECO
DPRINTLN("Attempting Teco decode");
if (decodeTeco(results)) return true;
#endif
#if DECODE_LEGOPF
DPRINTLN("Attempting LEGOPF decode");
if (decodeLegoPf(results)) return true;
#endif
#if DECODE_MITSUBISHIHEAVY
DPRINTLN("Attempting MITSUBISHIHEAVY (152 bit) decode");
if (decodeMitsubishiHeavy(results, kMitsubishiHeavy152Bits)) return true;
DPRINTLN("Attempting MITSUBISHIHEAVY (88 bit) decode");
if (decodeMitsubishiHeavy(results, kMitsubishiHeavy88Bits)) return true;
#endif
#if DECODE_HASH
// decodeHash returns a hash on any input.
// Thus, it needs to be last in the list.

View File

@ -181,6 +181,10 @@ class IRrecv {
uint16_t nbits = kMitsubishiACBits,
bool strict = false);
#endif
#if DECODE_MITSUBISHIHEAVY
bool decodeMitsubishiHeavy(decode_results *results, const uint16_t nbits,
const bool strict = true);
#endif
#if (DECODE_RC5 || DECODE_R6 || DECODE_LASERTAG || DECODE_MWM)
int16_t getRClevel(decode_results *results, uint16_t *offset, uint16_t *used,
uint16_t bitTime, uint8_t tolerance = kTolerance,
@ -216,6 +220,11 @@ class IRrecv {
bool decodeSAMSUNG(decode_results *results, uint16_t nbits = kSamsungBits,
bool strict = true);
#endif
#if DECODE_SAMSUNG
bool decodeSamsung36(decode_results *results,
const uint16_t nbits = kSamsung36Bits,
const bool strict = true);
#endif
#if DECODE_SAMSUNG_AC
bool decodeSamsungAC(decode_results *results, uint16_t nbits = kSamsungAcBits,
bool strict = true);
@ -257,8 +266,17 @@ class IRrecv {
uint16_t nbits = kKelvinatorBits, bool strict = true);
#endif
#if DECODE_DAIKIN
bool decodeDaikin(decode_results *results, uint16_t nbits = kDaikinRawBits,
bool strict = true);
bool decodeDaikin(decode_results *results, const uint16_t nbits = kDaikinBits,
const bool strict = true);
#endif
#if DECODE_DAIKIN2
bool decodeDaikin2(decode_results *results, uint16_t nbits = kDaikin2Bits,
bool strict = true);
#endif
#if DECODE_DAIKIN216
bool decodeDaikin216(decode_results *results,
const uint16_t nbits = kDaikin216Bits,
const bool strict = true);
#endif
#if DECODE_TOSHIBA_AC
bool decodeToshibaAC(decode_results *results,
@ -330,6 +348,22 @@ class IRrecv {
bool decodeMWM(decode_results *results, uint16_t nbits = 24,
bool strict = true);
#endif
#if DECODE_VESTEL_AC
bool decodeVestelAc(decode_results *results, uint16_t nbits = kVestelAcBits,
bool strict = true);
#endif
#if DECODE_TCL112AC
bool decodeTcl112Ac(decode_results *results, uint16_t nbits = kTcl112AcBits,
bool strict = true);
#endif
#if DECODE_TECO
bool decodeTeco(decode_results *results, uint16_t nbits = kTecoBits,
bool strict = false);
#endif
#if DECODE_LEGOPF
bool decodeLegoPf(decode_results *results, const uint16_t nbits = kLegoPfBits,
const bool strict = true);
#endif
};
#endif // IRRECV_H_

View File

@ -34,6 +34,8 @@
* Fujitsu A/C code added by jonnygraham
* Trotec AC code by stufisher
* Carrier & Haier AC code by crankyoldgit
* Vestel AC code by Erdem U. Altınyurt
* Teco AC code by Fabien Valthier (hcoohb)
*
* GPL license, all text above must be included in any redistribution
****************************************************/
@ -48,7 +50,7 @@
#endif
// Library Version
#define _IRREMOTEESP8266_VERSION_ "2.5.2"
#define _IRREMOTEESP8266_VERSION_ "2.6.0"
// Supported IR protocols
// Each protocol you include costs memory and, during decode, costs time
// Disable (set to false) all the protocols you do not need/want!
@ -86,6 +88,9 @@
#define DECODE_SAMSUNG true
#define SEND_SAMSUNG true
#define DECODE_SAMSUNG36 true
#define SEND_SAMSUNG36 true
#define DECODE_SAMSUNG_AC true
#define SEND_SAMSUNG_AC true
@ -199,6 +204,27 @@
#define DECODE_PIONEER true
#define SEND_PIONEER true
#define DECODE_DAIKIN2 true
#define SEND_DAIKIN2 true
#define DECODE_VESTEL_AC true
#define SEND_VESTEL_AC true
#define DECODE_TECO true
#define SEND_TECO true
#define DECODE_TCL112AC true
#define SEND_TCL112AC true
#define DECODE_LEGOPF true
#define SEND_LEGOPF true
#define DECODE_MITSUBISHIHEAVY true
#define SEND_MITSUBISHIHEAVY true
#define DECODE_DAIKIN216 true
#define SEND_DAIKIN216 true
*/
// Tasmota supported protocols (less protocols is less code size)
@ -233,6 +259,9 @@
#define DECODE_SAMSUNG true
#define SEND_SAMSUNG true
#define DECODE_SAMSUNG36 false
#define SEND_SAMSUNG36 false
#define DECODE_SAMSUNG_AC false
#define SEND_SAMSUNG_AC false
@ -347,12 +376,35 @@
#define DECODE_PIONEER false
#define SEND_PIONEER false
#define DECODE_DAIKIN2 false
#define SEND_DAIKIN2 false
#define DECODE_VESTEL_AC false
#define SEND_VESTEL_AC false
#define DECODE_TECO false
#define SEND_TECO false
#define DECODE_TCL112AC false
#define SEND_TCL112AC false
#define DECODE_LEGOPF false
#define SEND_LEGOPF false
#define DECODE_MITSUBISHIHEAVY false
#define SEND_MITSUBISHIHEAVY false
#define DECODE_DAIKIN216 false
#define SEND_DAIKIN216 false
#if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \
DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \
DECODE_TROTEC || DECODE_HAIER_AC || DECODE_HITACHI_AC || \
DECODE_HITACHI_AC1 || DECODE_HITACHI_AC2 || DECODE_HAIER_AC_YRW02 || \
DECODE_WHIRLPOOL_AC || DECODE_SAMSUNG_AC || DECODE_ELECTRA_AC || \
DECODE_PANASONIC_AC || DECODE_MWM)
DECODE_PANASONIC_AC || DECODE_MWM || DECODE_DAIKIN2 || \
DECODE_VESTEL_AC || DECODE_TCL112AC || DECODE_MITSUBISHIHEAVY || \
DECODE_DAIKIN216)
#define DECODE_AC true // We need some common infrastructure for decoding A/Cs.
#else
#define DECODE_AC false // We don't need that infrastructure.
@ -376,54 +428,65 @@ enum decode_type_t {
RC6,
NEC,
SONY,
PANASONIC,
PANASONIC, // (5)
JVC,
SAMSUNG,
WHYNTER,
AIWA_RC_T501,
LG,
LG, // (10)
SANYO,
MITSUBISHI,
DISH,
SHARP,
COOLIX,
COOLIX, // (15)
DAIKIN,
DENON,
KELVINATOR,
SHERWOOD,
MITSUBISHI_AC,
MITSUBISHI_AC, // (20)
RCMM,
SANYO_LC7461,
RC5X,
GREE,
PRONTO, // Technically not a protocol, but an encoding.
PRONTO, // Technically not a protocol, but an encoding. (25)
NEC_LIKE,
ARGO,
TROTEC,
NIKAI,
RAW, // Technically not a protocol, but an encoding.
RAW, // Technically not a protocol, but an encoding. (30)
GLOBALCACHE, // Technically not a protocol, but an encoding.
TOSHIBA_AC,
FUJITSU_AC,
MIDEA,
MAGIQUEST,
MAGIQUEST, // (35)
LASERTAG,
CARRIER_AC,
HAIER_AC,
MITSUBISHI2,
HITACHI_AC,
HITACHI_AC, // (40)
HITACHI_AC1,
HITACHI_AC2,
GICABLE,
HAIER_AC_YRW02,
WHIRLPOOL_AC,
WHIRLPOOL_AC, // (45)
SAMSUNG_AC,
LUTRON,
ELECTRA_AC,
PANASONIC_AC,
PIONEER,
PIONEER, // (50)
LG2,
MWM,
DAIKIN2,
VESTEL_AC,
TECO, // (55)
SAMSUNG36,
TCL112AC,
LEGOPF,
MITSUBISHI_HEAVY_88,
MITSUBISHI_HEAVY_152, // 60
DAIKIN216,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = DAIKIN216,
};
// Message lengths & required repeat values
@ -433,13 +496,22 @@ const uint16_t kSingleRepeat = 1;
const uint16_t kAiwaRcT501Bits = 15;
const uint16_t kAiwaRcT501MinRepeats = kSingleRepeat;
const uint16_t kArgoStateLength = 12;
const uint16_t kArgoDefaultRepeat = kNoRepeat;
const uint16_t kCoolixBits = 24;
const uint16_t kCoolixDefaultRepeat = 1;
const uint16_t kCarrierAcBits = 32;
const uint16_t kCarrierAcMinRepeat = kNoRepeat;
// Daikin has a lot of static stuff that is discarded
const uint16_t kDaikinRawBits = 583;
const uint16_t kDaikinStateLength = 27;
const uint16_t kDaikinStateLength = 35;
const uint16_t kDaikinBits = kDaikinStateLength * 8;
const uint16_t kDaikinStateLengthShort = kDaikinStateLength - 8;
const uint16_t kDaikinBitsShort = kDaikinStateLengthShort * 8;
const uint16_t kDaikinDefaultRepeat = kNoRepeat;
const uint16_t kDaikin2StateLength = 39;
const uint16_t kDaikin2Bits = kDaikin2StateLength * 8;
const uint16_t kDaikin2DefaultRepeat = kNoRepeat;
const uint16_t kDaikin216StateLength = 27;
const uint16_t kDaikin216Bits = kDaikin216StateLength * 8;
const uint16_t kDaikin216DefaultRepeat = kNoRepeat;
const uint16_t kDenonBits = 15;
const uint16_t kDenonLegacyBits = 14;
const uint16_t kDishBits = 16;
@ -455,12 +527,16 @@ const uint16_t kGicableBits = 16;
const uint16_t kGicableMinRepeat = kSingleRepeat;
const uint16_t kGreeStateLength = 8;
const uint16_t kGreeBits = kGreeStateLength * 8;
const uint16_t kGreeDefaultRepeat = kNoRepeat;
const uint16_t kHaierACStateLength = 9;
const uint16_t kHaierACBits = kHaierACStateLength * 8;
const uint16_t kHaierAcDefaultRepeat = kNoRepeat;
const uint16_t kHaierACYRW02StateLength = 14;
const uint16_t kHaierACYRW02Bits = kHaierACYRW02StateLength * 8;
const uint16_t kHaierAcYrw02DefaultRepeat = kNoRepeat;
const uint16_t kHitachiAcStateLength = 28;
const uint16_t kHitachiAcBits = kHitachiAcStateLength * 8;
const uint16_t kHitachiAcDefaultRepeat = kNoRepeat;
const uint16_t kHitachiAc1StateLength = 13;
const uint16_t kHitachiAc1Bits = kHitachiAc1StateLength * 8;
const uint16_t kHitachiAc2StateLength = 53;
@ -468,8 +544,11 @@ const uint16_t kHitachiAc2Bits = kHitachiAc2StateLength * 8;
const uint16_t kJvcBits = 16;
const uint16_t kKelvinatorStateLength = 16;
const uint16_t kKelvinatorBits = kKelvinatorStateLength * 8;
const uint16_t kKelvinatorDefaultRepeat = kNoRepeat;
const uint16_t kLasertagBits = 13;
const uint16_t kLasertagMinRepeat = kNoRepeat;
const uint16_t kLegoPfBits = 16;
const uint16_t kLegoPfMinRepeat = kNoRepeat;
const uint16_t kLgBits = 28;
const uint16_t kLg32Bits = 32;
const uint16_t kLutronBits = 35;
@ -483,6 +562,12 @@ const uint16_t kMitsubishiMinRepeat = kSingleRepeat;
const uint16_t kMitsubishiACStateLength = 18;
const uint16_t kMitsubishiACBits = kMitsubishiACStateLength * 8;
const uint16_t kMitsubishiACMinRepeat = kSingleRepeat;
const uint16_t kMitsubishiHeavy88StateLength = 11;
const uint16_t kMitsubishiHeavy88Bits = kMitsubishiHeavy88StateLength * 8;
const uint16_t kMitsubishiHeavy88MinRepeat = kNoRepeat;
const uint16_t kMitsubishiHeavy152StateLength = 19;
const uint16_t kMitsubishiHeavy152Bits = kMitsubishiHeavy152StateLength * 8;
const uint16_t kMitsubishiHeavy152MinRepeat = kNoRepeat;
const uint16_t kNikaiBits = 24;
const uint16_t kNECBits = 32;
const uint16_t kPanasonicBits = 48;
@ -491,6 +576,7 @@ const uint16_t kPanasonicAcStateLength = 27;
const uint16_t kPanasonicAcStateShortLength = 16;
const uint16_t kPanasonicAcBits = kPanasonicAcStateLength * 8;
const uint16_t kPanasonicAcShortBits = kPanasonicAcStateShortLength * 8;
const uint16_t kPanasonicAcDefaultRepeat = kNoRepeat;
const uint16_t kPioneerBits = 64;
const uint16_t kProntoMinLength = 6;
const uint16_t kRC5RawBits = 14;
@ -500,10 +586,12 @@ const uint16_t kRC6Mode0Bits = 20; // Excludes the 'start' bit.
const uint16_t kRC6_36Bits = 36; // Excludes the 'start' bit.
const uint16_t kRCMMBits = 24;
const uint16_t kSamsungBits = 32;
const uint16_t kSamsung36Bits = 36;
const uint16_t kSamsungAcStateLength = 14;
const uint16_t kSamsungAcBits = kSamsungAcStateLength * 8;
const uint16_t kSamsungAcExtendedStateLength = 21;
const uint16_t kSamsungAcExtendedBits = kSamsungAcExtendedStateLength * 8;
const uint16_t kSamsungAcDefaultRepeat = kNoRepeat;
const uint16_t kSanyoSA8650BBits = 12;
const uint16_t kSanyoLC7461AddressBits = 13;
const uint16_t kSanyoLC7461CommandBits = 8;
@ -519,13 +607,22 @@ const uint16_t kSony15Bits = 15;
const uint16_t kSony20Bits = 20;
const uint16_t kSonyMinBits = 12;
const uint16_t kSonyMinRepeat = 2;
const uint16_t kTcl112AcStateLength = 14;
const uint16_t kTcl112AcBits = kTcl112AcStateLength * 8;
const uint16_t kTcl112AcDefaultRepeat = kNoRepeat;
const uint16_t kTecoBits = 35;
const uint16_t kTecoDefaultRepeat = kNoRepeat;
const uint16_t kToshibaACStateLength = 9;
const uint16_t kToshibaACBits = kToshibaACStateLength * 8;
const uint16_t kToshibaACMinRepeat = kSingleRepeat;
const uint16_t kTrotecStateLength = 9;
const uint16_t kTrotecDefaultRepeat = kNoRepeat;
const uint16_t kWhirlpoolAcStateLength = 21;
const uint16_t kWhirlpoolAcBits = kWhirlpoolAcStateLength * 8;
const uint16_t kWhirlpoolAcDefaultRepeat = kNoRepeat;
const uint16_t kWhynterBits = 32;
const uint8_t kVestelAcBits = 56;
// Legacy defines. (Deprecated)
#define AIWA_RC_T501_BITS kAiwaRcT501Bits
@ -598,4 +695,14 @@ const uint16_t kWhynterBits = 32;
#define DPRINTLN(x)
#endif // DEBUG
#ifdef UNIT_TEST
#ifndef F
// Create a no-op F() macro so the code base still compiles outside of the
// Arduino framework. Thus we can safely use the Arduino 'F()' macro through-out
// the code base. That macro stores constants in Flash (PROGMEM) memory.
// See: https://github.com/markszabo/IRremoteESP8266/issues/667
#define F(x) x
#endif // F
#endif // UNIT_TEST
#endif // IRREMOTEESP8266_H_

View File

@ -1,6 +1,6 @@
// Copyright 2009 Ken Shirriff
// Copyright 2015 Mark Szabo
// Copyright 2017 David Conran
// Copyright 2017,2019 David Conran
#include "IRsend.h"
#ifndef UNIT_TEST
@ -110,6 +110,9 @@ void IRsend::enableIROut(uint32_t freq, uint8_t duty) {
}
if (freq < 1000) // Were we given kHz? Supports the old call usage.
freq *= 1000;
#ifdef UNIT_TEST
_freq_unittest = freq;
#endif // UNIT_TEST
uint32_t period = calcUSecPeriod(freq);
// Nr. of uSeconds the LED will be on per pulse.
onTimePeriod = (period * _dutycycle) / kDutyMax;
@ -488,57 +491,24 @@ void IRsend::sendRaw(uint16_t buf[], uint16_t len, uint16_t hz) {
}
#endif // SEND_RAW
#ifndef UNIT_TEST
void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
// Send a simple (up to 64 bits) IR message of a given type.
// An unknown/unsupported type will do nothing.
// Args:
// type: Protocol number/type of the message you want to send.
// data: The data you want to send (up to 64 bits).
// nbits: How many bits long the message is to be.
// Returns:
// bool: True if it is a type we can attempt to send, false if not.
bool IRsend::send(decode_type_t type, uint64_t data, uint16_t nbits) {
switch (type) {
#if SEND_NEC
case NEC:
sendNEC(data, nbits);
#if SEND_AIWA_RC_T501
case AIWA_RC_T501:
sendAiwaRCT501(data, nbits);
break;
#endif
#if SEND_SONY
case SONY:
sendSony(data, nbits);
break;
#endif
#if SEND_RC5
case RC5:
sendRC5(data, nbits);
break;
#endif
#if SEND_RC6
case RC6:
sendRC6(data, nbits);
break;
#endif
#if SEND_DISH
case DISH:
sendDISH(data, nbits);
break;
#endif
#if SEND_JVC
case JVC:
sendJVC(data, nbits);
break;
#endif
#if SEND_SAMSUNG
case SAMSUNG:
sendSAMSUNG(data, nbits);
break;
#endif
#if SEND_LG
case LG:
sendLG(data, nbits);
break;
#endif
#if SEND_LG
case LG2:
sendLG2(data, nbits);
break;
#endif
#if SEND_WHYNTER
case WHYNTER:
sendWhynter(data, nbits);
#if SEND_CARRIER_AC
case CARRIER_AC:
sendCarrierAC(data, nbits);
break;
#endif
#if SEND_COOLIX
@ -551,14 +521,57 @@ void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
sendDenon(data, nbits);
break;
#endif
#if SEND_SHERWOOD
case SHERWOOD:
sendSherwood(data, nbits);
#if SEND_DISH
case DISH:
sendDISH(data, nbits);
break;
#endif
#if SEND_RCMM
case RCMM:
sendRCMM(data, nbits);
#if SEND_GICABLE
case GICABLE:
sendGICable(data, nbits);
break;
#endif
#if SEND_GREE
case GREE:
sendGree(data, nbits);
break;
#endif
#if SEND_JVC
case JVC:
sendJVC(data, nbits);
break;
#endif
#if SEND_LASERTAG
case LASERTAG:
sendLasertag(data, nbits);
break;
#endif
#if SEND_LEGOPF
case LEGOPF:
sendLegoPf(data, nbits);
break;
#endif
#if SEND_LG
case LG:
sendLG(data, nbits);
break;
case LG2:
sendLG2(data, nbits);
break;
#endif
#if SEND_LUTRON
case LUTRON:
sendLutron(data, nbits);
break;
#endif
#if SEND_MAGIQUEST
case MAGIQUEST:
sendMagiQuest(data, nbits);
break;
#endif
#if SEND_MIDEA
case MIDEA:
sendMidea(data, nbits);
break;
#endif
#if SEND_MITSUBISHI
@ -571,24 +584,20 @@ void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
sendMitsubishi2(data, nbits);
break;
#endif
#if SEND_SHARP
case SHARP:
sendSharpRaw(data, nbits);
#if SEND_NIKAI
case NIKAI:
sendNikai(data, nbits);
break;
#endif
#if SEND_AIWA_RC_T501
case AIWA_RC_T501:
sendAiwaRCT501(data, nbits);
#if SEND_NEC
case NEC:
case NEC_LIKE:
sendNEC(data, nbits);
break;
#endif
#if SEND_MIDEA
case MIDEA:
sendMidea(data, nbits);
break;
#endif
#if SEND_GICABLE
case GICABLE:
sendGICable(data, nbits);
#if SEND_PANASONIC
case PANASONIC:
sendPanasonic64(data, nbits);
break;
#endif
#if SEND_PIONEER
@ -596,6 +605,68 @@ void IRsend::send(uint16_t type, uint64_t data, uint16_t nbits) {
sendPioneer(data, nbits);
break;
#endif
}
}
#if SEND_RC5
case RC5:
sendRC5(data, nbits);
break;
#endif
#if SEND_RC6
case RC6:
sendRC6(data, nbits);
break;
#endif
#if SEND_RCMM
case RCMM:
sendRCMM(data, nbits);
break;
#endif
#if SEND_SAMSUNG
case SAMSUNG:
sendSAMSUNG(data, nbits);
break;
#endif
#if SEND_SAMSUNG36
case SAMSUNG36:
sendSamsung36(data, nbits);
break;
#endif
#if SEND_SANYO
case SANYO_LC7461:
sendSanyoLC7461(data, nbits);
break;
#endif
#if SEND_SHARP
case SHARP:
sendSharpRaw(data, nbits);
break;
#endif
#if SEND_SHERWOOD
case SHERWOOD:
sendSherwood(data, nbits);
break;
#endif
#if SEND_SONY
case SONY:
sendSony(data, nbits);
break;
#endif
#if SEND_TECO
case TECO:
sendTeco(data, nbits);
break;
#endif
#if SEND_VESTEL_AC
case VESTEL_AC:
sendVestelAc(data, nbits);
break;
#endif
#if SEND_WHYNTER
case WHYNTER:
sendWhynter(data, nbits);
break;
#endif
default:
return false;
}
return true;
}

View File

@ -28,6 +28,49 @@ const uint8_t kDutyMax = 100; // Percentage
// delayMicroseconds() is only accurate to 16383us.
// Ref: https://www.arduino.cc/en/Reference/delayMicroseconds
const uint16_t kMaxAccurateUsecDelay = 16383;
// Usecs to wait between messages we don't know the proper gap time.
const uint32_t kDefaultMessageGap = 100000;
namespace stdAc {
enum class opmode_t {
kOff = -1,
kAuto = 0,
kCool = 1,
kHeat = 2,
kDry = 3,
kFan = 4,
};
enum class fanspeed_t {
kAuto = 0,
kMin = 1,
kLow = 2,
kMedium = 3,
kHigh = 4,
kMax = 5,
};
enum class swingv_t {
kOff = -1,
kAuto = 0,
kHighest = 1,
kHigh = 2,
kMiddle = 3,
kLow = 4,
kLowest = 5,
};
enum class swingh_t {
kOff = -1,
kAuto = 0, // a.k.a. On.
kLeftMax = 1,
kLeft = 2,
kMiddle = 3,
kRight = 4,
kRightMax = 5,
};
}; // namespace stdAc
// Classes
class IRsend {
@ -66,7 +109,7 @@ class IRsend {
const uint8_t *dataptr, const uint16_t nbytes,
const uint16_t frequency, const bool MSBfirst,
const uint16_t repeat, const uint8_t dutycycle);
void send(uint16_t type, uint64_t data, uint16_t nbits);
bool send(decode_type_t type, uint64_t data, uint16_t nbits);
#if (SEND_NEC || SEND_SHERWOOD || SEND_AIWA_RC_T501 || SEND_SANYO)
void sendNEC(uint64_t data, uint16_t nbits = kNECBits,
uint16_t repeat = kNoRepeat);
@ -92,10 +135,14 @@ class IRsend {
uint16_t repeat = kNoRepeat);
uint32_t encodeSAMSUNG(uint8_t customer, uint8_t command);
#endif
#if SEND_SAMSUNG36
void sendSamsung36(const uint64_t data, const uint16_t nbits = kSamsung36Bits,
const uint16_t repeat = kNoRepeat);
#endif
#if SEND_SAMSUNG_AC
void sendSamsungAC(unsigned char data[],
uint16_t nbytes = kSamsungAcStateLength,
uint16_t repeat = kNoRepeat);
void sendSamsungAC(const unsigned char data[],
const uint16_t nbytes = kSamsungAcStateLength,
const uint16_t repeat = kSamsungAcDefaultRepeat);
#endif
#if SEND_LG
void sendLG(uint64_t data, uint16_t nbits = kLgBits,
@ -166,7 +213,7 @@ class IRsend {
#endif
#if SEND_COOLIX
void sendCOOLIX(uint64_t data, uint16_t nbits = kCoolixBits,
uint16_t repeat = kNoRepeat);
uint16_t repeat = kCoolixDefaultRepeat);
#endif
#if SEND_WHYNTER
void sendWhynter(uint64_t data, uint16_t nbits = kWhynterBits,
@ -185,6 +232,16 @@ class IRsend {
uint16_t nbytes = kMitsubishiACStateLength,
uint16_t repeat = kMitsubishiACMinRepeat);
#endif
#if SEND_MITSUBISHIHEAVY
void sendMitsubishiHeavy88(
const unsigned char data[],
const uint16_t nbytes = kMitsubishiHeavy88StateLength,
const uint16_t repeat = kMitsubishiHeavy88MinRepeat);
void sendMitsubishiHeavy152(
const unsigned char data[],
const uint16_t nbytes = kMitsubishiHeavy152StateLength,
const uint16_t repeat = kMitsubishiHeavy152MinRepeat);
#endif
#if SEND_FUJITSU_AC
void sendFujitsuAC(unsigned char data[], uint16_t nbytes,
uint16_t repeat = kFujitsuAcMinRepeat);
@ -195,12 +252,21 @@ class IRsend {
#if SEND_KELVINATOR
void sendKelvinator(unsigned char data[],
uint16_t nbytes = kKelvinatorStateLength,
uint16_t repeat = kNoRepeat);
uint16_t repeat = kKelvinatorDefaultRepeat);
#endif
#if SEND_DAIKIN
void sendDaikin(unsigned char data[], uint16_t nbytes = kDaikinStateLength,
uint16_t repeat = kNoRepeat);
void sendDaikinGapHeader();
void sendDaikin(const unsigned char data[],
const uint16_t nbytes = kDaikinStateLength,
const uint16_t repeat = kDaikinDefaultRepeat);
#endif
#if SEND_DAIKIN2
void sendDaikin2(unsigned char data[], uint16_t nbytes = kDaikin2StateLength,
uint16_t repeat = kDaikin2DefaultRepeat);
#endif
#if SEND_DAIKIN216
void sendDaikin216(const unsigned char data[],
const uint16_t nbytes = kDaikin216StateLength,
const uint16_t repeat = kDaikin216DefaultRepeat);
#endif
#if SEND_AIWA_RC_T501
void sendAiwaRCT501(uint64_t data, uint16_t nbits = kAiwaRcT501Bits,
@ -208,20 +274,20 @@ class IRsend {
#endif
#if SEND_GREE
void sendGree(uint64_t data, uint16_t nbits = kGreeBits,
uint16_t repeat = kNoRepeat);
uint16_t repeat = kGreeDefaultRepeat);
void sendGree(uint8_t data[], uint16_t nbytes = kGreeStateLength,
uint16_t repeat = kNoRepeat);
uint16_t repeat = kGreeDefaultRepeat);
#endif
#if SEND_PRONTO
void sendPronto(uint16_t data[], uint16_t len, uint16_t repeat = kNoRepeat);
#endif
#if SEND_ARGO
void sendArgo(unsigned char data[], uint16_t nbytes = kArgoStateLength,
uint16_t repeat = kNoRepeat);
uint16_t repeat = kArgoDefaultRepeat);
#endif
#if SEND_TROTEC
void sendTrotec(unsigned char data[], uint16_t nbytes = kTrotecStateLength,
uint16_t repeat = kNoRepeat);
uint16_t repeat = kTrotecDefaultRepeat);
#endif
#if SEND_NIKAI
void sendNikai(uint64_t data, uint16_t nbits = kNikaiBits,
@ -251,17 +317,17 @@ class IRsend {
#endif
#if (SEND_HAIER_AC || SEND_HAIER_AC_YRW02)
void sendHaierAC(unsigned char data[], uint16_t nbytes = kHaierACStateLength,
uint16_t repeat = kNoRepeat);
uint16_t repeat = kHaierAcDefaultRepeat);
#endif
#if SEND_HAIER_AC_YRW02
void sendHaierACYRW02(unsigned char data[],
uint16_t nbytes = kHaierACYRW02StateLength,
uint16_t repeat = kNoRepeat);
uint16_t repeat = kHaierAcYrw02DefaultRepeat);
#endif
#if SEND_HITACHI_AC
void sendHitachiAC(unsigned char data[],
uint16_t nbytes = kHitachiAcStateLength,
uint16_t repeat = kNoRepeat);
uint16_t repeat = kHitachiAcDefaultRepeat);
#endif
#if SEND_HITACHI_AC1
void sendHitachiAC1(unsigned char data[],
@ -280,7 +346,7 @@ class IRsend {
#if SEND_WHIRLPOOL_AC
void sendWhirlpoolAC(unsigned char data[],
uint16_t nbytes = kWhirlpoolAcStateLength,
uint16_t repeat = kNoRepeat);
uint16_t repeat = kWhirlpoolAcDefaultRepeat);
#endif
#if SEND_LUTRON
void sendLutron(uint64_t data, uint16_t nbits = kLutronBits,
@ -294,7 +360,7 @@ class IRsend {
#if SEND_PANASONIC_AC
void sendPanasonicAC(unsigned char data[],
uint16_t nbytes = kPanasonicAcStateLength,
uint16_t repeat = kNoRepeat);
uint16_t repeat = kPanasonicAcDefaultRepeat);
#endif
#if SEND_PIONEER
void sendPioneer(const uint64_t data, const uint16_t nbits = kPioneerBits,
@ -305,6 +371,24 @@ class IRsend {
void sendMWM(unsigned char data[], uint16_t nbytes,
uint16_t repeat = kNoRepeat);
#endif
#if SEND_VESTEL_AC
void sendVestelAc(const uint64_t data, const uint16_t nbits = kVestelAcBits,
const uint16_t repeat = kNoRepeat);
#endif
#if SEND_TCL112AC
void sendTcl112Ac(const unsigned char data[],
const uint16_t nbytes = kTcl112AcStateLength,
const uint16_t repeat = kTcl112AcDefaultRepeat);
#endif
#if SEND_TECO
void sendTeco(uint64_t data, uint16_t nbits = kTecoBits,
uint16_t repeat = kNoRepeat);
#endif
#if SEND_LEGOPF
void sendLegoPf(const uint64_t data, const uint16_t nbits = kLegoPfBits,
const uint16_t repeat = kLegoPfMinRepeat);
#endif
protected:
#ifdef UNIT_TEST
@ -319,8 +403,12 @@ class IRsend {
uint8_t outputOff;
VIRTUAL void ledOff();
VIRTUAL void ledOn();
#ifndef UNIT_TEST
private:
#else
uint32_t _freq_unittest;
#endif // UNIT_TEST
uint16_t onTimePeriod;
uint16_t offTimePeriod;
uint16_t IRpin;

View File

@ -7,12 +7,12 @@
#ifdef UNIT_TEST
// Used to help simulate elapsed time in unit tests.
extern uint32_t _IRtimer_unittest_now;
uint32_t _IRtimer_unittest_now = 0;
uint32_t _TimerMs_unittest_now = 0;
#endif // UNIT_TEST
// This class performs a simple time in useconds since instantiated.
// Handles when the system timer wraps around (once).
IRtimer::IRtimer() { reset(); }
void IRtimer::reset() {
@ -39,3 +39,32 @@ uint32_t IRtimer::elapsed() {
#ifdef UNIT_TEST
void IRtimer::add(uint32_t usecs) { _IRtimer_unittest_now += usecs; }
#endif // UNIT_TEST
// This class performs a simple time in milli-seoncds since instantiated.
// Handles when the system timer wraps around (once).
TimerMs::TimerMs() { reset(); }
void TimerMs::reset() {
#ifndef UNIT_TEST
start = millis();
#else
start = _TimerMs_unittest_now;
#endif
}
uint32_t TimerMs::elapsed() {
#ifndef UNIT_TEST
uint32_t now = millis();
#else
uint32_t now = _TimerMs_unittest_now;
#endif
if (start <= now) // Check if the system timer has wrapped.
return now - start; // No wrap.
else
return UINT32_MAX - start + now; // Has wrapped.
}
// Only used in unit testing.
#ifdef UNIT_TEST
void TimerMs::add(uint32_t msecs) { _IRtimer_unittest_now += msecs; }
#endif // UNIT_TEST

View File

@ -20,4 +20,16 @@ class IRtimer {
uint32_t start;
};
class TimerMs {
public:
TimerMs();
void reset();
uint32_t elapsed();
#ifdef UNIT_TEST
static void add(uint32_t msecs);
#endif // UNIT_TEST
private:
uint32_t start;
};
#endif // IRTIMER_H_

View File

@ -0,0 +1,768 @@
// Copyright 2017 David Conran
#include "IRutils.h"
#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <string.h>
#include <algorithm>
#ifndef ARDUINO
#include <string>
#endif
#include "IRrecv.h"
#include "IRremoteESP8266.h"
// Reverse the order of the requested least significant nr. of bits.
// Args:
// input: Bit pattern/integer to reverse.
// nbits: Nr. of bits to reverse.
// Returns:
// The reversed bit pattern.
uint64_t reverseBits(uint64_t input, uint16_t nbits) {
if (nbits <= 1) return input; // Reversing <= 1 bits makes no change at all.
// Cap the nr. of bits to rotate to the max nr. of bits in the input.
nbits = std::min(nbits, (uint16_t)(sizeof(input) * 8));
uint64_t output = 0;
for (uint16_t i = 0; i < nbits; i++) {
output <<= 1;
output |= (input & 1);
input >>= 1;
}
// Merge any remaining unreversed bits back to the top of the reversed bits.
return (input << nbits) | output;
}
// Convert a uint64_t (unsigned long long) to a string.
// Arduino String/toInt/Serial.print() can't handle printing 64 bit values.
//
// Args:
// input: The value to print
// base: The output base.
// Returns:
// A string representation of the integer.
// Note: Based on Arduino's Print::printNumber()
#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist.
String uint64ToString(uint64_t input, uint8_t base) {
String result = "";
#else
std::string uint64ToString(uint64_t input, uint8_t base) {
std::string result = "";
#endif
// prevent issues if called with base <= 1
if (base < 2) base = 10;
// Check we have a base that we can actually print.
// i.e. [0-9A-Z] == 36
if (base > 36) base = 10;
do {
char c = input % base;
input /= base;
if (c < 10)
c += '0';
else
c += 'A' - 10;
result = c + result;
} while (input);
return result;
}
#ifdef ARDUINO
// Print a uint64_t/unsigned long long to the Serial port
// Serial.print() can't handle printing long longs. (uint64_t)
//
// Args:
// input: The value to print
// base: The output base.
void serialPrintUint64(uint64_t input, uint8_t base) {
Serial.print(uint64ToString(input, base));
}
#endif
// Convert a c-style str to a decode_type_t
// Note: Assumes str is upper case.
//
// Args:
// str: An upper-case C-style string.
// Returns:
// A decode_type_t enum.
decode_type_t strToDecodeType(const char *str) {
if (!strcmp(str, "UNKNOWN"))
return decode_type_t::UNKNOWN;
else if (!strcmp(str, "UNUSED"))
return decode_type_t::UNUSED;
else if (!strcmp(str, "AIWA_RC_T501"))
return decode_type_t::AIWA_RC_T501;
else if (!strcmp(str, "ARGO"))
return decode_type_t::ARGO;
else if (!strcmp(str, "CARRIER_AC"))
return decode_type_t::CARRIER_AC;
else if (!strcmp(str, "COOLIX"))
return decode_type_t::COOLIX;
else if (!strcmp(str, "DAIKIN"))
return decode_type_t::DAIKIN;
else if (!strcmp(str, "DAIKIN2"))
return decode_type_t::DAIKIN2;
else if (!strcmp(str, "DAIKIN216"))
return decode_type_t::DAIKIN216;
else if (!strcmp(str, "DENON"))
return decode_type_t::DENON;
else if (!strcmp(str, "DISH"))
return decode_type_t::DISH;
else if (!strcmp(str, "ELECTRA_AC"))
return decode_type_t::ELECTRA_AC;
else if (!strcmp(str, "FUJITSU_AC"))
return decode_type_t::FUJITSU_AC;
else if (!strcmp(str, "GICABLE"))
return decode_type_t::GICABLE;
else if (!strcmp(str, "GLOBALCACHE"))
return decode_type_t::GLOBALCACHE;
else if (!strcmp(str, "GREE"))
return decode_type_t::GREE;
else if (!strcmp(str, "HAIER_AC"))
return decode_type_t::HAIER_AC;
else if (!strcmp(str, "HAIER_AC_YRW02"))
return decode_type_t::HAIER_AC_YRW02;
else if (!strcmp(str, "HITACHI_AC"))
return decode_type_t::HITACHI_AC;
else if (!strcmp(str, "HITACHI_AC1"))
return decode_type_t::HITACHI_AC1;
else if (!strcmp(str, "HITACHI_AC2"))
return decode_type_t::HITACHI_AC2;
else if (!strcmp(str, "JVC"))
return decode_type_t::JVC;
else if (!strcmp(str, "KELVINATOR"))
return decode_type_t::KELVINATOR;
else if (!strcmp(str, "LEGOPF"))
return decode_type_t::LEGOPF;
else if (!strcmp(str, "LG"))
return decode_type_t::LG;
else if (!strcmp(str, "LG2"))
return decode_type_t::LG2;
else if (!strcmp(str, "LASERTAG"))
return decode_type_t::LASERTAG;
else if (!strcmp(str, "LUTRON"))
return decode_type_t::LUTRON;
else if (!strcmp(str, "MAGIQUEST"))
return decode_type_t::MAGIQUEST;
else if (!strcmp(str, "MIDEA"))
return decode_type_t::MIDEA;
else if (!strcmp(str, "MITSUBISHI"))
return decode_type_t::MITSUBISHI;
else if (!strcmp(str, "MITSUBISHI2"))
return decode_type_t::MITSUBISHI2;
else if (!strcmp(str, "MITSUBISHI_AC"))
return decode_type_t::MITSUBISHI_AC;
else if (!strcmp(str, "MWM"))
return decode_type_t::MWM;
else if (!strcmp(str, "NEC") || !strcmp(str, "NEC (NON-STRICT"))
return decode_type_t::NEC;
else if (!strcmp(str, "NIKAI"))
return decode_type_t::NIKAI;
else if (!strcmp(str, "PANASONIC"))
return decode_type_t::PANASONIC;
else if (!strcmp(str, "PANASONIC_AC"))
return decode_type_t::PANASONIC_AC;
else if (!strcmp(str, "PIONEER"))
return decode_type_t::PIONEER;
else if (!strcmp(str, "PRONTO"))
return decode_type_t::PRONTO;
else if (!strcmp(str, "RAW"))
return decode_type_t::RAW;
else if (!strcmp(str, "RC5"))
return decode_type_t::RC5;
else if (!strcmp(str, "RC5X"))
return decode_type_t::RC5X;
else if (!strcmp(str, "RC6"))
return decode_type_t::RC6;
else if (!strcmp(str, "RCMM"))
return decode_type_t::RCMM;
else if (!strcmp(str, "SAMSUNG"))
return decode_type_t::SAMSUNG;
else if (!strcmp(str, "SAMSUNG36"))
return decode_type_t::SAMSUNG36;
else if (!strcmp(str, "SAMSUNG_AC"))
return decode_type_t::SAMSUNG_AC;
else if (!strcmp(str, "SANYO"))
return decode_type_t::SANYO;
else if (!strcmp(str, "SANYO_LC7461"))
return decode_type_t::SANYO_LC7461;
else if (!strcmp(str, "SHARP"))
return decode_type_t::SHARP;
else if (!strcmp(str, "SHERWOOD"))
return decode_type_t::SHERWOOD;
else if (!strcmp(str, "SONY"))
return decode_type_t::SONY;
else if (!strcmp(str, "TCL112AC"))
return decode_type_t::TCL112AC;
else if (!strcmp(str, "TECO"))
return decode_type_t::TECO;
else if (!strcmp(str, "TOSHIBA_AC"))
return decode_type_t::TOSHIBA_AC;
else if (!strcmp(str, "TROTEC"))
return decode_type_t::TROTEC;
else if (!strcmp(str, "VESTEL_AC"))
return decode_type_t::VESTEL_AC;
else if (!strcmp(str, "WHIRLPOOL_AC"))
return decode_type_t::WHIRLPOOL_AC;
else if (!strcmp(str, "WHYNTER"))
return decode_type_t::WHYNTER;
// Handle integer values of the type by converting to a string and back again.
decode_type_t result = strToDecodeType(
typeToString((decode_type_t)atoi(str)).c_str());
if (result > 0)
return result;
else
return decode_type_t::UNKNOWN;
}
// Escape any special HTML (unsafe) characters in a string. e.g. anti-XSS.
// Args:
// unescaped: A string containing text to make HTML safe.
// Returns:
// A string that is HTML safe.
#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist.
String htmlEscape(const String unescaped) {
String result = "";
#else
std::string htmlEscape(const std::string unescaped) {
std::string result = "";
#endif
uint16_t ulen = unescaped.length();
result.reserve(ulen); // The result will be at least the size of input.
for (size_t i = 0; i < ulen; i++) {
char c = unescaped[i];
switch (c) {
// ';!-"<>=&#{}() are all unsafe.
case '\'':
result += F("&apos;");
break;
case ';':
result += F("&semi;");
break;
case '!':
result += F("&excl;");
break;
case '-':
result += F("&dash;");
break;
case '\"':
result += F("&quot;");
break;
case '<':
result += F("&lt;");
break;
case '>':
result += F("&gt;");
break;
case '=':
result += F("&#equals;");
break;
case '&':
result += F("&amp;");
break;
case '#':
result += F("&num;");
break;
case '{':
result += F("&lcub;");
break;
case '}':
result += F("&rcub;");
break;
case '(':
result += F("&lpar;");
break;
case ')':
result += F("&rpar;");
break;
default:
result += c;
}
}
return result;
}
// Convert a protocol type (enum etc) to a human readable string.
// Args:
// protocol: Nr. (enum) of the protocol.
// isRepeat: A flag indicating if it is a repeat message of the protocol.
// Returns:
// A string containing the protocol name.
#ifdef ARDUINO // Arduino's & C++'s string implementations can't co-exist.
String typeToString(const decode_type_t protocol, const bool isRepeat) {
String result = "";
#else
std::string typeToString(const decode_type_t protocol, const bool isRepeat) {
std::string result = "";
#endif
switch (protocol) {
case UNUSED:
result = F("UNUSED");
break;
case AIWA_RC_T501:
result = F("AIWA_RC_T501");
break;
case ARGO:
result = F("ARGO");
break;
case CARRIER_AC:
result = F("CARRIER_AC");
break;
case COOLIX:
result = F("COOLIX");
break;
case DAIKIN:
result = F("DAIKIN");
break;
case DAIKIN2:
result = F("DAIKIN2");
break;
case DAIKIN216:
result = F("DAIKIN216");
break;
case DENON:
result = F("DENON");
break;
case DISH:
result = F("DISH");
break;
case ELECTRA_AC:
result = F("ELECTRA_AC");
break;
case FUJITSU_AC:
result = F("FUJITSU_AC");
break;
case GICABLE:
result = F("GICABLE");
break;
case GLOBALCACHE:
result = F("GLOBALCACHE");
break;
case GREE:
result = F("GREE");
break;
case HAIER_AC:
result = F("HAIER_AC");
break;
case HAIER_AC_YRW02:
result = F("HAIER_AC_YRW02");
break;
case HITACHI_AC:
result = F("HITACHI_AC");
break;
case HITACHI_AC1:
result = F("HITACHI_AC1");
break;
case HITACHI_AC2:
result = F("HITACHI_AC2");
break;
case JVC:
result = F("JVC");
break;
case KELVINATOR:
result = F("KELVINATOR");
break;
case LEGOPF:
result = F("LEGOPF");
break;
case LG:
result = F("LG");
break;
case LG2:
result = F("LG2");
break;
case LASERTAG:
result = F("LASERTAG");
break;
case LUTRON:
result = F("LUTRON");
break;
case MAGIQUEST:
result = F("MAGIQUEST");
break;
case MIDEA:
result = F("MIDEA");
break;
case MITSUBISHI:
result = F("MITSUBISHI");
break;
case MITSUBISHI2:
result = F("MITSUBISHI2");
break;
case MITSUBISHI_AC:
result = F("MITSUBISHI_AC");
break;
case MITSUBISHI_HEAVY_88:
result = F("MITSUBISHI_HEAVY_88");
break;
case MITSUBISHI_HEAVY_152:
result = F("MITSUBISHI_HEAVY_152");
break;
case MWM:
result = F("MWM");
break;
case NEC:
result = F("NEC");
break;
case NEC_LIKE:
result = F("NEC (non-strict)");
break;
case NIKAI:
result = F("NIKAI");
break;
case PANASONIC:
result = F("PANASONIC");
break;
case PANASONIC_AC:
result = F("PANASONIC_AC");
break;
case PIONEER:
result = F("PIONEER");
break;
case PRONTO:
result = F("PRONTO");
break;
case RAW:
result = F("RAW");
break;
case RC5:
result = F("RC5");
break;
case RC5X:
result = F("RC5X");
break;
case RC6:
result = F("RC6");
break;
case RCMM:
result = F("RCMM");
break;
case SAMSUNG:
result = F("SAMSUNG");
break;
case SAMSUNG36:
result = F("SAMSUNG36");
break;
case SAMSUNG_AC:
result = F("SAMSUNG_AC");
break;
case SANYO:
result = F("SANYO");
break;
case SANYO_LC7461:
result = F("SANYO_LC7461");
break;
case SHARP:
result = F("SHARP");
break;
case SHERWOOD:
result = F("SHERWOOD");
break;
case SONY:
result = F("SONY");
break;
case TCL112AC:
result = F("TCL112AC");
break;
case TECO:
result = F("TECO");
break;
case TOSHIBA_AC:
result = F("TOSHIBA_AC");
break;
case TROTEC:
result = F("TROTEC");
break;
case VESTEL_AC:
result = F("VESTEL_AC");
break;
case WHIRLPOOL_AC:
result = F("WHIRLPOOL_AC");
break;
case WHYNTER:
result = F("WHYNTER");
break;
case UNKNOWN:
default:
result = F("UNKNOWN");
break;
}
if (isRepeat) result += F(" (Repeat)");
return result;
}
// Does the given protocol use a complex state as part of the decode?
bool hasACState(const decode_type_t protocol) {
switch (protocol) {
case DAIKIN:
case DAIKIN2:
case DAIKIN216:
case ELECTRA_AC:
case FUJITSU_AC:
case GREE:
case HAIER_AC:
case HAIER_AC_YRW02:
case HITACHI_AC:
case HITACHI_AC1:
case HITACHI_AC2:
case KELVINATOR:
case MITSUBISHI_AC:
case MITSUBISHI_HEAVY_88:
case MITSUBISHI_HEAVY_152:
case MWM:
case PANASONIC_AC:
case SAMSUNG_AC:
case TCL112AC:
case TOSHIBA_AC:
case WHIRLPOOL_AC:
return true;
default:
return false;
}
}
// Return the corrected length of a 'raw' format array structure
// after over-large values are converted into multiple entries.
// Args:
// results: A ptr to a decode result.
// Returns:
// A uint16_t containing the length.
uint16_t getCorrectedRawLength(const decode_results *results) {
uint16_t extended_length = results->rawlen - 1;
for (uint16_t i = 0; i < results->rawlen - 1; i++) {
uint32_t usecs = results->rawbuf[i] * kRawTick;
// Add two extra entries for multiple larger than UINT16_MAX it is.
extended_length += (usecs / (UINT16_MAX + 1)) * 2;
}
return extended_length;
}
// Return a string containing the key values of a decode_results structure
// in a C/C++ code style format.
#ifdef ARDUINO
String resultToSourceCode(const decode_results *results) {
String output = "";
#else
std::string resultToSourceCode(const decode_results *results) {
std::string output = "";
#endif
// Start declaration
output += F("uint16_t "); // variable type
output += F("rawData["); // array name
output += uint64ToString(getCorrectedRawLength(results), 10);
// array size
output += F("] = {"); // Start declaration
// Dump data
for (uint16_t i = 1; i < results->rawlen; i++) {
uint32_t usecs;
for (usecs = results->rawbuf[i] * kRawTick; usecs > UINT16_MAX;
usecs -= UINT16_MAX) {
output += uint64ToString(UINT16_MAX);
if (i % 2)
output += F(", 0, ");
else
output += F(", 0, ");
}
output += uint64ToString(usecs, 10);
if (i < results->rawlen - 1)
output += F(", "); // ',' not needed on the last one
if (i % 2 == 0) output += ' '; // Extra if it was even.
}
// End declaration
output += F("};");
// Comment
output += F(" // ");
output += typeToString(results->decode_type, results->repeat);
// Only display the value if the decode type doesn't have an A/C state.
if (!hasACState(results->decode_type))
output += ' ' + uint64ToString(results->value, 16);
output += F("\n");
// Now dump "known" codes
if (results->decode_type != UNKNOWN) {
if (hasACState(results->decode_type)) {
#if DECODE_AC
uint16_t nbytes = results->bits / 8;
output += F("uint8_t state[");
output += uint64ToString(nbytes);
output += F("] = {");
for (uint16_t i = 0; i < nbytes; i++) {
output += F("0x");
if (results->state[i] < 0x10) output += '0';
output += uint64ToString(results->state[i], 16);
if (i < nbytes - 1) output += F(", ");
}
output += F("};\n");
#endif // DECODE_AC
} else {
// Simple protocols
// Some protocols have an address &/or command.
// NOTE: It will ignore the atypical case when a message has been
// decoded but the address & the command are both 0.
if (results->address > 0 || results->command > 0) {
output += F("uint32_t address = 0x");
output += uint64ToString(results->address, 16);
output += F(";\n");
output += F("uint32_t command = 0x");
output += uint64ToString(results->command, 16);
output += F(";\n");
}
// Most protocols have data
output += F("uint64_t data = 0x");
output += uint64ToString(results->value, 16);
output += F(";\n");
}
}
return output;
}
// Dump out the decode_results structure.
//
#ifdef ARDUINO
String resultToTimingInfo(const decode_results *results) {
String output = "";
String value = "";
#else
std::string resultToTimingInfo(const decode_results *results) {
std::string output = "";
std::string value = "";
#endif
output += F("Raw Timing[");
output += uint64ToString(results->rawlen - 1, 10);
output += F("]:\n");
for (uint16_t i = 1; i < results->rawlen; i++) {
if (i % 2 == 0)
output += '-'; // even
else
output += F(" +"); // odd
value = uint64ToString(results->rawbuf[i] * kRawTick);
// Space pad the value till it is at least 6 chars long.
while (value.length() < 6) value = ' ' + value;
output += value;
if (i < results->rawlen - 1)
output += F(", "); // ',' not needed for last one
if (!(i % 8)) output += '\n'; // Newline every 8 entries.
}
output += '\n';
return output;
}
// Convert the decode_results structure's value/state to simple hexadecimal.
//
#ifdef ARDUINO
String resultToHexidecimal(const decode_results *result) {
String output = "";
#else
std::string resultToHexidecimal(const decode_results *result) {
std::string output = "";
#endif
if (hasACState(result->decode_type)) {
#if DECODE_AC
for (uint16_t i = 0; result->bits > i * 8; i++) {
if (result->state[i] < 0x10) output += '0'; // Zero pad
output += uint64ToString(result->state[i], 16);
}
#endif // DECODE_AC
} else {
output += uint64ToString(result->value, 16);
}
return output;
}
// Dump out the decode_results structure.
//
#ifdef ARDUINO
String resultToHumanReadableBasic(const decode_results *results) {
String output = "";
#else
std::string resultToHumanReadableBasic(const decode_results *results) {
std::string output = "";
#endif
// Show Encoding standard
output += F("Encoding : ");
output += typeToString(results->decode_type, results->repeat);
output += '\n';
// Show Code & length
output += F("Code : ");
output += resultToHexidecimal(results);
output += F(" (");
output += uint64ToString(results->bits);
output += F(" bits)\n");
return output;
}
uint8_t sumBytes(uint8_t *start, const uint16_t length, const uint8_t init) {
uint8_t checksum = init;
uint8_t *ptr;
for (ptr = start; ptr - start < length; ptr++) checksum += *ptr;
return checksum;
}
uint8_t xorBytes(uint8_t *start, const uint16_t length, const uint8_t init) {
uint8_t checksum = init;
uint8_t *ptr;
for (ptr = start; ptr - start < length; ptr++) checksum ^= *ptr;
return checksum;
}
// Count the number of bits of a certain type.
// Args:
// start: Ptr to the start of data to count bits in.
// length: How many bytes to count.
// ones: Count the binary 1 bits. False for counting the 0 bits.
// init: Start the counting from this value.
// Returns:
// Nr. of bits found.
uint16_t countBits(const uint8_t *start, const uint16_t length, const bool ones,
const uint16_t init) {
uint16_t count = init;
for (uint16_t offset = 0; offset < length; offset++)
for (uint8_t currentbyte = *(start + offset);
currentbyte;
currentbyte >>= 1)
if (currentbyte & 1) count++;
if (ones || length == 0)
return count;
else
return (length * 8) - count;
}
// Count the number of bits of a certain type.
// Args:
// data: The value you want bits counted for, starting from the LSB.
// length: How many bits to count.
// ones: Count the binary 1 bits. False for counting the 0 bits.
// init: Start the counting from this value.
// Returns:
// Nr. of bits found.
uint16_t countBits(const uint64_t data, const uint8_t length, const bool ones,
const uint16_t init) {
uint16_t count = init;
uint8_t bitsSoFar = length;
for (uint64_t remainder = data; remainder && bitsSoFar;
remainder >>= 1, bitsSoFar--)
if (remainder & 1) count++;
if (ones || length == 0)
return count;
else
return length - count;
}
uint64_t invertBits(const uint64_t data, const uint16_t nbits) {
// No change if we are asked to invert no bits.
if (nbits == 0) return data;
uint64_t result = ~data;
// If we are asked to invert all the bits or more than we have, it's simple.
if (nbits >= sizeof(data) * 8) return result;
// Mask off any unwanted bits and return the result.
return (result & ((1ULL << nbits) - 1));
}

View File

@ -24,7 +24,8 @@ String resultToSourceCode(const decode_results *results);
String resultToTimingInfo(const decode_results *results);
String resultToHumanReadableBasic(const decode_results *results);
String resultToHexidecimal(const decode_results *result);
#else
String htmlEscape(const String unescaped);
#else // ARDUINO
std::string uint64ToString(uint64_t input, uint8_t base = 10);
std::string typeToString(const decode_type_t protocol,
const bool isRepeat = false);
@ -32,10 +33,16 @@ std::string resultToSourceCode(const decode_results *results);
std::string resultToTimingInfo(const decode_results *results);
std::string resultToHumanReadableBasic(const decode_results *results);
std::string resultToHexidecimal(const decode_results *result);
#endif
std::string htmlEscape(const std::string unescaped);
#endif // ARDUINO
bool hasACState(const decode_type_t protocol);
uint16_t getCorrectedRawLength(const decode_results *results);
uint8_t sumBytes(uint8_t *start, const uint16_t length, const uint8_t init = 0);
uint8_t xorBytes(uint8_t *start, const uint16_t length, const uint8_t init = 0);
uint16_t countBits(const uint8_t *start, const uint16_t length,
const bool ones = true, const uint16_t init = 0);
uint16_t countBits(const uint64_t data, const uint8_t length,
const bool ones = true, const uint16_t init = 0);
uint64_t invertBits(const uint64_t data, const uint16_t nbits);
decode_type_t strToDecodeType(const char *str);
#endif // IRUTILS_H_

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