diff --git a/.gitignore b/.gitignore index e9c55b5b9..ef1e0a508 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ build firmware.map firmware.asm tasmota*.bin +tasmota*.bin.gz tasmota*.map platformio_override.ini diff --git a/.gitpod.yml b/.gitpod.yml index ee7750c54..8ac16a8ad 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -1,3 +1,3 @@ tasks: - - before: pip install -U platformio + - before: pip3 install -U platformio command: platformio run -e tasmota diff --git a/BUILDS.md b/BUILDS.md index 5cac6108f..aa1834061 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -128,6 +128,7 @@ | | | | | | | | | | USE_IR_REMOTE | - | - | x | x | x | x | x | | USE_IR_RECEIVE | - | - | x | x | x | x | x | +| USE_IR_REMOTE_FULL | - | - | - | - | - | x | - | Enable ALL protocols | | | | | | | | | | USE_SR04 | - | - | x | x | x | - | x | | USE_TM1638 | - | - | - | - | x | - | - | diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 0335fc6e6..f994be9c0 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -52,17 +52,33 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ## Changelog -### Version 8.1.0.2 +### Version 8.1.0.5 - Change Lights: simplified gamma correction and 10 bits internal computation +- Change commands ``Prefix``, ``Ssid``, ``StateText``, ``NTPServer``, and ``FriendlyName`` displaying all items +- Change IRremoteESP8266 library updated to v2.7.3 +- Change Zigbee command prefix from ``Zigbee*`` to ``Zb*`` +- Change wifi connectivity stability (#7602) - Fix Sonoff Bridge, Sc, L1, iFan03 and CSE7766 serial interface to forced speed, config and disable logging - Fix commands ``Display`` and ``Counter`` from overruling command processing (#7322) - Fix ``White`` added to light status (#7142) - Fix Improved fade linearity with gamma correction - Fix LCD line and column positioning (#7387) - Fix Display handling of hexadecimal escape characters (#7387) +- Fix ``WakeUp `` ignores provided value (#7473) +- Fix exception 9 restart on log message in Ticker interrupt service routines NTP, Wemos and Hue emulation (#7496) +- Fix ``PowerDelta`` zero power detection (#7515) +- Fix ``RGBWWTable`` ignored (#7572) +- Fix PWM flickering at low levels (#7415) +- Fix Hass sensor discovery part 1/4 by Federico Leoni (#7582, #7548) +- Fix MaxPower functionality (#7647) - Add command ``SetOption79 0/1`` to enable reset of counters at teleperiod time by Andre Thomas (#7355) +- Add command ``SetOption82 0/1`` to limit the CT range for Alexa to 200..380 +- Add command ``SetOption84 1`` to send AWS IoT device shadow updates (alternative to retained) - Add command ``ShutterButton `` to control shutter(s) by to-scho (#7403) +- Add commands ``SwitchMode 8`` ToggleMulti, ``SwitchMode 9`` FollowMulti and ``SwitchMode 10`` FollowMultiInverted (#7522) +- Add commands ``SwitchMode 11`` PushHoldMulti and ``SwitchMode 12`` PushHoldInverted (#7603) +- Add command ``Buzzer -1`` for infinite mode and command ``Buzzer -2`` for following led mode (#7623) - Add SerialConfig to ``Status 1`` - Add WifiPower to ``Status 5`` - Add support for DS1624, DS1621 Temperature sensor by Leonid Myravjev @@ -71,3 +87,14 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add optional support for Prometheus using file xsns_91_prometheus.ino (#7216) - Add experimental support for NRF24L01 as BLE-bridge for Mijia Bluetooth sensors by Christian Baars (#7394) - Add support to BMP driver to enter reset state (sleep enable) when deep sleep is used in Tasmota +- Add support for gzipped binaries +- Add web page sliders when ``SetOption37 128`` is active allowing control of white(s) +- Add most SetOptions as defines to my_user_config.h +- Add SoftwareSerial to CSE7766 driver allowing different GPIOs (#7563) +- Add optional parameter to command ``Scheme , `` to control initial start color +- Add rule trigger on one level deeper using syntax with two ``#`` like ``on zigbeereceived#vibration_sensor#aqaracubeside=0 do ...`` +- Add support for sensors DS18x20 and DHT family on Shelly 1 and Shelly 1PM using Shelly Add-On adapter (#7469) +- Add support for MI-BLE sensors using HM-10 Bluetooth 4.0 module by Christian Staars (#7683) +- Add BootCount Reset Time as BCResetTime to ``Status 1`` +- Add ``ZbZNPReceived``and ``ZbZCLReceived`` being published to MQTT when ``SetOption66 1`` +- Add optional Wifi AccessPoint passphrase define WIFI_AP_PASSPHRASE in my_user_config.h (#7690) diff --git a/api/upload-arduino.php b/api/upload-arduino.php index 2b472c643..bf1f60846 100644 --- a/api/upload-arduino.php +++ b/api/upload-arduino.php @@ -3,12 +3,46 @@ // //var_dump($_FILES); +/** + * GZIPs a file on disk (appending .gz to the name) + * + * From http://stackoverflow.com/questions/6073397/how-do-you-create-a-gz-file-using-php + * Based on function by Kioob at: + * http://www.php.net/manual/en/function.gzwrite.php#34955 + * + * @param string $source Path to file that should be compressed + * @param integer $level GZIP compression level (default: 9) + * @return string New filename (with .gz appended) if success, or false if operation fails + */ +function gzCompressFile($source, $level = 9){ + $dest = $source . '.gz'; + $mode = 'wb' . $level; + $error = false; + if ($fp_out = gzopen($dest, $mode)) { + if ($fp_in = fopen($source,'rb')) { + while (!feof($fp_in)) + gzwrite($fp_out, fread($fp_in, 1024 * 512)); + fclose($fp_in); + } else { + $error = true; + } + gzclose($fp_out); + } else { + $error = true; + } + if ($error) + return false; + else + return $dest; +} + $image = basename($_FILES["file"]["name"]); $target_file = "arduino/".$image; $hostname = $_SERVER['SERVER_NAME']; if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) { - echo "The file $image has been uploaded to OTA server $hostname. \n"; + gzCompressFile($target_file); + echo "The files $image and $image.gz have been uploaded to OTA server $hostname. \n"; } else { echo "Sorry, there was an error uploading your file $image to OTA server $hostname. \n"; } diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_LG.h b/lib/IRremoteESP8266-2.7.1/src/ir_LG.h deleted file mode 100644 index 01f81e2c1..000000000 --- a/lib/IRremoteESP8266-2.7.1/src/ir_LG.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2017 David Conran - -// Supports: -// Brand: LG, Model: 6711A20083V remote -// Brand: LG, Model: AKB74395308 remote - -#ifndef IR_LG_H_ -#define IR_LG_H_ - -#define __STDC_LIMIT_MACROS -#include - -uint8_t calcLGChecksum(uint16_t data); - -#endif // IR_LG_H_ diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_NEC.h b/lib/IRremoteESP8266-2.7.1/src/ir_NEC.h deleted file mode 100644 index e45ff702c..000000000 --- a/lib/IRremoteESP8266-2.7.1/src/ir_NEC.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2009 Ken Shirriff -// Copyright 2017, 2018 David Conran - -// NEC originally added from https://github.com/shirriff/Arduino-IRremote/ - -#ifndef IR_NEC_H_ -#define IR_NEC_H_ - -#include -#include "IRremoteESP8266.h" - -// Supports: -// Brand: Yamaha, Model: RAV561 remote -// Brand: Yamaha, Model: RXV585B A/V Receiver - -// Constants -// Ref: -// http://www.sbprojects.com/knowledge/ir/nec.php -const uint16_t kNecTick = 560; -const uint16_t kNecHdrMarkTicks = 16; -const uint16_t kNecHdrMark = kNecHdrMarkTicks * kNecTick; -const uint16_t kNecHdrSpaceTicks = 8; -const uint16_t kNecHdrSpace = kNecHdrSpaceTicks * kNecTick; -const uint16_t kNecBitMarkTicks = 1; -const uint16_t kNecBitMark = kNecBitMarkTicks * kNecTick; -const uint16_t kNecOneSpaceTicks = 3; -const uint16_t kNecOneSpace = kNecOneSpaceTicks * kNecTick; -const uint16_t kNecZeroSpaceTicks = 1; -const uint16_t kNecZeroSpace = kNecZeroSpaceTicks * kNecTick; -const uint16_t kNecRptSpaceTicks = 4; -const uint16_t kNecRptSpace = kNecRptSpaceTicks * kNecTick; -const uint16_t kNecRptLength = 4; -const uint16_t kNecMinCommandLengthTicks = 193; -const uint32_t kNecMinCommandLength = kNecMinCommandLengthTicks * kNecTick; -const uint32_t kNecMinGap = - kNecMinCommandLength - - (kNecHdrMark + kNecHdrSpace + kNECBits * (kNecBitMark + kNecOneSpace) + - kNecBitMark); -const uint16_t kNecMinGapTicks = - kNecMinCommandLengthTicks - - (kNecHdrMarkTicks + kNecHdrSpaceTicks + - kNECBits * (kNecBitMarkTicks + kNecOneSpaceTicks) + kNecBitMarkTicks); - -#endif // IR_NEC_H_ diff --git a/lib/IRremoteESP8266-2.7.1/CPPLINT.cfg b/lib/IRremoteESP8266-2.7.3/CPPLINT.cfg similarity index 100% rename from lib/IRremoteESP8266-2.7.1/CPPLINT.cfg rename to lib/IRremoteESP8266-2.7.3/CPPLINT.cfg diff --git a/lib/IRremoteESP8266-2.7.1/LICENSE.txt b/lib/IRremoteESP8266-2.7.3/LICENSE.txt similarity index 100% rename from lib/IRremoteESP8266-2.7.1/LICENSE.txt rename to lib/IRremoteESP8266-2.7.3/LICENSE.txt diff --git a/lib/IRremoteESP8266-2.7.1/README.md b/lib/IRremoteESP8266-2.7.3/README.md similarity index 98% rename from lib/IRremoteESP8266-2.7.1/README.md rename to lib/IRremoteESP8266-2.7.3/README.md index e06c8fb79..9ca606af8 100644 --- a/lib/IRremoteESP8266-2.7.1/README.md +++ b/lib/IRremoteESP8266-2.7.3/README.md @@ -9,8 +9,8 @@ This library enables you to **send _and_ receive** infra-red signals on an [ESP8266](https://github.com/esp8266/Arduino) or an [ESP32](https://github.com/espressif/arduino-esp32) using the [Arduino framework](https://www.arduino.cc/) using common 940nm IR LEDs and common IR receiver modules. e.g. TSOP{17,22,24,36,38,44,48}* demodulators etc. -## v2.7.1 Now Available -Version 2.7.1 of the library is now [available](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes. +## v2.7.3 Now Available +Version 2.7.3 of the library is now [available](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). You can view the [Release Notes](ReleaseNotes.md) for all the significant changes. #### Upgrading from pre-v2.0 Usage of the library has been slightly changed in v2.0. You will need to change your usage to work with v2.0 and beyond. You can read more about the changes required on our [Upgrade to v2.0](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Upgrading-to-v2.0) page. diff --git a/lib/IRremoteESP8266-2.7.1/README_fr.md b/lib/IRremoteESP8266-2.7.3/README_fr.md similarity index 98% rename from lib/IRremoteESP8266-2.7.1/README_fr.md rename to lib/IRremoteESP8266-2.7.3/README_fr.md index b24d935c5..ca31b3b7b 100644 --- a/lib/IRremoteESP8266-2.7.1/README_fr.md +++ b/lib/IRremoteESP8266-2.7.3/README_fr.md @@ -9,8 +9,8 @@ Cette librairie vous permetra de **recevoir et d'envoyer des signaux** infrarouge sur le protocole [ESP8266](https://github.com/esp8266/Arduino) ou sur le protocole [ESP32](https://github.com/espressif/arduino-esp32) en utilisant le [Arduino framework](https://www.arduino.cc/) qui utilise la norme 940nm IR LEDs et le module basique de reception d'onde IR. Exemple : TSOP{17,22,24,36,38,44,48}* modules etc. -## v2.7.1 disponible -Version 2.7.1 de la libraire est maintenant [disponible](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Vous pouvez voir le [Release Notes](ReleaseNotes.md) pour tous les changements importants. +## v2.7.3 disponible +Version 2.7.3 de la libraire est maintenant [disponible](https://github.com/crankyoldgit/IRremoteESP8266/releases/latest). Vous pouvez voir le [Release Notes](ReleaseNotes.md) pour tous les changements importants. #### mise à jour depuis pre-v2.0 L'utilisation de la librairie à un peu changer depuis la version in v2.0. Si vous voulez l'utiliser vous devrez changer votre utilisation aussi. Vous pouvez vous renseigner sur les précondition d'utilisation ici : [Upgrade to v2.0](https://github.com/crankyoldgit/IRremoteESP8266/wiki/Upgrading-to-v2.0) page. diff --git a/lib/IRremoteESP8266-2.7.1/ReleaseNotes.md b/lib/IRremoteESP8266-2.7.3/ReleaseNotes.md similarity index 95% rename from lib/IRremoteESP8266-2.7.1/ReleaseNotes.md rename to lib/IRremoteESP8266-2.7.3/ReleaseNotes.md index 537960ac9..a7218fc07 100644 --- a/lib/IRremoteESP8266-2.7.1/ReleaseNotes.md +++ b/lib/IRremoteESP8266-2.7.3/ReleaseNotes.md @@ -1,5 +1,35 @@ # Release Notes +## _v2.7.3 (20200130)_ + +**[Features]** +- Allow protocols to be enabled or disabled with compiler flags. (#1013, #1012) +- Panasonic AC: Add Ion Filter support for DKE models. (#1025, #1024) +- Add support for sending Sony at 38Khz (#1029, #1018, #1019) +- auto_analyse_raw_data.py: Handle analysing messages with no headers. (#1017) + +**[Misc]** +- Fix Coolix unit test errors when using Apple c++ compiler. (#1030, #1028) +- Fix Apple clang c++ compiler error in unit tests. (#1027, #1026) +- Improve/fix scraping of supported devices (#1022) +- Panasonic PKR series A/C uses DKE protocol. (#1020, #1021) +- Update NEC supported devices. (#1018) +- Add note to avoid GPIO16 on the ESP8266 for receiving. (#1016, #1015) + + +## _v2.7.2 (20200106)_ + +**[Bug Fixes]** +- Common AC api: Better handle protocols with power toggles. (#1002) + +**[Features]** +- Experimental detailed support for LG a/c. (#1008 #1009) + +**[Misc]** +- Add remote codes for Aloka LED lamp. (#1005) +- Improve Supported Devices scraping. (#1006) + + ## _v2.7.1 (20191125)_ **[Bug Fixes]** diff --git a/lib/IRremoteESP8266-2.7.1/SupportedProtocols.md b/lib/IRremoteESP8266-2.7.3/SupportedProtocols.md similarity index 87% rename from lib/IRremoteESP8266-2.7.1/SupportedProtocols.md rename to lib/IRremoteESP8266-2.7.3/SupportedProtocols.md index 02d51093a..c9b2f85c7 100644 --- a/lib/IRremoteESP8266-2.7.1/SupportedProtocols.md +++ b/lib/IRremoteESP8266-2.7.3/SupportedProtocols.md @@ -1,6 +1,6 @@ + Last generated: Thu Jan 30 20:05:33 2020 ---> # IR Protocols supported by this library | Protocol | Brand | Model | A/C Model | Detailed A/C Support | @@ -11,42 +11,45 @@ | [Carrier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Carrier.cpp) | **Carrier/Surrey** | 42QG5A55970 remote
53NGK009/012 Inverter
619EGX0090E0 A/C
619EGX0120E0 A/C
619EGX0180E0 A/C
619EGX0220E0 A/C | | - | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Beko](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | BINR 070/071 split-type A/C
BINR 070/071 split-type A/C
RG57K7(B)/BGEF Remote
RG57K7(B)/BGEF Remote | | Yes | | [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | MS12FU-10HRDN1-QRD0GW(B) A/C
MS12FU-10HRDN1-QRD0GW(B) A/C
MSABAU-07HRFN1-QRD0GW A/C (circa 2016)
MSABAU-07HRFN1-QRD0GW A/C (circa 2016)
RG52D/BGE Remote
RG52D/BGE Remote | | Yes | -| [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Tokio](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | AATOEMF17-12CHR1SW split-type RG51|50/BGE Remote
AATOEMF17-12CHR1SW split-type RG51|50/BGE Remote | | Yes | +| [Coolix](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Tokio](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | AATOEMF17-12CHR1SW split-type RG51\|50/BGE Remote
AATOEMF17-12CHR1SW split-type RG51\|50/BGE Remote | | Yes | | [Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.cpp) | **[Daikin](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Daikin.h)** | 17 Series A/C (DAIKIN128)
ARC423A5 remote
ARC433** remote
ARC433B69 remote
ARC477A1 remote
ARC480A5 remote (DAIKIN152)
BRC4C153 remote
BRC52B63 remote (DAIKIN128)
FTE12HV2S A/C
FTXB09AXVJU A/C (DAIKIN128)
FTXB12AXVJU A/C (DAIKIN128)
FTXZ25NV1B A/C
FTXZ35NV1B A/C
FTXZ50NV1B A/C | | Yes | | [Denon](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Denon.cpp) | **Unknown** | | | - | | [Dish](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Dish.cpp) | **DISH NETWORK** | echostar 301 | | - | | [Electra](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **[AUX](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Electra.h)** | KFR-35GW/BpNFW=3 A/C
YKR-T/011 remote | | Yes | -| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AGTV14LAC A/C
AR-DB1 remote
AR-DL10 remote
AR-RAC1E remote
AR-RAE1E remote
AR-RAH2E remote
AR-REB1E remote
AR-RY4 remote
AST9RSGCW A/C
ASTB09LBC A/C
ASU30C1 A/C
ASYG30LFCA A/C
ASYG7LMCA A/C | | Yes | -| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu General](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AR-JW2 remote | | Yes | +| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AGTV14LAC A/C
AR-DB1 remote
AR-DL10 remote
AR-RAC1E remote
AR-RAE1E remote
AR-RAH2E remote
AR-REB1E remote
AR-RY4 remote
AST9RSGCW A/C
ASTB09LBC A/C
ASU30C1 A/C
ASYG30LFCA A/C
ASYG7LMCA A/C | ARDB1
ARJW2
ARRAH2E
ARREB1E
ARRY4 | Yes | +| [Fujitsu](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu General](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AR-JW2 remote | ARDB1
ARJW2
ARRAH2E
ARREB1E
ARRY4 | Yes | | [GICable](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GICable.cpp) | **Unknown** | | | - | | [GlobalCache](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_GlobalCache.cpp) | **Unknown** | | | - | | [Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.cpp) | **[Goodweather](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Goodweather.h)** | ZH/JT-03 remote | | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[EKOKAI](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | A/C | | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YBOFB remote
YBOFB2 remote | | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[RusClimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | EACS/I-09HAR_X/N3 A/C
YAW1F remote | | Yes | -| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Ultimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | Heat Pump | | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[EKOKAI](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | A/C | YAW1F
YBOFB | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | YBOFB remote
YBOFB2 remote | YAW1F
YBOFB | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[RusClimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | EACS/I-09HAR_X/N3 A/C
YAW1F remote | YAW1F
YBOFB | Yes | +| [Gree](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Ultimate](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Gree.h)** | Heat Pump | YAW1F
YBOFB | Yes | | [Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Haier](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Haier.h)** | HSU-09HMC203 A/C
HSU07-HEA03 remote
YR-W02 remote | | Yes | | [Hitachi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.cpp) | **[Hitachi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Hitachi.h)** | LT0541-HTA remote
RAR-8P2 remote
RAS-35THA6 remote
RAS-AJ25H A/C
Series VI A/C (Circa 2007) | | Yes | | [Inax](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Inax.cpp) | **Lixil** | Inax DT-BA283 Toilet | | - | | [JVC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_JVC.cpp) | **Unknown** | | | - | | [Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Green](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.h)** | YAPOF3 remote | | Yes | | [Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Kelvinator](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Kelvinator.h)** | KSV26CRC A/C
KSV26HRC A/C
KSV35CRC A/C
KSV35HRC A/C
KSV53HRC A/C
KSV62HRC A/C
KSV70CRC A/C
KSV70HRC A/C
KSV80HRC A/C
YALIF Remote | | Yes | -| [LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711A20083V remote
6711A20083V remote
AKB74395308 remote
AKB74395308 remote | | Yes | +| [LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[General Electric](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711AR2853M A/C Remote
AG1BH09AW101 Split A/C | | Yes | +| [LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[LG](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711A20083V remote
6711A20083V remote
AKB74395308 remote
AKB74395308 remote
AKB75215403 remote (LG2)
S4-W12JA3AA A/C (LG2) | | Yes | | [Lasertag](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Lasertag.cpp) | **Unknown** | | | - | | [Lego](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Lego.cpp) | **LEGO Power Functions** | IR Receiver | | - | | [Lutron](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Lutron.cpp) | **Unknown** | | | - | | [MWM](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MWM.cpp) | **Unknown** | | | - | -| [Magiquest](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Magiquest.cpp) | **[Unknown](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Magiquest.h)** | | | Yes | +| [Magiquest](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Magiquest.cpp) | **[Unknown](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Magiquest.h)** | | | - | | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Comfee](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | MPD1-12CRN7 A/C | | Yes | | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Keystone](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RG57H4(B)BGEF remote | | Yes | | [Midea](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Pioneer System](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RUBO18GMFILCAD A/C (18K BTU)
RYBO12GMFILCAD A/C (12K BTU) | | Yes | | [Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | HC3000 Projector
KM14A 0179213 remote
MS-GK24VA A/C
TV | | Yes | | [Mitsubishi](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi Electric](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | 001CP T7WE10714 remote
KPOA remote
MSH-A24WV / MUH-A24WV A/C
PEAD-RP71JAA Ducted A/C | | Yes | | [MitsubishiHeavy](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MitsubishiHeavy.cpp) | **[Mitsubishi Heavy Industries](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_MitsubishiHeavy.h)** | RKX502A001C remote
RLA502A700B remote
SRKxxZJ-S A/C
SRKxxZM-S A/C
SRKxxZMXA-S A/C | | Yes | -| [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Yamaha](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | RAV561 remote
RXV585B A/V Receiver | | Yes | +| [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Aloka](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | SleepyLights LED Lamp | | - | +| [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Toshiba](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | 42TL838 LCD TV | | - | +| [NEC](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Yamaha](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_NEC.h)** | RAV561 remote
RXV585B A/V Receiver | | - | | [Neoclima](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Neoclima.cpp) | **[Neoclima](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Neoclima.h)** | NS-09AHTI A/C
NS-09AHTI A/C
ZH/TY-01 remote
ZH/TY-01 remote | | Yes | | [Nikai](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Nikai.cpp) | **Unknown** | | | - | -| [Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.cpp) | **[Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.h)** | A75C2311 remote (CKP)
A75C3704 remote
A75C3747 remote
A75C3747 remote
A75C3747 remote
A75C3747 remote
CKP series A/C
CS-ME10CKPG A/C
CS-ME12CKPG A/C
CS-ME14CKPG A/C
CS-YW9MKD A/C
CS-Z9RKR A/C
DKE series A/C
JKE series A/C
NKE series A/C
RKR series A/C
TV | | Yes | +| [Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.cpp) | **[Panasonic](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Panasonic.h)** | A75C2311 remote (CKP)
A75C2616-1 remote (DKE)
A75C3704 remote
A75C3747 remote
CKP series A/C
CS-E7PKR A/C (DKE)
CS-ME10CKPG A/C
CS-ME12CKPG A/C
CS-ME14CKPG A/C
CS-YW9MKD A/C
CS-Z9RKR A/C
DKE series A/C
DKW series A/C (DKE)
JKE series A/C
NKE series A/C
PKR series A/C (DKE)
RKR series A/C
TV | CKP
DKE
JKE
LKE
NKE
RKR | Yes | | [Pioneer](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Pioneer.cpp) | **Unknown** | | | - | | [Pronto](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Pronto.cpp) | **Unknown** | | | - | | [RC5_RC6](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_RC5_RC6.cpp) | **Unknown** | | | - | @@ -55,24 +58,23 @@ | [Sanyo](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sanyo.cpp) | **Unknown** | | | - | | [Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.cpp) | **[Sharp](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sharp.h)** | AY-ZP40KR A/C
LC-52D62U TV | | Yes | | [Sherwood](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sherwood.cpp) | **Sherwood** | RC-138 remote
RD6505(B) Receiver | | - | -| [Sony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sony.cpp) | **Unknown** | | | - | +| [Sony](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Sony.cpp) | **Sony** | HT-CT380 Soundbar (Uses 38kHz & 3 repeats) | | - | | [Tcl](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[Leberg](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | LBS-TOR07 A/C | | Yes | | [Teco](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Teco.cpp) | **[Alaska](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Teco.h)** | SAC9010QC A/C
SAC9010QC remote | | Yes | | [Toshiba](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Toshiba.cpp) | **[Toshiba](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Toshiba.h)** | Akita EVO II
RAS 18SKP-ES
RAS-B13N3KV2
RAS-B13N3KVP-E
WC-L03SE
WH-TA04NE | | Yes | | [Trotec](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Trotec.cpp) | **[Unknown](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Trotec.h)** | | | Yes | | [Vestel](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Vestel.cpp) | **[Vestel](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Vestel.h)** | BIOX CXP-9 A/C (9K BTU) | | Yes | -| [Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.cpp) | **[Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.h)** | DG11J1-04 remote
DG11J1-3A remote
DG11J1-91 remote
SPIS409L A/C
SPIS412L A/C
SPIW409L A/C
SPIW412L A/C
SPIW418L A/C | | Yes | +| [Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.cpp) | **[Whirlpool](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whirlpool.h)** | DG11J1-04 remote
DG11J1-3A remote
DG11J1-91 remote
SPIS409L A/C
SPIS412L A/C
SPIW409L A/C
SPIW412L A/C
SPIW418L A/C | DG11J13A
DG11J191 | Yes | | [Whynter](https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Whynter.cpp) | **Whynter** | ARC-110WD A/C | | - | ## Send only protocols: - GLOBALCACHE -- MITSUBISHI112 - PRONTO - RAW - SHERWOOD -- TCL112AC +- SONY_38K ## Send & decodable protocols: @@ -113,6 +115,7 @@ - MAGIQUEST - MIDEA - MITSUBISHI +- MITSUBISHI112 - MITSUBISHI136 - MITSUBISHI2 - MITSUBISHI_AC @@ -138,10 +141,10 @@ - SHARP - SHARP_AC - SONY +- TCL112AC - TECO - TOSHIBA_AC - TROTEC - VESTEL_AC - WHIRLPOOL_AC - WHYNTER -- typeguess diff --git a/lib/IRremoteESP8266-2.7.1/examples/CommonAcControl/CommonAcControl.ino b/lib/IRremoteESP8266-2.7.3/examples/CommonAcControl/CommonAcControl.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/CommonAcControl/CommonAcControl.ino rename to lib/IRremoteESP8266-2.7.3/examples/CommonAcControl/CommonAcControl.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/CommonAcControl/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/CommonAcControl/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/CommonAcControl/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/CommonAcControl/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/ControlSamsungAC/ControlSamsungAC.ino b/lib/IRremoteESP8266-2.7.3/examples/ControlSamsungAC/ControlSamsungAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/ControlSamsungAC/ControlSamsungAC.ino rename to lib/IRremoteESP8266-2.7.3/examples/ControlSamsungAC/ControlSamsungAC.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/ControlSamsungAC/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/ControlSamsungAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/ControlSamsungAC/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/ControlSamsungAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/DumbIRRepeater/DumbIRRepeater.ino b/lib/IRremoteESP8266-2.7.3/examples/DumbIRRepeater/DumbIRRepeater.ino similarity index 96% rename from lib/IRremoteESP8266-2.7.1/examples/DumbIRRepeater/DumbIRRepeater.ino rename to lib/IRremoteESP8266-2.7.3/examples/DumbIRRepeater/DumbIRRepeater.ino index 80f5ce64a..d3ddbdb6a 100644 --- a/lib/IRremoteESP8266-2.7.1/examples/DumbIRRepeater/DumbIRRepeater.ino +++ b/lib/IRremoteESP8266-2.7.3/examples/DumbIRRepeater/DumbIRRepeater.ino @@ -37,6 +37,8 @@ * * Pin 0/D3: Can interfere with the boot/program mode & support circuits. * * Pin 1/TX/TXD0: Any serial transmissions from the ESP will interfere. * * Pin 3/RX/RXD0: Any serial transmissions to the ESP will interfere. + * * Pin 16/D0: Has no interrupts on the ESP8266, so can't be used for IR + * receiving with this library. * * ESP-01 modules are tricky. We suggest you use a module with more GPIOs * for your first time. e.g. ESP-12 etc. * @@ -54,6 +56,7 @@ // ==================== start of TUNEABLE PARAMETERS ==================== // The GPIO an IR detector/demodulator is connected to. Recommended: 14 (D5) +// Note: GPIO 16 won't work on the ESP8266 as it does not have interrupts. const uint16_t kRecvPin = 14; // GPIO to use to control the IR LED circuit. Recommended: 4 (D2). diff --git a/lib/IRremoteESP8266-2.7.1/examples/DumbIRRepeater/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/DumbIRRepeater/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/DumbIRRepeater/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/DumbIRRepeater/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRGCSendDemo/IRGCSendDemo.ino b/lib/IRremoteESP8266-2.7.3/examples/IRGCSendDemo/IRGCSendDemo.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRGCSendDemo/IRGCSendDemo.ino rename to lib/IRremoteESP8266-2.7.3/examples/IRGCSendDemo/IRGCSendDemo.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRGCSendDemo/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/IRGCSendDemo/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRGCSendDemo/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/IRGCSendDemo/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRGCTCPServer/IRGCTCPServer.ino b/lib/IRremoteESP8266-2.7.3/examples/IRGCTCPServer/IRGCTCPServer.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRGCTCPServer/IRGCTCPServer.ino rename to lib/IRremoteESP8266-2.7.3/examples/IRGCTCPServer/IRGCTCPServer.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRGCTCPServer/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/IRGCTCPServer/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRGCTCPServer/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/IRGCTCPServer/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRMQTTServer/IRMQTTServer.h b/lib/IRremoteESP8266-2.7.3/examples/IRMQTTServer/IRMQTTServer.h similarity index 99% rename from lib/IRremoteESP8266-2.7.1/examples/IRMQTTServer/IRMQTTServer.h rename to lib/IRremoteESP8266-2.7.3/examples/IRMQTTServer/IRMQTTServer.h index c9d4898b9..0693a4908 100644 --- a/lib/IRremoteESP8266-2.7.1/examples/IRMQTTServer/IRMQTTServer.h +++ b/lib/IRremoteESP8266-2.7.3/examples/IRMQTTServer/IRMQTTServer.h @@ -47,6 +47,7 @@ const int8_t kDefaultIrLed = 4; // <=- CHANGE_ME (optional) const bool kInvertTxOutput = false; // Default GPIO the IR demodulator is connected to/controlled by. GPIO 14 = D5. +// Note: GPIO 16 won't work on the ESP8266 as it does not have interrupts. const int8_t kDefaultIrRx = 14; // <=- CHANGE_ME (optional) // Enable/disable receiving/decoding IR messages entirely. diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRMQTTServer/IRMQTTServer.ino b/lib/IRremoteESP8266-2.7.3/examples/IRMQTTServer/IRMQTTServer.ino similarity index 99% rename from lib/IRremoteESP8266-2.7.1/examples/IRMQTTServer/IRMQTTServer.ino rename to lib/IRremoteESP8266-2.7.3/examples/IRMQTTServer/IRMQTTServer.ino index dfb1aa044..1824c660a 100644 --- a/lib/IRremoteESP8266-2.7.1/examples/IRMQTTServer/IRMQTTServer.ino +++ b/lib/IRremoteESP8266-2.7.3/examples/IRMQTTServer/IRMQTTServer.ino @@ -271,7 +271,7 @@ * * #### Home Assistant MQTT Discovery * There is an option for this: 'Send MQTT Discovery' under the 'Admin' menu. - * It will produce a single MQTT Cliamte Discovery message for Home Assistant + * It will produce a single MQTT Climate Discovery message for Home Assistant * provided you have everything configured correctly here and in HA. * This message has MQTT RETAIN set on it, so it only ever needs to be sent * once or if the config details change etc. diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRMQTTServer/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/IRMQTTServer/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRMQTTServer/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/IRMQTTServer/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRServer/IRServer.ino b/lib/IRremoteESP8266-2.7.3/examples/IRServer/IRServer.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRServer/IRServer.ino rename to lib/IRremoteESP8266-2.7.3/examples/IRServer/IRServer.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRServer/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/IRServer/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRServer/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/IRServer/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRrecvDemo/IRrecvDemo.ino b/lib/IRremoteESP8266-2.7.3/examples/IRrecvDemo/IRrecvDemo.ino similarity index 95% rename from lib/IRremoteESP8266-2.7.1/examples/IRrecvDemo/IRrecvDemo.ino rename to lib/IRremoteESP8266-2.7.3/examples/IRrecvDemo/IRrecvDemo.ino index 5fd03f4b4..945f94055 100644 --- a/lib/IRremoteESP8266-2.7.1/examples/IRrecvDemo/IRrecvDemo.ino +++ b/lib/IRremoteESP8266-2.7.3/examples/IRrecvDemo/IRrecvDemo.ino @@ -23,6 +23,7 @@ // An IR detector/demodulator is connected to GPIO pin 14(D5 on a NodeMCU // board). +// Note: GPIO 16 won't work on the ESP8266 as it does not have interrupts. const uint16_t kRecvPin = 14; IRrecv irrecv(kRecvPin); diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRrecvDemo/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/IRrecvDemo/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRrecvDemo/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/IRrecvDemo/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRrecvDump/IRrecvDump.ino b/lib/IRremoteESP8266-2.7.3/examples/IRrecvDump/IRrecvDump.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRrecvDump/IRrecvDump.ino rename to lib/IRremoteESP8266-2.7.3/examples/IRrecvDump/IRrecvDump.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRrecvDump/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/IRrecvDump/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRrecvDump/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/IRrecvDump/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRrecvDumpV2/IRrecvDumpV2.ino b/lib/IRremoteESP8266-2.7.3/examples/IRrecvDumpV2/IRrecvDumpV2.ino similarity index 98% rename from lib/IRremoteESP8266-2.7.1/examples/IRrecvDumpV2/IRrecvDumpV2.ino rename to lib/IRremoteESP8266-2.7.3/examples/IRrecvDumpV2/IRrecvDumpV2.ino index fc61f9b84..beed6c746 100644 --- a/lib/IRremoteESP8266-2.7.1/examples/IRrecvDumpV2/IRrecvDumpV2.ino +++ b/lib/IRremoteESP8266-2.7.3/examples/IRrecvDumpV2/IRrecvDumpV2.ino @@ -34,6 +34,7 @@ // ==================== start of TUNEABLE PARAMETERS ==================== // An IR detector/demodulator is connected to GPIO pin 14 // e.g. D5 on a NodeMCU board. +// Note: GPIO 16 won't work on the ESP8266 as it does not have interrupts. const uint16_t kRecvPin = 14; // The Serial connection baud rate. diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRrecvDumpV2/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/IRrecvDumpV2/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRrecvDumpV2/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/IRrecvDumpV2/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRsendDemo/IRsendDemo.ino b/lib/IRremoteESP8266-2.7.3/examples/IRsendDemo/IRsendDemo.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRsendDemo/IRsendDemo.ino rename to lib/IRremoteESP8266-2.7.3/examples/IRsendDemo/IRsendDemo.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRsendDemo/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/IRsendDemo/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRsendDemo/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/IRsendDemo/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRsendProntoDemo/IRsendProntoDemo.ino b/lib/IRremoteESP8266-2.7.3/examples/IRsendProntoDemo/IRsendProntoDemo.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRsendProntoDemo/IRsendProntoDemo.ino rename to lib/IRremoteESP8266-2.7.3/examples/IRsendProntoDemo/IRsendProntoDemo.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/IRsendProntoDemo/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/IRsendProntoDemo/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/IRsendProntoDemo/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/IRsendProntoDemo/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino b/lib/IRremoteESP8266-2.7.3/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino rename to lib/IRremoteESP8266-2.7.3/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/JVCPanasonicSendDemo/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/JVCPanasonicSendDemo/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/JVCPanasonicSendDemo/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/JVCPanasonicSendDemo/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/LGACSend/LGACSend.ino b/lib/IRremoteESP8266-2.7.3/examples/LGACSend/LGACSend.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/LGACSend/LGACSend.ino rename to lib/IRremoteESP8266-2.7.3/examples/LGACSend/LGACSend.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/LGACSend/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/LGACSend/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/LGACSend/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/LGACSend/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/SmartIRRepeater/SmartIRRepeater.ino b/lib/IRremoteESP8266-2.7.3/examples/SmartIRRepeater/SmartIRRepeater.ino similarity index 96% rename from lib/IRremoteESP8266-2.7.1/examples/SmartIRRepeater/SmartIRRepeater.ino rename to lib/IRremoteESP8266-2.7.3/examples/SmartIRRepeater/SmartIRRepeater.ino index 8dd202382..576abb516 100644 --- a/lib/IRremoteESP8266-2.7.1/examples/SmartIRRepeater/SmartIRRepeater.ino +++ b/lib/IRremoteESP8266-2.7.3/examples/SmartIRRepeater/SmartIRRepeater.ino @@ -40,6 +40,8 @@ * * Pin 0/D3: Can interfere with the boot/program mode & support circuits. * * Pin 1/TX/TXD0: Any serial transmissions from the ESP will interfere. * * Pin 3/RX/RXD0: Any serial transmissions to the ESP will interfere. + * * Pin 16/D0: Has no interrupts on the ESP8266, so can't be used for IR + * receiving with this library. * * ESP-01 modules are tricky. We suggest you use a module with more GPIOs * for your first time. e.g. ESP-12 etc. * @@ -57,6 +59,7 @@ // ==================== start of TUNEABLE PARAMETERS ==================== // The GPIO an IR detector/demodulator is connected to. Recommended: 14 (D5) +// Note: GPIO 16 won't work on the ESP8266 as it does not have interrupts. const uint16_t kRecvPin = 14; // GPIO to use to control the IR LED circuit. Recommended: 4 (D2). diff --git a/lib/IRremoteESP8266-2.7.1/examples/SmartIRRepeater/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/SmartIRRepeater/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/SmartIRRepeater/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/SmartIRRepeater/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnArgoAC/TurnOnArgoAC.ino b/lib/IRremoteESP8266-2.7.3/examples/TurnOnArgoAC/TurnOnArgoAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnArgoAC/TurnOnArgoAC.ino rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnArgoAC/TurnOnArgoAC.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnArgoAC/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/TurnOnArgoAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnArgoAC/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnArgoAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino b/lib/IRremoteESP8266-2.7.3/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnDaikinAC/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/TurnOnDaikinAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnDaikinAC/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnDaikinAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino b/lib/IRremoteESP8266-2.7.3/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnFujitsuAC/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/TurnOnFujitsuAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnFujitsuAC/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnFujitsuAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino b/lib/IRremoteESP8266-2.7.3/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnKelvinatorAC/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/TurnOnKelvinatorAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnKelvinatorAC/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnKelvinatorAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino b/lib/IRremoteESP8266-2.7.3/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnMitsubishiAC/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/TurnOnMitsubishiAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnMitsubishiAC/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnMitsubishiAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino b/lib/IRremoteESP8266-2.7.3/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnMitsubishiHeavyAc/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/TurnOnMitsubishiHeavyAc/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnMitsubishiHeavyAc/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnMitsubishiHeavyAc/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino b/lib/IRremoteESP8266-2.7.3/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnPanasonicAC/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/TurnOnPanasonicAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnPanasonicAC/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnPanasonicAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino b/lib/IRremoteESP8266-2.7.3/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnToshibaAC/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/TurnOnToshibaAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnToshibaAC/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnToshibaAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino b/lib/IRremoteESP8266-2.7.3/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/TurnOnTrotecAC/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/TurnOnTrotecAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/TurnOnTrotecAC/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/TurnOnTrotecAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/README.md b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/README.md similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/README.md rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/README.md diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/Web-AC-control.ino b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/Web-AC-control.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/Web-AC-control.ino rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/Web-AC-control.ino diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/platformio.ini b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/platformio.ini rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/printscreen.png b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/printscreen.png similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/printscreen.png rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/printscreen.png diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/favicon.ico b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/favicon.ico similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/favicon.ico rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/favicon.ico diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_1_off.svg b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_1_off.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_1_off.svg rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_1_off.svg diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_1_on.svg b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_1_on.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_1_on.svg rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_1_on.svg diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_2_off.svg b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_2_off.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_2_off.svg rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_2_off.svg diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_2_on.svg b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_2_on.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_2_on.svg rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_2_on.svg diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_3_off.svg b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_3_off.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_3_off.svg rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_3_off.svg diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_3_on.svg b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_3_on.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_3_on.svg rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_3_on.svg diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_4_off.svg b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_4_off.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_4_off.svg rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_4_off.svg diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_4_on.svg b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_4_on.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/level_4_on.svg rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/level_4_on.svg diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/ui.html b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/ui.html similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/ui.html rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/ui.html diff --git a/lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/ui.js b/lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/ui.js similarity index 100% rename from lib/IRremoteESP8266-2.7.1/examples/Web-AC-control/upload/ui.js rename to lib/IRremoteESP8266-2.7.3/examples/Web-AC-control/upload/ui.js diff --git a/lib/IRremoteESP8266-2.7.1/keywords.txt b/lib/IRremoteESP8266-2.7.3/keywords.txt similarity index 98% rename from lib/IRremoteESP8266-2.7.1/keywords.txt rename to lib/IRremoteESP8266-2.7.3/keywords.txt index f027e808b..65b0d8b2e 100644 --- a/lib/IRremoteESP8266-2.7.1/keywords.txt +++ b/lib/IRremoteESP8266-2.7.3/keywords.txt @@ -39,6 +39,7 @@ IRHaierACYRW02 KEYWORD1 IRHitachiAc KEYWORD1 IRHitachiAc424 KEYWORD1 IRKelvinatorAC KEYWORD1 +IRLgAc KEYWORD1 IRMideaAC KEYWORD1 IRMitsubishi112 KEYWORD1 IRMitsubishi136 KEYWORD1 @@ -66,6 +67,7 @@ fanspeed_t KEYWORD1 fujitsu_ac_remote_model_t KEYWORD1 gree_ac_remote_model_t KEYWORD1 irparams_t KEYWORD1 +lg_ac_remote_model_t KEYWORD1 match_result_t KEYWORD1 opmode_t KEYWORD1 panasonic_ac_remote_model_t KEYWORD1 @@ -82,6 +84,7 @@ _delayMicroseconds KEYWORD2 _getTime KEYWORD2 _getTimer KEYWORD2 _matchGeneric KEYWORD2 +_sendSony KEYWORD2 _setMode KEYWORD2 _setTemp KEYWORD2 _setTime KEYWORD2 @@ -346,9 +349,11 @@ isSwingVToggle KEYWORD2 isTimeCommand KEYWORD2 isTimerActive KEYWORD2 isTimerEnabled KEYWORD2 +isValidLgAc KEYWORD2 kelvinator KEYWORD2 ledOff KEYWORD2 ledOn KEYWORD2 +lg KEYWORD2 mark KEYWORD2 match KEYWORD2 matchAtLeast KEYWORD2 @@ -455,6 +460,7 @@ sendSharpAc KEYWORD2 sendSharpRaw KEYWORD2 sendSherwood KEYWORD2 sendSony KEYWORD2 +sendSony38 KEYWORD2 sendTcl112Ac KEYWORD2 sendTeco KEYWORD2 sendToshibaAC KEYWORD2 @@ -590,6 +596,7 @@ xorBytes KEYWORD2 // LITERAL1 AIWA_RC_T501 LITERAL1 AIWA_RC_T501_BITS LITERAL1 +AKB75215403 LITERAL1 ALLOW_DELAY_CALLS LITERAL1 AMCOR LITERAL1 ARDB1 LITERAL1 @@ -748,6 +755,7 @@ FUJITSU_AC_SWING_BOTH LITERAL1 FUJITSU_AC_SWING_HORIZ LITERAL1 FUJITSU_AC_SWING_OFF LITERAL1 FUJITSU_AC_SWING_VERT LITERAL1 +GE6711AR2853M LITERAL1 GICABLE LITERAL1 GICABLE_BITS LITERAL1 GLOBALCACHE LITERAL1 @@ -1018,6 +1026,7 @@ SONY LITERAL1 SONY_12_BITS LITERAL1 SONY_15_BITS LITERAL1 SONY_20_BITS LITERAL1 +SONY_38K LITERAL1 TCL112AC LITERAL1 TECO LITERAL1 TIMEOUT_MS LITERAL1 @@ -1063,6 +1072,22 @@ kAiwaRcT501PostBits LITERAL1 kAiwaRcT501PostData LITERAL1 kAiwaRcT501PreBits LITERAL1 kAiwaRcT501PreData LITERAL1 +kAlokaBits LITERAL1 +kAlokaLedBlue LITERAL1 +kAlokaLedGreen LITERAL1 +kAlokaLedLightGreen LITERAL1 +kAlokaLedMidBlue LITERAL1 +kAlokaLedOrange LITERAL1 +kAlokaLedPink LITERAL1 +kAlokaLedPinkRed LITERAL1 +kAlokaLedRainbow LITERAL1 +kAlokaLedRed LITERAL1 +kAlokaLedTreeGrow LITERAL1 +kAlokaLedWhite LITERAL1 +kAlokaLedYellow LITERAL1 +kAlokaNightFade LITERAL1 +kAlokaNightTimer LITERAL1 +kAlokaPower LITERAL1 kAmcorAuto LITERAL1 kAmcorBits LITERAL1 kAmcorChecksumByte LITERAL1 @@ -2094,9 +2119,38 @@ kLg32HdrSpace LITERAL1 kLg32HdrSpaceTicks LITERAL1 kLg32RptHdrMark LITERAL1 kLg32RptHdrMarkTicks LITERAL1 +kLgAcAuto LITERAL1 +kLgAcChecksumOffset LITERAL1 +kLgAcChecksumSize LITERAL1 +kLgAcCool LITERAL1 +kLgAcDry LITERAL1 +kLgAcFan LITERAL1 +kLgAcFanAuto LITERAL1 +kLgAcFanHigh LITERAL1 +kLgAcFanLow LITERAL1 +kLgAcFanMedium LITERAL1 +kLgAcFanOffset LITERAL1 +kLgAcFanSize LITERAL1 +kLgAcHeat LITERAL1 +kLgAcMaxTemp LITERAL1 +kLgAcMinTemp LITERAL1 +kLgAcModeOffset LITERAL1 +kLgAcModeSize LITERAL1 +kLgAcOffCommand LITERAL1 +kLgAcPowerOff LITERAL1 +kLgAcPowerOffset LITERAL1 +kLgAcPowerOn LITERAL1 +kLgAcPowerSize LITERAL1 +kLgAcSignature LITERAL1 +kLgAcSignatureOffset LITERAL1 +kLgAcSignatureSize LITERAL1 +kLgAcTempAdjust LITERAL1 +kLgAcTempOffset LITERAL1 +kLgAcTempSize LITERAL1 kLgBitMark LITERAL1 kLgBitMarkTicks LITERAL1 kLgBits LITERAL1 +kLgDefaultRepeat LITERAL1 kLgHdrMark LITERAL1 kLgHdrMarkTicks LITERAL1 kLgHdrSpace LITERAL1 @@ -2555,6 +2609,8 @@ kPanasonicAcFanMed LITERAL1 kPanasonicAcFanMin LITERAL1 kPanasonicAcFanModeTemp LITERAL1 kPanasonicAcHeat LITERAL1 +kPanasonicAcIonFilterByte LITERAL1 +kPanasonicAcIonFilterOffset LITERAL1 kPanasonicAcMaxTemp LITERAL1 kPanasonicAcMessageGap LITERAL1 kPanasonicAcMinTemp LITERAL1 @@ -2845,6 +2901,7 @@ kSlowStr LITERAL1 kSony12Bits LITERAL1 kSony15Bits LITERAL1 kSony20Bits LITERAL1 +kSonyAltFreq LITERAL1 kSonyHdrMark LITERAL1 kSonyHdrMarkTicks LITERAL1 kSonyMinBits LITERAL1 @@ -2857,6 +2914,7 @@ kSonyRptLength LITERAL1 kSonyRptLengthTicks LITERAL1 kSonySpace LITERAL1 kSonySpaceTicks LITERAL1 +kSonyStdFreq LITERAL1 kSonyTick LITERAL1 kSonyZeroMark LITERAL1 kSonyZeroMarkTicks LITERAL1 diff --git a/lib/IRremoteESP8266-2.7.1/library.json b/lib/IRremoteESP8266-2.7.3/library.json similarity index 97% rename from lib/IRremoteESP8266-2.7.1/library.json rename to lib/IRremoteESP8266-2.7.3/library.json index 50464bed1..b28b1b218 100644 --- a/lib/IRremoteESP8266-2.7.1/library.json +++ b/lib/IRremoteESP8266-2.7.3/library.json @@ -1,6 +1,6 @@ { "name": "IRremoteESP8266", - "version": "2.7.1", + "version": "2.7.3", "keywords": "infrared, ir, remote, esp8266, esp32", "description": "Send and receive infrared signals with multiple protocols (ESP8266/ESP32)", "repository": diff --git a/lib/IRremoteESP8266-2.7.1/library.properties b/lib/IRremoteESP8266-2.7.3/library.properties similarity index 97% rename from lib/IRremoteESP8266-2.7.1/library.properties rename to lib/IRremoteESP8266-2.7.3/library.properties index 6e7215626..b22e7f8cc 100644 --- a/lib/IRremoteESP8266-2.7.1/library.properties +++ b/lib/IRremoteESP8266-2.7.3/library.properties @@ -1,5 +1,5 @@ name=IRremoteESP8266 -version=2.7.1 +version=2.7.3 author=David Conran, Sebastien Warin, Mark Szabo, Ken Shirriff maintainer=Mark Szabo, David Conran, Sebastien Warin, Roi Dayan, Massimiliano Pinto sentence=Send and receive infrared signals with multiple protocols (ESP8266/ESP32) diff --git a/lib/IRremoteESP8266-2.7.1/pylintrc b/lib/IRremoteESP8266-2.7.3/pylintrc similarity index 100% rename from lib/IRremoteESP8266-2.7.1/pylintrc rename to lib/IRremoteESP8266-2.7.3/pylintrc diff --git a/lib/IRremoteESP8266-2.7.1/src/CPPLINT.cfg b/lib/IRremoteESP8266-2.7.3/src/CPPLINT.cfg similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/CPPLINT.cfg rename to lib/IRremoteESP8266-2.7.3/src/CPPLINT.cfg diff --git a/lib/IRremoteESP8266-2.7.1/src/IRac.cpp b/lib/IRremoteESP8266-2.7.3/src/IRac.cpp similarity index 91% rename from lib/IRremoteESP8266-2.7.1/src/IRac.cpp rename to lib/IRremoteESP8266-2.7.3/src/IRac.cpp index f8e5ca759..b2dc6f63e 100644 --- a/lib/IRremoteESP8266-2.7.1/src/IRac.cpp +++ b/lib/IRremoteESP8266-2.7.3/src/IRac.cpp @@ -25,6 +25,7 @@ #include "ir_Haier.h" #include "ir_Hitachi.h" #include "ir_Kelvinator.h" +#include "ir_LG.h" #include "ir_Midea.h" #include "ir_Mitsubishi.h" #include "ir_MitsubishiHeavy.h" @@ -149,6 +150,10 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { #if SEND_KELVINATOR case decode_type_t::KELVINATOR: #endif +#if SEND_LG + case decode_type_t::LG: + case decode_type_t::LG2: +#endif #if SEND_MIDEA case decode_type_t::MIDEA: #endif @@ -719,6 +724,30 @@ void IRac::kelvinator(IRKelvinatorAC *ac, } #endif // SEND_KELVINATOR +#if SEND_LG +void IRac::lg(IRLgAc *ac, const lg_ac_remote_model_t model, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan) { + ac->begin(); + ac->setModel(model); + ac->setPower(on); + ac->setMode(ac->convertMode(mode)); + ac->setTemp(degrees); + ac->setFan(ac->convertFan(fan)); + // No Vertical swing setting available. + // No Horizontal swing setting available. + // No Quiet setting available. + // No Turbo setting available. + // No Light setting available. + // No Filter setting available. + // No Clean setting available. + // No Beep setting available. + // No Sleep setting available. + // No Clock setting available. + ac->send(); +} +#endif // SEND_LG + #if SEND_MIDEA void IRac::midea(IRMideaAC *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, @@ -911,7 +940,8 @@ void IRac::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) { + const bool quiet, const bool turbo, const bool filter, + const int16_t clock) { ac->begin(); ac->setModel(model); ac->setPower(on); @@ -922,9 +952,9 @@ void IRac::panasonic(IRPanasonicAc *ac, const panasonic_ac_remote_model_t model, ac->setSwingHorizontal(ac->convertSwingH(swingh)); ac->setQuiet(quiet); ac->setPowerful(turbo); + ac->setIon(filter); // No Light setting available. // No Econo setting available. - // No Filter setting available. // No Clean setting available. // No Beep setting available. // No Sleep setting available. @@ -1144,6 +1174,20 @@ void IRac::whirlpool(IRWhirlpoolAc *ac, const whirlpool_ac_remote_model_t model, } #endif // SEND_WHIRLPOOL_AC +// Create a new state base on the provided state that has been suitably fixed. +// Args: +// state: The state_t structure describing the desired a/c state. +// +// Returns: +// A stdAc::state_t with the needed settings. +stdAc::state_t IRac::cleanState(const stdAc::state_t state) { + stdAc::state_t result = state; + // A hack for Home Assistant, it appears to need/want an Off opmode. + // So enforce the power is off if the mode is also off. + if (state.mode == stdAc::opmode_t::kOff) result.power = false; + return result; +} + // Create a new state base on desired & previous states but handle // any state changes for options that need to be toggled. // Args: @@ -1244,23 +1288,18 @@ bool IRac::sendAc(const decode_type_t vendor, const int16_t model, // Returns: // boolean: True, if accepted/converted/attempted. False, if unsupported. bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { - stdAc::state_t send = this->handleToggles(desired, prev); - // Convert the temperature to Celsius. - float degC; - if (desired.celsius) - degC = send.degrees; - else - degC = fahrenheitToCelsius(desired.degrees); - bool on = desired.power; - // A hack for Home Assistant, it appears to need/want an Off opmode. - if (desired.mode == stdAc::opmode_t::kOff) on = false; + // Convert the temp from Fahrenheit to Celsius if we are not in Celsius mode. + float degC = desired.celsius ? desired.degrees + : fahrenheitToCelsius(desired.degrees); + // special `state_t` that is required to be sent based on that. + stdAc::state_t send = this->handleToggles(this->cleanState(desired), prev); // Per vendor settings & setup. switch (send.protocol) { #if SEND_AMCOR case AMCOR: { IRAmcorAc ac(_pin, _inverted, _modulation); - amcor(&ac, on, send.mode, degC, send.fanspeed); + amcor(&ac, send.power, send.mode, degC, send.fanspeed); break; } #endif // SEND_AMCOR @@ -1268,8 +1307,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case ARGO: { IRArgoAC ac(_pin, _inverted, _modulation); - argo(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.turbo, - send.sleep); + argo(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, + send.turbo, send.sleep); break; } #endif // SEND_ARGO @@ -1277,8 +1316,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case COOLIX: { IRCoolixAC ac(_pin, _inverted, _modulation); - coolix(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.swingh, - send.turbo, send.light, send.clean, send.sleep); + coolix(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, + send.swingh, send.turbo, send.light, send.clean, send.sleep); break; } #endif // SEND_COOLIX @@ -1286,8 +1325,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case DAIKIN: { IRDaikinESP ac(_pin, _inverted, _modulation); - daikin(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.swingh, - send.quiet, send.turbo, send.econo, send.clean); + daikin(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, + send.swingh, send.quiet, send.turbo, send.econo, send.clean); break; } #endif // SEND_DAIKIN @@ -1295,7 +1334,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case DAIKIN128: { IRDaikin128 ac(_pin, _inverted, _modulation); - daikin128(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + daikin128(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, send.quiet, send.turbo, send.light, send.econo, send.sleep, send.clock); break; @@ -1305,7 +1344,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case DAIKIN152: { IRDaikin152 ac(_pin, _inverted, _modulation); - daikin152(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + daikin152(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, send.quiet, send.turbo, send.econo); break; } @@ -1314,7 +1353,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case DAIKIN160: { IRDaikin160 ac(_pin, _inverted, _modulation); - daikin160(&ac, on, send.mode, degC, send.fanspeed, send.swingv); + daikin160(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv); break; } #endif // SEND_DAIKIN160 @@ -1322,7 +1361,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case DAIKIN176: { IRDaikin176 ac(_pin, _inverted, _modulation); - daikin176(&ac, on, send.mode, degC, send.fanspeed, send.swingh); + daikin176(&ac, send.power, send.mode, degC, send.fanspeed, send.swingh); break; } #endif // SEND_DAIKIN176 @@ -1330,9 +1369,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case DAIKIN2: { IRDaikin2 ac(_pin, _inverted, _modulation); - daikin2(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.swingh, - send.quiet, send.turbo, send.light, send.econo, send.filter, - send.clean, send.beep, send.sleep, send.clock); + daikin2(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, + send.swingh, send.quiet, send.turbo, send.light, send.econo, + send.filter, send.clean, send.beep, send.sleep, send.clock); break; } #endif // SEND_DAIKIN2 @@ -1340,7 +1379,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case DAIKIN216: { IRDaikin216 ac(_pin, _inverted, _modulation); - daikin216(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + daikin216(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, send.swingh, send.quiet, send.turbo); break; } @@ -1349,7 +1388,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case ELECTRA_AC: { IRElectraAc ac(_pin, _inverted, _modulation); - electra(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + electra(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, send.swingh); break; } @@ -1359,9 +1398,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { { IRFujitsuAC ac(_pin, (fujitsu_ac_remote_model_t)send.model, _inverted, _modulation); - fujitsu(&ac, (fujitsu_ac_remote_model_t)send.model, on, send.mode, degC, - send.fanspeed, send.swingv, send.swingh, send.quiet, send.turbo, - send.econo, send.filter, send.clean); + fujitsu(&ac, (fujitsu_ac_remote_model_t)send.model, send.power, send.mode, + degC, send.fanspeed, send.swingv, send.swingh, send.quiet, + send.turbo, send.econo, send.filter, send.clean); break; } #endif // SEND_FUJITSU_AC @@ -1369,7 +1408,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case GOODWEATHER: { IRGoodweatherAc ac(_pin, _inverted, _modulation); - goodweather(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + goodweather(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, send.turbo, send.light, send.sleep); break; } @@ -1379,7 +1418,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { { IRGreeAC ac(_pin, (gree_ac_remote_model_t)send.model, _inverted, _modulation); - gree(&ac, (gree_ac_remote_model_t)send.model, on, send.mode, degC, + gree(&ac, (gree_ac_remote_model_t)send.model, send.power, send.mode, degC, send.fanspeed, send.swingv, send.turbo, send.light, send.clean, send.sleep); break; @@ -1389,8 +1428,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case HAIER_AC: { IRHaierAC ac(_pin, _inverted, _modulation); - haier(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.filter, - send.sleep, send.clock); + haier(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, + send.filter, send.sleep, send.clock); break; } #endif // SEND_HAIER_AC @@ -1398,7 +1437,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case HAIER_AC_YRW02: { IRHaierACYRW02 ac(_pin, _inverted, _modulation); - haierYrwo2(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + haierYrwo2(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, send.turbo, send.filter, send.sleep); break; } @@ -1407,7 +1446,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case HITACHI_AC: { IRHitachiAc ac(_pin, _inverted, _modulation); - hitachi(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + hitachi(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, send.swingh); break; } @@ -1416,7 +1455,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case HITACHI_AC424: { IRHitachiAc424 ac(_pin, _inverted, _modulation); - hitachi424(&ac, on, send.mode, degC, send.fanspeed, send.swingv); + hitachi424(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv); break; } #endif // SEND_HITACHI_AC424 @@ -1424,18 +1463,28 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case KELVINATOR: { IRKelvinatorAC ac(_pin, _inverted, _modulation); - kelvinator(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + kelvinator(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, send.swingh, send.quiet, send.turbo, send.light, send.filter, send.clean); break; } #endif // SEND_KELVINATOR +#if SEND_LG + case LG: + case LG2: + { + IRLgAc ac(_pin, _inverted, _modulation); + lg(&ac, (lg_ac_remote_model_t)send.model, send.power, send.mode, + send.degrees, send.fanspeed); + break; + } +#endif // SEND_LG #if SEND_MIDEA case MIDEA: { IRMideaAC ac(_pin, _inverted, _modulation); - midea(&ac, on, send.mode, send.celsius, send.degrees, send.fanspeed, - send.swingv, send.sleep); + midea(&ac, send.power, send.mode, send.celsius, send.degrees, + send.fanspeed, send.swingv, send.sleep); break; } #endif // SEND_MIDEA @@ -1443,7 +1492,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case MITSUBISHI_AC: { IRMitsubishiAC ac(_pin, _inverted, _modulation); - mitsubishi(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + mitsubishi(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, send.swingh, send.quiet, send.clock); break; } @@ -1452,8 +1501,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case MITSUBISHI112: { IRMitsubishi112 ac(_pin, _inverted, _modulation); - mitsubishi112(&ac, on, send.mode, degC, send.fanspeed, send.swingv, - send.swingh, send.quiet); + mitsubishi112(&ac, send.power, send.mode, degC, send.fanspeed, + send.swingv, send.swingh, send.quiet); break; } #endif // SEND_MITSUBISHI112 @@ -1461,8 +1510,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case MITSUBISHI136: { IRMitsubishi136 ac(_pin, _inverted, _modulation); - mitsubishi136(&ac, on, send.mode, degC, send.fanspeed, send.swingv, - send.quiet); + mitsubishi136(&ac, send.power, send.mode, degC, send.fanspeed, + send.swingv, send.quiet); break; } #endif // SEND_MITSUBISHI136 @@ -1470,16 +1519,17 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case MITSUBISHI_HEAVY_88: { IRMitsubishiHeavy88Ac ac(_pin, _inverted, _modulation); - mitsubishiHeavy88(&ac, on, send.mode, degC, send.fanspeed, send.swingv, - send.swingh, send.turbo, send.econo, send.clean); + mitsubishiHeavy88(&ac, send.power, send.mode, degC, send.fanspeed, + send.swingv, send.swingh, send.turbo, send.econo, + send.clean); break; } case MITSUBISHI_HEAVY_152: { IRMitsubishiHeavy152Ac ac(_pin, _inverted, _modulation); - mitsubishiHeavy152(&ac, on, send.mode, degC, send.fanspeed, send.swingv, - send.swingh, send.quiet, send.turbo, send.econo, - send.filter, send.clean, send.sleep); + mitsubishiHeavy152(&ac, send.power, send.mode, degC, send.fanspeed, + send.swingv, send.swingh, send.quiet, send.turbo, + send.econo, send.filter, send.clean, send.sleep); break; } #endif // SEND_MITSUBISHIHEAVY @@ -1487,7 +1537,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case NEOCLIMA: { IRNeoclimaAc ac(_pin, _inverted, _modulation); - neoclima(&ac, on, send.mode, degC, send.fanspeed, send.swingv, + neoclima(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, send.swingh, send.turbo, send.light, send.filter, send.sleep); break; } @@ -1496,9 +1546,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case PANASONIC_AC: { IRPanasonicAc ac(_pin, _inverted, _modulation); - panasonic(&ac, (panasonic_ac_remote_model_t)send.model, on, send.mode, - degC, send.fanspeed, send.swingv, send.swingh, send.quiet, - send.turbo, send.clock); + panasonic(&ac, (panasonic_ac_remote_model_t)send.model, send.power, + send.mode, degC, send.fanspeed, send.swingv, send.swingh, + send.quiet, send.turbo, send.clock); break; } #endif // SEND_PANASONIC_AC @@ -1506,8 +1556,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case SAMSUNG_AC: { IRSamsungAc ac(_pin, _inverted, _modulation); - samsung(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.quiet, - send.turbo, send.clean, send.beep, prev->power); + samsung(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, + send.quiet, send.turbo, send.clean, send.beep, prev->power); break; } #endif // SEND_SAMSUNG_AC @@ -1515,7 +1565,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case SHARP_AC: { IRSharpAc ac(_pin, _inverted, _modulation); - sharp(&ac, on, send.mode, degC, send.fanspeed); + sharp(&ac, send.power, send.mode, degC, send.fanspeed); break; } #endif // SEND_SHARP_AC @@ -1523,8 +1573,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case TCL112AC: { IRTcl112Ac ac(_pin, _inverted, _modulation); - tcl112(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.swingh, - send.turbo, send.light, send.econo, send.filter); + tcl112(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, + send.swingh, send.turbo, send.light, send.econo, send.filter); break; } #endif // SEND_TCL112AC @@ -1532,8 +1582,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case TECO: { IRTecoAc ac(_pin, _inverted, _modulation); - teco(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.light, - send.sleep); + teco(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, + send.light, send.sleep); break; } #endif // SEND_TECO @@ -1541,7 +1591,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case TOSHIBA_AC: { IRToshibaAC ac(_pin, _inverted, _modulation); - toshiba(&ac, on, send.mode, degC, send.fanspeed); + toshiba(&ac, send.power, send.mode, degC, send.fanspeed); break; } #endif // SEND_TOSHIBA_AC @@ -1549,7 +1599,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case TROTEC: { IRTrotecESP ac(_pin, _inverted, _modulation); - trotec(&ac, on, send.mode, degC, send.fanspeed, send.sleep); + trotec(&ac, send.power, send.mode, degC, send.fanspeed, send.sleep); break; } #endif // SEND_TROTEC @@ -1557,8 +1607,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case VESTEL_AC: { IRVestelAc ac(_pin, _inverted, _modulation); - vestel(&ac, on, send.mode, degC, send.fanspeed, send.swingv, send.turbo, - send.filter, send.sleep, send.clock); + vestel(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, + send.turbo, send.filter, send.sleep, send.clock); break; } #endif // SEND_VESTEL_AC @@ -1566,9 +1616,9 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case WHIRLPOOL_AC: { IRWhirlpoolAc ac(_pin, _inverted, _modulation); - whirlpool(&ac, (whirlpool_ac_remote_model_t)send.model, on, send.mode, - degC, send.fanspeed, send.swingv, send.turbo, send.light, - send.sleep, send.clock); + whirlpool(&ac, (whirlpool_ac_remote_model_t)send.model, send.power, + send.mode, degC, send.fanspeed, send.swingv, send.turbo, + send.light, send.sleep, send.clock); break; } #endif // SEND_WHIRLPOOL_AC @@ -1750,7 +1800,8 @@ int16_t IRac::strToModel(const char *str, const int16_t def) { return panasonic_ac_remote_model_t::kPanasonicLke; } else if (!strcasecmp(str, "NKE") || !strcasecmp(str, "PANASONICNKE")) { return panasonic_ac_remote_model_t::kPanasonicNke; - } else if (!strcasecmp(str, "DKE") || !strcasecmp(str, "PANASONICDKE")) { + } else if (!strcasecmp(str, "DKE") || !strcasecmp(str, "PANASONICDKE") || + !strcasecmp(str, "PKR") || !strcasecmp(str, "PANASONICPKR")) { return panasonic_ac_remote_model_t::kPanasonicDke; } else if (!strcasecmp(str, "JKE") || !strcasecmp(str, "PANASONICJKE")) { return panasonic_ac_remote_model_t::kPanasonicJke; @@ -2129,6 +2180,21 @@ namespace IRAcUtils { return ac.toString(); } #endif // DECODE_TCL112AC +#if DECODE_LG + case decode_type_t::LG: + case decode_type_t::LG2: { + IRLgAc ac(0); + ac.setRaw(result->value); // Like Coolix, use value instead of state. + switch (result->decode_type) { + case decode_type_t::LG2: + ac.setModel(lg_ac_remote_model_t::AKB75215403); + break; + default: + ac.setModel(lg_ac_remote_model_t::GE6711AR2853M); + } + return ac.isValidLgAc() ? ac.toString() : ""; + } +#endif // DECODE_LG default: return ""; } @@ -2166,6 +2232,7 @@ namespace IRAcUtils { #if DECODE_COOLIX case decode_type_t::COOLIX: { IRCoolixAC ac(kGpioUnused); + ac.on(); ac.setRaw(decode->value); // Uses value instead of state. *result = ac.toCommon(prev); break; @@ -2299,6 +2366,23 @@ namespace IRAcUtils { break; } #endif // DECODE_KELVINATOR +#if DECODE_LG + case decode_type_t::LG: + case decode_type_t::LG2: { + IRLgAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + if (!ac.isValidLgAc()) return false; + switch (decode->decode_type) { + case decode_type_t::LG2: + ac.setModel(lg_ac_remote_model_t::AKB75215403); + break; + default: + ac.setModel(lg_ac_remote_model_t::GE6711AR2853M); + } + *result = ac.toCommon(); + break; + } +#endif // DECODE_LG #if DECODE_MIDEA case decode_type_t::MIDEA: { IRMideaAC ac(kGpioUnused); diff --git a/lib/IRremoteESP8266-2.7.1/src/IRac.h b/lib/IRremoteESP8266-2.7.3/src/IRac.h similarity index 94% rename from lib/IRremoteESP8266-2.7.1/src/IRac.h rename to lib/IRremoteESP8266-2.7.3/src/IRac.h index 4e1237d8d..4945bfac9 100644 --- a/lib/IRremoteESP8266-2.7.1/src/IRac.h +++ b/lib/IRremoteESP8266-2.7.3/src/IRac.h @@ -18,6 +18,7 @@ #include "ir_Haier.h" #include "ir_Hitachi.h" #include "ir_Kelvinator.h" +#include "ir_LG.h" #include "ir_Midea.h" #include "ir_Mitsubishi.h" #include "ir_MitsubishiHeavy.h" @@ -136,16 +137,16 @@ class IRac { const bool quiet, const bool turbo, const bool econo); #endif // SEND_DAIKIN152 #if SEND_DAIKIN160 -void daikin160(IRDaikin160 *ac, - const bool on, const stdAc::opmode_t mode, - const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv); + void daikin160(IRDaikin160 *ac, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv); #endif // SEND_DAIKIN160 #if SEND_DAIKIN176 -void daikin176(IRDaikin176 *ac, - const bool on, const stdAc::opmode_t mode, - const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingh_t swingh); + void daikin176(IRDaikin176 *ac, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan, + const stdAc::swingh_t swingh); #endif // SEND_DAIKIN176 #if SEND_DAIKIN2 void daikin2(IRDaikin2 *ac, @@ -230,6 +231,11 @@ void electra(IRElectraAc *ac, const bool quiet, const bool turbo, const bool light, const bool filter, const bool clean); #endif // SEND_KELVINATOR +#if SEND_LG + void lg(IRLgAc *ac, const lg_ac_remote_model_t model, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan); +#endif // SEND_LG #if SEND_MIDEA void midea(IRMideaAC *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, @@ -286,7 +292,8 @@ void electra(IRElectraAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, const stdAc::swingh_t swingh, - const bool quiet, const bool turbo, const int16_t clock = -1); + const bool quiet, const bool turbo, const bool filter, + const int16_t clock = -1); #endif // SEND_PANASONIC_AC #if SEND_SAMSUNG_AC void samsung(IRSamsungAc *ac, @@ -340,6 +347,7 @@ void electra(IRElectraAc *ac, const bool turbo, const bool light, const int16_t sleep = -1, const int16_t clock = -1); #endif // SEND_WHIRLPOOL_AC +static stdAc::state_t cleanState(const stdAc::state_t state); static stdAc::state_t handleToggles(const stdAc::state_t desired, const stdAc::state_t *prev = NULL); }; // IRac class diff --git a/lib/IRremoteESP8266-2.7.1/src/IRrecv.cpp b/lib/IRremoteESP8266-2.7.3/src/IRrecv.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/IRrecv.cpp rename to lib/IRremoteESP8266-2.7.3/src/IRrecv.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/IRrecv.h b/lib/IRremoteESP8266-2.7.3/src/IRrecv.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/IRrecv.h rename to lib/IRremoteESP8266-2.7.3/src/IRrecv.h diff --git a/lib/IRremoteESP8266-2.7.1/src/IRremoteESP8266.h b/lib/IRremoteESP8266-2.7.3/src/IRremoteESP8266.h similarity index 53% rename from lib/IRremoteESP8266-2.7.1/src/IRremoteESP8266.h rename to lib/IRremoteESP8266-2.7.3/src/IRremoteESP8266.h index 9e4cdbaab..eb8a67f5c 100644 --- a/lib/IRremoteESP8266-2.7.1/src/IRremoteESP8266.h +++ b/lib/IRremoteESP8266-2.7.3/src/IRremoteESP8266.h @@ -1,4 +1,4 @@ -/*************************************************** + /*************************************************** * IRremote for ESP8266 * * Based on the IRremote library for Arduino by Ken Shirriff @@ -52,428 +52,518 @@ #endif // UNIT_TEST // Library Version -#define _IRREMOTEESP8266_VERSION_ "2.7.1" +#define _IRREMOTEESP8266_VERSION_ "2.7.3" // Set the language & locale for the library. See the `locale` dir for options. #ifndef _IR_LOCALE_ #define _IR_LOCALE_ en-AU #endif // _IR_LOCALE_ +// Do we enable all the protocols by default (true), or disable them (false)? +// This allows users of the library to disable or enable all protocols at +// compile-time with `-D_IR_ENABLE_DEFAULT_=true` or +// `-D_IR_ENABLE_DEFAULT_=false` compiler flags respectively. +// Everything is included by default. +// e.g. If you only want to enable use of he NEC protocol to save program space, +// you would use something like: +// `-D_IR_ENABLE_DEFAULT_=false -DDECODE_NEC=true -DSEND_NEC=true` +// +// or alter your 'platform.ini' file accordingly: +// ``` +// build_flags = -D_IR_ENABLE_DEFAULT_=false +// -DDECODE_NEC=true +// -DSEND_NEC=true +// ``` +// If you want to enable support for every protocol *except* _decoding_ the +// Kelvinator protocol, you would use: +// `-DDECODE_KELVINATOR=false` +#ifndef _IR_ENABLE_DEFAULT_ +#define _IR_ENABLE_DEFAULT_ true // Unless set externally, the default is on. +#endif // _IR_ENABLE_DEFAULT_ + // 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! // The Air Conditioner protocols are the most expensive memory-wise. // -#ifdef USE_IR_REMOTE_FULL // full IR protocols -#define DECODE_HASH true // Semi-unique code for unknown messages - -#define SEND_RAW true - -#define DECODE_NEC true -#define SEND_NEC true - -#define DECODE_SHERWOOD true // Doesn't exist. Actually is DECODE_NEC -#define SEND_SHERWOOD true - -#define DECODE_RC5 true -#define SEND_RC5 true - -#define DECODE_RC6 true -#define SEND_RC6 true - -#define DECODE_RCMM true -#define SEND_RCMM true - -#define DECODE_SONY true -#define SEND_SONY true - -#define DECODE_PANASONIC true -#define SEND_PANASONIC true - -#define DECODE_JVC true -#define SEND_JVC true - -#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 - -#define DECODE_WHYNTER true -#define SEND_WHYNTER true - -#define DECODE_AIWA_RC_T501 true -#define SEND_AIWA_RC_T501 true - -#define DECODE_LG true -#define SEND_LG true - -#define DECODE_SANYO true -#define SEND_SANYO true - -#define DECODE_MITSUBISHI true -#define SEND_MITSUBISHI true - -#define DECODE_MITSUBISHI2 true -#define SEND_MITSUBISHI2 true - -#define DECODE_DISH true -#define SEND_DISH true - -#define DECODE_SHARP true -#define SEND_SHARP true - -#define DECODE_SHARP_AC true -#define SEND_SHARP_AC true - -#define DECODE_DENON true -#define SEND_DENON true - -#define DECODE_KELVINATOR true -#define SEND_KELVINATOR true - -#define DECODE_MITSUBISHI_AC true // Beta. -#define SEND_MITSUBISHI_AC true - -#define DECODE_MITSUBISHI136 true -#define SEND_MITSUBISHI136 true - -#define DECODE_MITSUBISHI112 true -#define SEND_MITSUBISHI112 true - -#define DECODE_FUJITSU_AC true -#define SEND_FUJITSU_AC true - -#define DECODE_INAX true -#define SEND_INAX true - -#define DECODE_DAIKIN true -#define SEND_DAIKIN true - -#define DECODE_COOLIX true -#define SEND_COOLIX true - -#define DECODE_GLOBALCACHE false // Not written. -#define SEND_GLOBALCACHE true - -#define DECODE_GOODWEATHER true -#define SEND_GOODWEATHER true - -#define DECODE_GREE true -#define SEND_GREE true - -#define DECODE_PRONTO false // Not written. -#define SEND_PRONTO true - -#define DECODE_ARGO true // Experimental -#define SEND_ARGO true - -#define DECODE_TROTEC true -#define SEND_TROTEC true - -#define DECODE_NIKAI true -#define SEND_NIKAI true - -#define DECODE_TOSHIBA_AC true -#define SEND_TOSHIBA_AC true - -#define DECODE_MAGIQUEST true -#define SEND_MAGIQUEST true - -#define DECODE_MIDEA true -#define SEND_MIDEA true - -#define DECODE_LASERTAG true -#define SEND_LASERTAG true - -#define DECODE_CARRIER_AC true -#define SEND_CARRIER_AC true - -#define DECODE_HAIER_AC true -#define SEND_HAIER_AC true - -#define DECODE_HITACHI_AC true -#define SEND_HITACHI_AC true - -#define DECODE_HITACHI_AC1 true -#define SEND_HITACHI_AC1 true - -#define DECODE_HITACHI_AC2 true -#define SEND_HITACHI_AC2 true - -#define DECODE_GICABLE true -#define SEND_GICABLE true - -#define DECODE_HAIER_AC_YRW02 true -#define SEND_HAIER_AC_YRW02 true - -#define DECODE_WHIRLPOOL_AC true -#define SEND_WHIRLPOOL_AC true - -#define DECODE_LUTRON true -#define SEND_LUTRON true - -#define DECODE_ELECTRA_AC true -#define SEND_ELECTRA_AC true - -#define DECODE_PANASONIC_AC true -#define SEND_PANASONIC_AC true - -#define DECODE_MWM true -#define SEND_MWM true - -#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 - -#define DECODE_DAIKIN160 true -#define SEND_DAIKIN160 true - -#define DECODE_NEOCLIMA true -#define SEND_NEOCLIMA true - -#define DECODE_DAIKIN176 true -#define SEND_DAIKIN176 true - -#define DECODE_DAIKIN128 true -#define SEND_DAIKIN128 true - -#define DECODE_AMCOR true -#define SEND_AMCOR true - -#define DECODE_DAIKIN152 true -#define SEND_DAIKIN152 true - -#define DECODE_HITACHI_AC424 true -#define SEND_HITACHI_AC424 true - -#else // defined(FIRMWARE_IR) || defined(FIRMWARE_IR_CUSTOM) // full IR protocols - -// Tasmota supported protocols (less protocols is less code size) -#define DECODE_HASH true // Semi-unique code for unknown messages - -#define SEND_RAW false - -#define DECODE_NEC true -#define SEND_NEC true - -#define DECODE_SHERWOOD false // Doesn't exist. Actually is DECODE_NEC -#define SEND_SHERWOOD false - -#define DECODE_RC5 true -#define SEND_RC5 true - -#define DECODE_RC6 true -#define SEND_RC6 true - -#define DECODE_RCMM false -#define SEND_RCMM false - -#define DECODE_SONY false -#define SEND_SONY false - -#define DECODE_PANASONIC false -#define SEND_PANASONIC false - -#define DECODE_JVC false -#define SEND_JVC false - -#define DECODE_SAMSUNG false -#define SEND_SAMSUNG false - -#define DECODE_SAMSUNG36 false -#define SEND_SAMSUNG36 false - -#define DECODE_SAMSUNG_AC false -#define SEND_SAMSUNG_AC false - -#define DECODE_WHYNTER false -#define SEND_WHYNTER false - -#define DECODE_AIWA_RC_T501 false -#define SEND_AIWA_RC_T501 false - -#define DECODE_LG false -#define SEND_LG false - -#define DECODE_SANYO false -#define SEND_SANYO false - -#define DECODE_MITSUBISHI false -#define SEND_MITSUBISHI false - -#define DECODE_MITSUBISHI2 false -#define SEND_MITSUBISHI2 false - -#define DECODE_DISH false -#define SEND_DISH false - -#define DECODE_SHARP false -#define SEND_SHARP false - -#define DECODE_SHARP_AC false -#define SEND_SHARP_AC false - -#define DECODE_DENON false -#define SEND_DENON false - -#define DECODE_KELVINATOR false -#define SEND_KELVINATOR false - -#define DECODE_MITSUBISHI_AC false // Beta. -#define SEND_MITSUBISHI_AC false - -#define DECODE_FUJITSU_AC false -#define SEND_FUJITSU_AC false - -#define DECODE_INAX false -#define SEND_INAX false - -#define DECODE_DAIKIN false -#define SEND_DAIKIN false - -#define DECODE_COOLIX false -#define SEND_COOLIX false - -#define DECODE_GLOBALCACHE false // Not written. -#define SEND_GLOBALCACHE false - -#define DECODE_GOODWEATHER false -#define SEND_GOODWEATHER false - -#define DECODE_GREE false -#define SEND_GREE false - -#define DECODE_PRONTO false // Not written. -#define SEND_PRONTO false - -#define DECODE_ARGO false // Experimental -#define SEND_ARGO false - -#define DECODE_TROTEC false -#define SEND_TROTEC false - -#define DECODE_NIKAI false -#define SEND_NIKAI false - -#define DECODE_TOSHIBA_AC false -#define SEND_TOSHIBA_AC false - -#define DECODE_MAGIQUEST false -#define SEND_MAGIQUEST false - -#define DECODE_MIDEA false -#define SEND_MIDEA false - -#define DECODE_LASERTAG false -#define SEND_LASERTAG false - -#define DECODE_CARRIER_AC false -#define SEND_CARRIER_AC false - -#define DECODE_HAIER_AC false -#define SEND_HAIER_AC false - -#define DECODE_HITACHI_AC false -#define SEND_HITACHI_AC false - -#define DECODE_HITACHI_AC1 false -#define SEND_HITACHI_AC1 false - -#define DECODE_HITACHI_AC2 false -#define SEND_HITACHI_AC2 false - -#define DECODE_GICABLE false -#define SEND_GICABLE false - -#define DECODE_HAIER_AC_YRW02 false -#define SEND_HAIER_AC_YRW02 false - -#define DECODE_WHIRLPOOL_AC false -#define SEND_WHIRLPOOL_AC false - -#define DECODE_LUTRON false -#define SEND_LUTRON false - -#define DECODE_ELECTRA_AC false -#define SEND_ELECTRA_AC false - -#define DECODE_PANASONIC_AC false -#define SEND_PANASONIC_AC false - -#define DECODE_MWM false -#define SEND_MWM false - -#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 - -#define DECODE_DAIKIN160 false -#define SEND_DAIKIN160 false - -#define DECODE_NEOCLIMA false -#define SEND_NEOCLIMA false - -#define DECODE_DAIKIN176 false -#define SEND_DAIKIN176 false - -#define DECODE_DAIKIN128 false -#define SEND_DAIKIN128 false - -#define DECODE_AMCOR false -#define SEND_AMCOR false - -#define DECODE_DAIKIN152 false -#define SEND_DAIKIN152 false - -#define DECODE_HITACHI_AC424 false -#define SEND_HITACHI_AC424 false - -#endif // defined(FIRMWARE_IR) || defined(FIRMWARE_IR_CUSTOM) // full IR protocols +// Semi-unique code for unknown messages +#ifndef DECODE_HASH +#define DECODE_HASH _IR_ENABLE_DEFAULT_ +#endif // DECODE_HASH + +#ifndef SEND_RAW +#define SEND_RAW _IR_ENABLE_DEFAULT_ +#endif // SEND_RAW + +#ifndef DECODE_NEC +#define DECODE_NEC _IR_ENABLE_DEFAULT_ +#endif // DECODE_NEC +#ifndef SEND_NEC +#define SEND_NEC _IR_ENABLE_DEFAULT_ +#endif // SEND_NEC + +#ifndef DECODE_SHERWOOD +#define DECODE_SHERWOOD false // Not applicable. Actually is DECODE_NEC +#endif // DECODE_SHERWOOD +#ifndef SEND_SHERWOOD +#define SEND_SHERWOOD _IR_ENABLE_DEFAULT_ +#endif // SEND_SHERWOOD + +#ifndef DECODE_RC5 +#define DECODE_RC5 _IR_ENABLE_DEFAULT_ +#endif // DECODE_RC5 +#ifndef SEND_RC5 +#define SEND_RC5 _IR_ENABLE_DEFAULT_ +#endif // SEND_RC5 + +#ifndef DECODE_RC6 +#define DECODE_RC6 _IR_ENABLE_DEFAULT_ +#endif // DECODE_RC6 +#ifndef SEND_RC6 +#define SEND_RC6 _IR_ENABLE_DEFAULT_ +#endif // SEND_RC6 + +#ifndef DECODE_RCMM +#define DECODE_RCMM _IR_ENABLE_DEFAULT_ +#endif // DECODE_RCMM +#ifndef SEND_RCMM +#define SEND_RCMM _IR_ENABLE_DEFAULT_ +#endif // SEND_RCMM + +#ifndef DECODE_SONY +#define DECODE_SONY _IR_ENABLE_DEFAULT_ +#endif // DECODE_SONY +#ifndef SEND_SONY +#define SEND_SONY _IR_ENABLE_DEFAULT_ +#endif // SEND_SONY + +#ifndef DECODE_PANASONIC +#define DECODE_PANASONIC _IR_ENABLE_DEFAULT_ +#endif // DECODE_PANASONIC +#ifndef SEND_PANASONIC +#define SEND_PANASONIC _IR_ENABLE_DEFAULT_ +#endif // SEND_PANASONIC + +#ifndef DECODE_JVC +#define DECODE_JVC _IR_ENABLE_DEFAULT_ +#endif // DECODE_JVC +#ifndef SEND_JVC +#define SEND_JVC _IR_ENABLE_DEFAULT_ +#endif // SEND_JVC + +#ifndef DECODE_SAMSUNG +#define DECODE_SAMSUNG _IR_ENABLE_DEFAULT_ +#endif // DECODE_SAMSUNG +#ifndef SEND_SAMSUNG +#define SEND_SAMSUNG _IR_ENABLE_DEFAULT_ +#endif // SEND_SAMSUNG + +#ifndef DECODE_SAMSUNG36 +#define DECODE_SAMSUNG36 _IR_ENABLE_DEFAULT_ +#endif // DECODE_SAMSUNG36 +#ifndef SEND_SAMSUNG36 +#define SEND_SAMSUNG36 _IR_ENABLE_DEFAULT_ +#endif // SEND_SAMSUNG36 + +#ifndef DECODE_SAMSUNG_AC +#define DECODE_SAMSUNG_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_SAMSUNG_AC +#ifndef SEND_SAMSUNG_AC +#define SEND_SAMSUNG_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_SAMSUNG_AC + +#ifndef DECODE_WHYNTER +#define DECODE_WHYNTER _IR_ENABLE_DEFAULT_ +#endif // DECODE_WHYNTER +#ifndef SEND_WHYNTER +#define SEND_WHYNTER _IR_ENABLE_DEFAULT_ +#endif // SEND_WHYNTER + +#ifndef DECODE_AIWA_RC_T501 +#define DECODE_AIWA_RC_T501 _IR_ENABLE_DEFAULT_ +#endif // DECODE_AIWA_RC_T501 +#ifndef SEND_AIWA_RC_T501 +#define SEND_AIWA_RC_T501 _IR_ENABLE_DEFAULT_ +#endif // SEND_AIWA_RC_T501 + +#ifndef DECODE_LG +#define DECODE_LG _IR_ENABLE_DEFAULT_ +#endif // DECODE_LG +#ifndef SEND_LG +#define SEND_LG _IR_ENABLE_DEFAULT_ +#endif // SEND_LG + +#ifndef DECODE_SANYO +#define DECODE_SANYO _IR_ENABLE_DEFAULT_ +#endif // DECODE_SANYO +#ifndef SEND_SANYO +#define SEND_SANYO _IR_ENABLE_DEFAULT_ +#endif // SEND_SANYO + +#ifndef DECODE_MITSUBISHI +#define DECODE_MITSUBISHI _IR_ENABLE_DEFAULT_ +#endif // DECODE_MITSUBISHI +#ifndef SEND_MITSUBISHI +#define SEND_MITSUBISHI _IR_ENABLE_DEFAULT_ +#endif // SEND_MITSUBISHI + +#ifndef DECODE_MITSUBISHI2 +#define DECODE_MITSUBISHI2 _IR_ENABLE_DEFAULT_ +#endif // DECODE_MITSUBISHI2 +#ifndef SEND_MITSUBISHI2 +#define SEND_MITSUBISHI2 _IR_ENABLE_DEFAULT_ +#endif // SEND_MITSUBISHI2 + +#ifndef DECODE_DISH +#define DECODE_DISH _IR_ENABLE_DEFAULT_ +#endif // DECODE_DISH +#ifndef SEND_DISH +#define SEND_DISH _IR_ENABLE_DEFAULT_ +#endif // SEND_DISH + +#ifndef DECODE_SHARP +#define DECODE_SHARP _IR_ENABLE_DEFAULT_ +#endif // DECODE_SHARP +#ifndef SEND_SHARP +#define SEND_SHARP _IR_ENABLE_DEFAULT_ +#endif // SEND_SHARP + +#ifndef DECODE_SHARP_AC +#define DECODE_SHARP_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_SHARP_AC +#ifndef SEND_SHARP_AC +#define SEND_SHARP_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_SHARP_AC + +#ifndef DECODE_DENON +#define DECODE_DENON _IR_ENABLE_DEFAULT_ +#endif // DECODE_DENON +#ifndef SEND_DENON +#define SEND_DENON _IR_ENABLE_DEFAULT_ +#endif // SEND_DENON + +#ifndef DECODE_KELVINATOR +#define DECODE_KELVINATOR _IR_ENABLE_DEFAULT_ +#endif // DECODE_KELVINATOR +#ifndef SEND_KELVINATOR +#define SEND_KELVINATOR _IR_ENABLE_DEFAULT_ +#endif // SEND_KELVINATOR + +#ifndef DECODE_MITSUBISHI_AC +#define DECODE_MITSUBISHI_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_MITSUBISHI_AC +#ifndef SEND_MITSUBISHI_AC +#define SEND_MITSUBISHI_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_MITSUBISHI_AC + +#ifndef DECODE_MITSUBISHI136 +#define DECODE_MITSUBISHI136 _IR_ENABLE_DEFAULT_ +#endif // DECODE_MITSUBISHI136 +#ifndef SEND_MITSUBISHI136 +#define SEND_MITSUBISHI136 _IR_ENABLE_DEFAULT_ +#endif // SEND_MITSUBISHI136 + +#ifndef DECODE_MITSUBISHI112 +#define DECODE_MITSUBISHI112 _IR_ENABLE_DEFAULT_ +#endif // DECODE_MITSUBISHI112 +#ifndef SEND_MITSUBISHI112 +#define SEND_MITSUBISHI112 _IR_ENABLE_DEFAULT_ +#endif // SEND_MITSUBISHI112 + +#ifndef DECODE_FUJITSU_AC +#define DECODE_FUJITSU_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_FUJITSU_AC +#ifndef SEND_FUJITSU_AC +#define SEND_FUJITSU_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_FUJITSU_AC + +#ifndef DECODE_INAX +#define DECODE_INAX _IR_ENABLE_DEFAULT_ +#endif // DECODE_INAX +#ifndef SEND_INAX +#define SEND_INAX _IR_ENABLE_DEFAULT_ +#endif // SEND_INAX + +#ifndef DECODE_DAIKIN +#define DECODE_DAIKIN _IR_ENABLE_DEFAULT_ +#endif // DECODE_DAIKIN +#ifndef SEND_DAIKIN +#define SEND_DAIKIN _IR_ENABLE_DEFAULT_ +#endif // SEND_DAIKIN + +#ifndef DECODE_COOLIX +#define DECODE_COOLIX _IR_ENABLE_DEFAULT_ +#endif // DECODE_COOLIX +#ifndef SEND_COOLIX +#define SEND_COOLIX _IR_ENABLE_DEFAULT_ +#endif // SEND_COOLIX + +#ifndef DECODE_GLOBALCACHE +#define DECODE_GLOBALCACHE false // Not applicable. +#endif // DECODE_GLOBALCACHE +#ifndef SEND_GLOBALCACHE +#define SEND_GLOBALCACHE _IR_ENABLE_DEFAULT_ +#endif // SEND_GLOBALCACHE + +#ifndef DECODE_GOODWEATHER +#define DECODE_GOODWEATHER _IR_ENABLE_DEFAULT_ +#endif // DECODE_GOODWEATHER +#ifndef SEND_GOODWEATHER +#define SEND_GOODWEATHER _IR_ENABLE_DEFAULT_ +#endif // SEND_GOODWEATHER + +#ifndef DECODE_GREE +#define DECODE_GREE _IR_ENABLE_DEFAULT_ +#endif // DECODE_GREE +#ifndef SEND_GREE +#define SEND_GREE _IR_ENABLE_DEFAULT_ +#endif // SEND_GREE + +#ifndef DECODE_PRONTO +#define DECODE_PRONTO false // Not applicable. +#endif // DECODE_PRONTO +#ifndef SEND_PRONTO +#define SEND_PRONTO _IR_ENABLE_DEFAULT_ +#endif // SEND_PRONTO + +#ifndef DECODE_ARGO +#define DECODE_ARGO _IR_ENABLE_DEFAULT_ +#endif // DECODE_ARGO +#ifndef SEND_ARGO +#define SEND_ARGO _IR_ENABLE_DEFAULT_ +#endif // SEND_ARGO + +#ifndef DECODE_TROTEC +#define DECODE_TROTEC _IR_ENABLE_DEFAULT_ +#endif // DECODE_TROTEC +#ifndef SEND_TROTEC +#define SEND_TROTEC _IR_ENABLE_DEFAULT_ +#endif // SEND_TROTEC + +#ifndef DECODE_NIKAI +#define DECODE_NIKAI _IR_ENABLE_DEFAULT_ +#endif // DECODE_NIKAI +#ifndef SEND_NIKAI +#define SEND_NIKAI _IR_ENABLE_DEFAULT_ +#endif // SEND_NIKAI + +#ifndef DECODE_TOSHIBA_AC +#define DECODE_TOSHIBA_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_TOSHIBA_AC +#ifndef SEND_TOSHIBA_AC +#define SEND_TOSHIBA_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_TOSHIBA_AC + +#ifndef DECODE_MAGIQUEST +#define DECODE_MAGIQUEST _IR_ENABLE_DEFAULT_ +#endif // DECODE_MAGIQUEST +#ifndef SEND_MAGIQUEST +#define SEND_MAGIQUEST _IR_ENABLE_DEFAULT_ +#endif // SEND_MAGIQUEST + +#ifndef DECODE_MIDEA +#define DECODE_MIDEA _IR_ENABLE_DEFAULT_ +#endif // DECODE_MIDEA +#ifndef SEND_MIDEA +#define SEND_MIDEA _IR_ENABLE_DEFAULT_ +#endif // SEND_MIDEA + +#ifndef DECODE_LASERTAG +#define DECODE_LASERTAG _IR_ENABLE_DEFAULT_ +#endif // DECODE_LASERTAG +#ifndef SEND_LASERTAG +#define SEND_LASERTAG _IR_ENABLE_DEFAULT_ +#endif // SEND_LASERTAG + +#ifndef DECODE_CARRIER_AC +#define DECODE_CARRIER_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_CARRIER_AC +#ifndef SEND_CARRIER_AC +#define SEND_CARRIER_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_CARRIER_AC + +#ifndef DECODE_HAIER_AC +#define DECODE_HAIER_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_HAIER_AC +#ifndef SEND_HAIER_AC +#define SEND_HAIER_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_HAIER_AC + +#ifndef DECODE_HITACHI_AC +#define DECODE_HITACHI_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_HITACHI_AC +#ifndef SEND_HITACHI_AC +#define SEND_HITACHI_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_HITACHI_AC + +#ifndef DECODE_HITACHI_AC1 +#define DECODE_HITACHI_AC1 _IR_ENABLE_DEFAULT_ +#endif // DECODE_HITACHI_AC1 +#ifndef SEND_HITACHI_AC1 +#define SEND_HITACHI_AC1 _IR_ENABLE_DEFAULT_ +#endif // SEND_HITACHI_AC1 + +#ifndef DECODE_HITACHI_AC2 +#define DECODE_HITACHI_AC2 _IR_ENABLE_DEFAULT_ +#endif // DECODE_HITACHI_AC2 +#ifndef SEND_HITACHI_AC2 +#define SEND_HITACHI_AC2 _IR_ENABLE_DEFAULT_ +#endif // SEND_HITACHI_AC2 + +#ifndef DECODE_GICABLE +#define DECODE_GICABLE _IR_ENABLE_DEFAULT_ +#endif // DECODE_GICABLE +#ifndef SEND_GICABLE +#define SEND_GICABLE _IR_ENABLE_DEFAULT_ +#endif // SEND_GICABLE + +#ifndef DECODE_HAIER_AC_YRW02 +#define DECODE_HAIER_AC_YRW02 _IR_ENABLE_DEFAULT_ +#endif // DECODE_HAIER_AC_YRW02 +#ifndef SEND_HAIER_AC_YRW02 +#define SEND_HAIER_AC_YRW02 _IR_ENABLE_DEFAULT_ +#endif // SEND_HAIER_AC_YRW02 + +#ifndef DECODE_WHIRLPOOL_AC +#define DECODE_WHIRLPOOL_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_WHIRLPOOL_AC +#ifndef SEND_WHIRLPOOL_AC +#define SEND_WHIRLPOOL_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_WHIRLPOOL_AC + +#ifndef DECODE_LUTRON +#define DECODE_LUTRON _IR_ENABLE_DEFAULT_ +#endif // DECODE_LUTRON +#ifndef SEND_LUTRON +#define SEND_LUTRON _IR_ENABLE_DEFAULT_ +#endif // SEND_LUTRON + +#ifndef DECODE_ELECTRA_AC +#define DECODE_ELECTRA_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_ELECTRA_AC +#ifndef SEND_ELECTRA_AC +#define SEND_ELECTRA_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_ELECTRA_AC + +#ifndef DECODE_PANASONIC_AC +#define DECODE_PANASONIC_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_PANASONIC_AC +#ifndef SEND_PANASONIC_AC +#define SEND_PANASONIC_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_PANASONIC_AC + +#ifndef DECODE_MWM +#define DECODE_MWM _IR_ENABLE_DEFAULT_ +#endif // DECODE_MWM +#ifndef SEND_MWM +#define SEND_MWM _IR_ENABLE_DEFAULT_ +#endif // SEND_MWM + +#ifndef DECODE_PIONEER +#define DECODE_PIONEER _IR_ENABLE_DEFAULT_ +#endif // DECODE_PIONEER +#ifndef SEND_PIONEER +#define SEND_PIONEER _IR_ENABLE_DEFAULT_ +#endif // SEND_PIONEER + +#ifndef DECODE_DAIKIN2 +#define DECODE_DAIKIN2 _IR_ENABLE_DEFAULT_ +#endif // DECODE_DAIKIN2 +#ifndef SEND_DAIKIN2 +#define SEND_DAIKIN2 _IR_ENABLE_DEFAULT_ +#endif // SEND_DAIKIN2 + +#ifndef DECODE_VESTEL_AC +#define DECODE_VESTEL_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_VESTEL_AC +#ifndef SEND_VESTEL_AC +#define SEND_VESTEL_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_VESTEL_AC + +#ifndef DECODE_TECO +#define DECODE_TECO _IR_ENABLE_DEFAULT_ +#endif // DECODE_TECO +#ifndef SEND_TECO +#define SEND_TECO _IR_ENABLE_DEFAULT_ +#endif // SEND_TECO + +#ifndef DECODE_TCL112AC +#define DECODE_TCL112AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_TCL112AC +#ifndef SEND_TCL112AC +#define SEND_TCL112AC _IR_ENABLE_DEFAULT_ +#endif // SEND_TCL112AC + +#ifndef DECODE_LEGOPF +#define DECODE_LEGOPF _IR_ENABLE_DEFAULT_ +#endif // DECODE_LEGOPF +#ifndef SEND_LEGOPF +#define SEND_LEGOPF _IR_ENABLE_DEFAULT_ +#endif // SEND_LEGOPF + +#ifndef DECODE_MITSUBISHIHEAVY +#define DECODE_MITSUBISHIHEAVY _IR_ENABLE_DEFAULT_ +#endif // DECODE_MITSUBISHIHEAVY +#ifndef SEND_MITSUBISHIHEAVY +#define SEND_MITSUBISHIHEAVY _IR_ENABLE_DEFAULT_ +#endif // SEND_MITSUBISHIHEAVY + +#ifndef DECODE_DAIKIN216 +#define DECODE_DAIKIN216 _IR_ENABLE_DEFAULT_ +#endif // DECODE_DAIKIN216 +#ifndef SEND_DAIKIN216 +#define SEND_DAIKIN216 _IR_ENABLE_DEFAULT_ +#endif // SEND_DAIKIN216 + +#ifndef DECODE_DAIKIN160 +#define DECODE_DAIKIN160 _IR_ENABLE_DEFAULT_ +#endif // DECODE_DAIKIN160 +#ifndef SEND_DAIKIN160 +#define SEND_DAIKIN160 _IR_ENABLE_DEFAULT_ +#endif // SEND_DAIKIN160 + +#ifndef DECODE_NEOCLIMA +#define DECODE_NEOCLIMA _IR_ENABLE_DEFAULT_ +#endif // DECODE_NEOCLIMA +#ifndef SEND_NEOCLIMA +#define SEND_NEOCLIMA _IR_ENABLE_DEFAULT_ +#endif // SEND_NEOCLIMA + +#ifndef DECODE_DAIKIN176 +#define DECODE_DAIKIN176 _IR_ENABLE_DEFAULT_ +#endif // DECODE_DAIKIN176 +#ifndef SEND_DAIKIN176 +#define SEND_DAIKIN176 _IR_ENABLE_DEFAULT_ +#endif // SEND_DAIKIN176 + +#ifndef DECODE_DAIKIN128 +#define DECODE_DAIKIN128 _IR_ENABLE_DEFAULT_ +#endif // DECODE_DAIKIN128 +#ifndef SEND_DAIKIN128 +#define SEND_DAIKIN128 _IR_ENABLE_DEFAULT_ +#endif // SEND_DAIKIN128 + +#ifndef DECODE_AMCOR +#define DECODE_AMCOR _IR_ENABLE_DEFAULT_ +#endif // DECODE_AMCOR +#ifndef SEND_AMCOR +#define SEND_AMCOR _IR_ENABLE_DEFAULT_ +#endif // SEND_AMCOR + +#ifndef DECODE_DAIKIN152 +#define DECODE_DAIKIN152 _IR_ENABLE_DEFAULT_ +#endif // DECODE_DAIKIN152 +#ifndef SEND_DAIKIN152 +#define SEND_DAIKIN152 _IR_ENABLE_DEFAULT_ +#endif // SEND_DAIKIN152 + +#ifndef DECODE_HITACHI_AC424 +#define DECODE_HITACHI_AC424 _IR_ENABLE_DEFAULT_ +#endif // DECODE_HITACHI_AC424 +#ifndef SEND_HITACHI_AC424 +#define SEND_HITACHI_AC424 _IR_ENABLE_DEFAULT_ +#endif // SEND_HITACHI_AC424 #if (DECODE_ARGO || DECODE_DAIKIN || DECODE_FUJITSU_AC || DECODE_GREE || \ DECODE_KELVINATOR || DECODE_MITSUBISHI_AC || DECODE_TOSHIBA_AC || \ @@ -495,7 +585,9 @@ // Note: If you plan to send IR messages in the callbacks of the AsyncWebserver // library, you need to set ALLOW_DELAY_CALLS to false. // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/430 +#ifndef ALLOW_DELAY_CALLS #define ALLOW_DELAY_CALLS true +#endif // ALLOW_DELAY_CALLS /* * Always add to the end of the list and should never remove entries @@ -578,8 +670,9 @@ enum decode_type_t { MITSUBISHI136, MITSUBISHI112, HITACHI_AC424, + SONY_38K, // Add new entries before this one, and update it to point to the last entry. - kLastDecodeType = HITACHI_AC424, + kLastDecodeType = SONY_38K, }; // Message lengths & required repeat values @@ -588,6 +681,7 @@ const uint16_t kSingleRepeat = 1; const uint16_t kAiwaRcT501Bits = 15; const uint16_t kAiwaRcT501MinRepeats = kSingleRepeat; +const uint16_t kAlokaBits = 32; const uint16_t kAmcorStateLength = 8; const uint16_t kAmcorBits = kAmcorStateLength * 8; const uint16_t kAmcorDefaultRepeat = kSingleRepeat; @@ -668,6 +762,7 @@ const uint16_t kLegoPfBits = 16; const uint16_t kLegoPfMinRepeat = kNoRepeat; const uint16_t kLgBits = 28; const uint16_t kLg32Bits = 32; +const uint16_t kLgDefaultRepeat = kNoRepeat; const uint16_t kLutronBits = 35; const uint16_t kMagiquestBits = 56; const uint16_t kMideaBits = 48; diff --git a/lib/IRremoteESP8266-2.7.1/src/IRsend.cpp b/lib/IRremoteESP8266-2.7.3/src/IRsend.cpp similarity index 99% rename from lib/IRremoteESP8266-2.7.1/src/IRsend.cpp rename to lib/IRremoteESP8266-2.7.3/src/IRsend.cpp index 18e2eb559..4bc16a75c 100644 --- a/lib/IRremoteESP8266-2.7.1/src/IRsend.cpp +++ b/lib/IRremoteESP8266-2.7.3/src/IRsend.cpp @@ -515,6 +515,8 @@ uint16_t IRsend::minRepeats(const decode_type_t protocol) { return kDishMinRepeat; case SONY: return kSonyMinRepeat; + case SONY_38K: + return kSonyMinRepeat + 1; default: return kNoRepeat; } @@ -545,6 +547,7 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return 16; case RC6: case SONY: + case SONY_38K: return 20; case COOLIX: case INAX: @@ -818,6 +821,9 @@ bool IRsend::send(const decode_type_t type, const uint64_t data, case SONY: sendSony(data, nbits, min_repeat); break; + case SONY_38K: + sendSony38(data, nbits, min_repeat); + break; #endif #if SEND_TECO case TECO: diff --git a/lib/IRremoteESP8266-2.7.1/src/IRsend.h b/lib/IRremoteESP8266-2.7.3/src/IRsend.h similarity index 98% rename from lib/IRremoteESP8266-2.7.1/src/IRsend.h rename to lib/IRremoteESP8266-2.7.3/src/IRsend.h index b0956e77c..ff801210d 100644 --- a/lib/IRremoteESP8266-2.7.1/src/IRsend.h +++ b/lib/IRremoteESP8266-2.7.3/src/IRsend.h @@ -130,7 +130,7 @@ enum panasonic_ac_remote_model_t { kPanasonicUnknown = 0, kPanasonicLke = 1, kPanasonicNke = 2, - kPanasonicDke = 3, + kPanasonicDke = 3, // PKR too. kPanasonicJke = 4, kPanasonicCkp = 5, kPanasonicRkr = 6, @@ -141,6 +141,11 @@ enum whirlpool_ac_remote_model_t { DG11J191, }; +enum lg_ac_remote_model_t { + GE6711AR2853M = 1, // (1) LG 28-bit Protocol (default) + AKB75215403, // (2) LG2 28-bit Protocol +}; + // Classes class IRsend { @@ -198,6 +203,8 @@ class IRsend { // a Sony command that will be accepted be a device. void sendSony(uint64_t data, uint16_t nbits = kSony20Bits, uint16_t repeat = kSonyMinRepeat); + void sendSony38(uint64_t data, uint16_t nbits = kSony20Bits, + uint16_t repeat = kSonyMinRepeat + 1); uint32_t encodeSony(uint16_t nbits, uint16_t command, uint16_t address, uint16_t extended = 0); #endif @@ -556,6 +563,10 @@ class IRsend { uint8_t _dutycycle; bool modulation; uint32_t calcUSecPeriod(uint32_t hz, bool use_offset = true); +#if SEND_SONY + void _sendSony(uint64_t data, uint16_t nbits, + uint16_t repeat, uint16_t freq); +#endif }; #endif // IRSEND_H_ diff --git a/lib/IRremoteESP8266-2.7.1/src/IRtext.cpp b/lib/IRremoteESP8266-2.7.3/src/IRtext.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/IRtext.cpp rename to lib/IRremoteESP8266-2.7.3/src/IRtext.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/IRtext.h b/lib/IRremoteESP8266-2.7.3/src/IRtext.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/IRtext.h rename to lib/IRremoteESP8266-2.7.3/src/IRtext.h diff --git a/lib/IRremoteESP8266-2.7.1/src/IRtimer.cpp b/lib/IRremoteESP8266-2.7.3/src/IRtimer.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/IRtimer.cpp rename to lib/IRremoteESP8266-2.7.3/src/IRtimer.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/IRtimer.h b/lib/IRremoteESP8266-2.7.3/src/IRtimer.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/IRtimer.h rename to lib/IRremoteESP8266-2.7.3/src/IRtimer.h diff --git a/lib/IRremoteESP8266-2.7.1/src/IRutils.cpp b/lib/IRremoteESP8266-2.7.3/src/IRutils.cpp similarity index 98% rename from lib/IRremoteESP8266-2.7.1/src/IRutils.cpp rename to lib/IRremoteESP8266-2.7.3/src/IRutils.cpp index 0aa19e821..bbb9ed491 100644 --- a/lib/IRremoteESP8266-2.7.1/src/IRutils.cpp +++ b/lib/IRremoteESP8266-2.7.3/src/IRutils.cpp @@ -228,6 +228,8 @@ decode_type_t strToDecodeType(const char * const str) { return decode_type_t::SHERWOOD; else if (!strcasecmp(str, "SONY")) return decode_type_t::SONY; + else if (!strcasecmp(str, "SONY_38K")) + return decode_type_t::SONY_38K; else if (!strcasecmp(str, "TCL112AC")) return decode_type_t::TCL112AC; else if (!strcasecmp(str, "TECO")) @@ -461,6 +463,9 @@ String typeToString(const decode_type_t protocol, const bool isRepeat) { case SONY: result = F("SONY"); break; + case SONY_38K: + result = F("SONY_38K"); + break; case TCL112AC: result = F("TCL112AC"); break; @@ -824,13 +829,6 @@ namespace irutils { String modelToStr(const decode_type_t protocol, const int16_t model) { switch (protocol) { - case decode_type_t::GREE: - switch (model) { - case gree_ac_remote_model_t::YAW1F: return F("YAW1F"); - case gree_ac_remote_model_t::YBOFB: return F("YBOFB"); - default: return kUnknownStr; - } - break; case decode_type_t::FUJITSU_AC: switch (model) { case fujitsu_ac_remote_model_t::ARRAH2E: return F("ARRAH2E"); @@ -841,6 +839,21 @@ namespace irutils { default: return kUnknownStr; } break; + case decode_type_t::GREE: + switch (model) { + case gree_ac_remote_model_t::YAW1F: return F("YAW1F"); + case gree_ac_remote_model_t::YBOFB: return F("YBOFB"); + default: return kUnknownStr; + } + break; + case decode_type_t::LG: + case decode_type_t::LG2: + switch (model) { + case lg_ac_remote_model_t::GE6711AR2853M: return F("GE6711AR2853M"); + case lg_ac_remote_model_t::AKB75215403: return F("AKB75215403"); + default: return kUnknownStr; + } + break; case decode_type_t::PANASONIC_AC: switch (model) { case panasonic_ac_remote_model_t::kPanasonicLke: return F("LKE"); diff --git a/lib/IRremoteESP8266-2.7.1/src/IRutils.h b/lib/IRremoteESP8266-2.7.3/src/IRutils.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/IRutils.h rename to lib/IRremoteESP8266-2.7.3/src/IRutils.h diff --git a/lib/IRremoteESP8266-2.7.1/src/i18n.h b/lib/IRremoteESP8266-2.7.3/src/i18n.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/i18n.h rename to lib/IRremoteESP8266-2.7.3/src/i18n.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Aiwa.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Aiwa.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Aiwa.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Aiwa.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Amcor.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Amcor.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Amcor.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Amcor.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Amcor.h b/lib/IRremoteESP8266-2.7.3/src/ir_Amcor.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Amcor.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Amcor.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Argo.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Argo.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Argo.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Argo.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Argo.h b/lib/IRremoteESP8266-2.7.3/src/ir_Argo.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Argo.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Argo.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Carrier.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Carrier.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Carrier.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Carrier.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Coolix.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Coolix.cpp similarity index 97% rename from lib/IRremoteESP8266-2.7.1/src/ir_Coolix.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Coolix.cpp index 0dbd68d63..8b184bf9f 100644 --- a/lib/IRremoteESP8266-2.7.1/src/ir_Coolix.cpp +++ b/lib/IRremoteESP8266-2.7.3/src/ir_Coolix.cpp @@ -27,16 +27,16 @@ // Pulse parms are *50-100 for the Mark and *50+100 for the space // First MARK is the one after the long gap // pulse parameters in usec -const uint16_t kCoolixTick = 560; // Approximately 21 cycles at 38kHz -const uint16_t kCoolixBitMarkTicks = 1; +const uint16_t kCoolixTick = 276; // Approximately 10.5 cycles at 38kHz +const uint16_t kCoolixBitMarkTicks = 2; const uint16_t kCoolixBitMark = kCoolixBitMarkTicks * kCoolixTick; -const uint16_t kCoolixOneSpaceTicks = 3; +const uint16_t kCoolixOneSpaceTicks = 6; const uint16_t kCoolixOneSpace = kCoolixOneSpaceTicks * kCoolixTick; -const uint16_t kCoolixZeroSpaceTicks = 1; +const uint16_t kCoolixZeroSpaceTicks = 2; const uint16_t kCoolixZeroSpace = kCoolixZeroSpaceTicks * kCoolixTick; -const uint16_t kCoolixHdrMarkTicks = 8; +const uint16_t kCoolixHdrMarkTicks = 17; const uint16_t kCoolixHdrMark = kCoolixHdrMarkTicks * kCoolixTick; -const uint16_t kCoolixHdrSpaceTicks = 8; +const uint16_t kCoolixHdrSpaceTicks = 16; const uint16_t kCoolixHdrSpace = kCoolixHdrSpaceTicks * kCoolixTick; const uint16_t kCoolixMinGapTicks = kCoolixHdrMarkTicks + kCoolixZeroSpaceTicks; const uint16_t kCoolixMinGap = kCoolixMinGapTicks * kCoolixTick; @@ -57,11 +57,10 @@ using irutils::setBits; // nbits: Nr. of bits of data to be sent. Typically kCoolixBits. // repeat: Nr. of additional times the message is to be sent. // -// Status: BETA / Probably works. +// Status: STABLE / Confirmed Working. // // Ref: // https://github.com/z3t0/Arduino-IRremote/blob/master/ir_COOLIX.cpp -// TODO(anyone): Verify repeat functionality against a real unit. void IRsend::sendCOOLIX(uint64_t data, uint16_t nbits, uint16_t repeat) { if (nbits % 8 != 0) return; // nbits is required to be a multiple of 8. @@ -443,7 +442,11 @@ stdAc::state_t IRCoolixAC::toCommon(const stdAc::state_t *prev) { } else { // Set defaults for non-zero values that are not implicitly set for when // there is no previous state. + // e.g. Any setting that toggles should probably go here. result.swingv = stdAc::swingv_t::kOff; + result.turbo = false; + result.clean = false; + result.light = false; result.sleep = -1; } // Not supported. diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Coolix.h b/lib/IRremoteESP8266-2.7.3/src/ir_Coolix.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Coolix.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Coolix.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Daikin.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Daikin.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Daikin.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Daikin.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Daikin.h b/lib/IRremoteESP8266-2.7.3/src/ir_Daikin.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Daikin.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Daikin.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Denon.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Denon.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Denon.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Denon.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Dish.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Dish.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Dish.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Dish.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Electra.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Electra.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Electra.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Electra.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Electra.h b/lib/IRremoteESP8266-2.7.3/src/ir_Electra.h similarity index 97% rename from lib/IRremoteESP8266-2.7.1/src/ir_Electra.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Electra.h index ef28b44cf..a120bcd28 100644 --- a/lib/IRremoteESP8266-2.7.1/src/ir_Electra.h +++ b/lib/IRremoteESP8266-2.7.3/src/ir_Electra.h @@ -19,6 +19,8 @@ // Supports: // Brand: AUX, Model: KFR-35GW/BpNFW=3 A/C // Brand: AUX, Model: YKR-T/011 remote +// Brand: Electra, Model: Classic INV 17 / AXW12DCS A/C +// Brand: Electra, Model: YKR-M/003E remote // Ref: // https://github.com/ToniA/arduino-heatpumpir/blob/master/AUXHeatpumpIR.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Fujitsu.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Fujitsu.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Fujitsu.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Fujitsu.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Fujitsu.h b/lib/IRremoteESP8266-2.7.3/src/ir_Fujitsu.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Fujitsu.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Fujitsu.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_GICable.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_GICable.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_GICable.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_GICable.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_GlobalCache.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_GlobalCache.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_GlobalCache.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_GlobalCache.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Goodweather.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Goodweather.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Goodweather.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Goodweather.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Goodweather.h b/lib/IRremoteESP8266-2.7.3/src/ir_Goodweather.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Goodweather.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Goodweather.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Gree.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Gree.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Gree.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Gree.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Gree.h b/lib/IRremoteESP8266-2.7.3/src/ir_Gree.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Gree.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Gree.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Haier.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Haier.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Haier.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Haier.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Haier.h b/lib/IRremoteESP8266-2.7.3/src/ir_Haier.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Haier.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Haier.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Hitachi.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Hitachi.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Hitachi.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Hitachi.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Hitachi.h b/lib/IRremoteESP8266-2.7.3/src/ir_Hitachi.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Hitachi.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Hitachi.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Inax.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Inax.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Inax.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Inax.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_JVC.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_JVC.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_JVC.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_JVC.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Kelvinator.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Kelvinator.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Kelvinator.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Kelvinator.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Kelvinator.h b/lib/IRremoteESP8266-2.7.3/src/ir_Kelvinator.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Kelvinator.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Kelvinator.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_LG.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_LG.cpp similarity index 56% rename from lib/IRremoteESP8266-2.7.1/src/ir_LG.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_LG.cpp index 124256e9f..ce0a36d3d 100644 --- a/lib/IRremoteESP8266-2.7.1/src/ir_LG.cpp +++ b/lib/IRremoteESP8266-2.7.3/src/ir_LG.cpp @@ -8,10 +8,20 @@ #include "ir_LG.h" #include +#include "IRac.h" #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" #include "IRutils.h" +using irutils::addBoolToString; +using irutils::addModeToString; +using irutils::addModelToString; +using irutils::addFanToString; +using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; + // LG decode originally added by Darryl Smith (based on the JVC protocol) // LG send originally added by https://github.com/chaeplin @@ -283,3 +293,254 @@ bool IRrecv::decodeLG(decode_results *results, uint16_t nbits, bool strict) { return true; } #endif + +// LG A/C Class +// Support for LG-type A/C units. +// Ref: +// https://github.com/arendst/Tasmota/blob/54c2eb283a02e4287640a4595e506bc6eadbd7f2/sonoff/xdrv_05_irremote.ino#L327-438 +IRLgAc::IRLgAc(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { this->stateReset(); } + +void IRLgAc::stateReset(void) { + setRaw(kLgAcOffCommand); + setModel(lg_ac_remote_model_t::GE6711AR2853M); +} + +void IRLgAc::begin(void) { _irsend.begin(); } + +#if SEND_LG +void IRLgAc::send(const uint16_t repeat) { + if (this->getPower()) + _irsend.send(this->_protocol, this->getRaw(), kLgBits, repeat); + else + // Always send the special Off command if the power is set to off. + // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1008#issuecomment-570763580 + _irsend.send(this->_protocol, kLgAcOffCommand, kLgBits, repeat); +} +#endif // SEND_LG + +void IRLgAc::setModel(const lg_ac_remote_model_t model) { + switch (model) { + case lg_ac_remote_model_t::AKB75215403: + _protocol = decode_type_t::LG2; + break; + case lg_ac_remote_model_t::GE6711AR2853M: + // FALL THRU + default: + _protocol = decode_type_t::LG; + } +} + +lg_ac_remote_model_t IRLgAc::getModel(void) { + switch (_protocol) { + case LG2: + return lg_ac_remote_model_t::AKB75215403; + case LG: + // FALL THRU + default: + return lg_ac_remote_model_t::GE6711AR2853M; + } +} + +uint32_t IRLgAc::getRaw(void) { + checksum(); + return remote_state; +} + +void IRLgAc::setRaw(const uint32_t new_code) { + remote_state = new_code; + _temp = 15; // Ensure there is a "sane" previous temp. + _temp = getTemp(); +} + +// Calculate the checksum for a given state. +// Args: +// state: The value to calculate the checksum of. +// Returns: +// A uint8_t of the checksum. +uint8_t IRLgAc::calcChecksum(const uint32_t state) { + return calcLGChecksum(state >> 4); +} + +// Verify the checksum is valid for a given state. +// Args: +// state: The value to verify the checksum of. +// Returns: +// A boolean. +bool IRLgAc::validChecksum(const uint32_t state) { + return calcChecksum(state) == GETBITS32(state, kLgAcChecksumOffset, + kLgAcChecksumSize); +} + +void IRLgAc::checksum(void) { + setBits(&remote_state, kLgAcChecksumOffset, kLgAcChecksumSize, + calcChecksum(remote_state)); +} + +void IRLgAc::on(void) { setPower(true); } + +void IRLgAc::off(void) { setPower(false); } + +void IRLgAc::setPower(const bool on) { + setBits(&remote_state, kLgAcPowerOffset, kLgAcPowerSize, + on ? kLgAcPowerOn : kLgAcPowerOff); + if (on) + setTemp(_temp); // Reset the temp if we are on. + else + _setTemp(0); // Off clears the temp. +} + +bool IRLgAc::getPower(void) { + return GETBITS32(remote_state, kLgAcPowerOffset, kLgAcPowerSize) == + kLgAcPowerOn; +} + +// Set the temp. (Internal use only) +void IRLgAc::_setTemp(const uint8_t value) { + setBits(&remote_state, kLgAcTempOffset, kLgAcTempSize, value); +} + +// Set the temp. in deg C +void IRLgAc::setTemp(const uint8_t degrees) { + uint8_t temp = std::max(kLgAcMinTemp, degrees); + temp = std::min(kLgAcMaxTemp, temp); + _temp = temp; + _setTemp(temp - kLgAcTempAdjust); +} + +// Return the set temp. in deg C +uint8_t IRLgAc::getTemp(void) { + if (getPower()) + return GETBITS32(remote_state, kLgAcTempOffset, kLgAcTempSize) + + kLgAcTempAdjust; + else + return _temp; +} + +// Set the speed of the fan. +void IRLgAc::setFan(const uint8_t speed) { + switch (speed) { + case kLgAcFanAuto: + case kLgAcFanLow: + case kLgAcFanMedium: + case kLgAcFanHigh: + setBits(&remote_state, kLgAcFanOffset, kLgAcFanSize, speed); + break; + default: + setFan(kLgAcFanAuto); + } +} + +uint8_t IRLgAc::getFan(void) { + return GETBITS32(remote_state, kLgAcFanOffset, kLgAcFanSize); +} + +uint8_t IRLgAc::getMode(void) { + return GETBITS32(remote_state, kLgAcModeOffset, kLgAcModeSize); +} + +void IRLgAc::setMode(const uint8_t mode) { + switch (mode) { + case kLgAcAuto: + case kLgAcDry: + case kLgAcHeat: + case kLgAcCool: + case kLgAcFan: + setBits(&remote_state, kLgAcModeOffset, kLgAcModeSize, mode); + break; + default: // If we get an unexpected mode, default to AUTO. + this->setMode(kLgAcAuto); + } +} + +// Convert a standard A/C mode into its native mode. +uint8_t IRLgAc::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: return kLgAcCool; + case stdAc::opmode_t::kHeat: return kLgAcHeat; + case stdAc::opmode_t::kFan: return kLgAcFan; + case stdAc::opmode_t::kDry: return kLgAcDry; + default: return kLgAcAuto; + } +} + +// Convert a native mode to it's common equivalent. +stdAc::opmode_t IRLgAc::toCommonMode(const uint8_t mode) { + switch (mode) { + case kLgAcCool: return stdAc::opmode_t::kCool; + case kLgAcHeat: return stdAc::opmode_t::kHeat; + case kLgAcDry: return stdAc::opmode_t::kDry; + case kLgAcFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; + } +} + +// Convert a standard A/C Fan speed into its native fan speed. +uint8_t IRLgAc::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: + case stdAc::fanspeed_t::kLow: return kLgAcFanLow; + case stdAc::fanspeed_t::kMedium: return kLgAcFanMedium; + case stdAc::fanspeed_t::kHigh: + case stdAc::fanspeed_t::kMax: return kHitachiAcFanHigh; + default: return kHitachiAcFanAuto; + } +} + +// Convert a native fan speed to it's common equivalent. +stdAc::fanspeed_t IRLgAc::toCommonFanSpeed(const uint8_t speed) { + switch (speed) { + case kLgAcFanHigh: return stdAc::fanspeed_t::kMax; + case kLgAcFanMedium: return stdAc::fanspeed_t::kMedium; + case kLgAcFanLow: return stdAc::fanspeed_t::kLow; + default: return stdAc::fanspeed_t::kAuto; + } +} + +// Convert the A/C state to it's common equivalent. +stdAc::state_t IRLgAc::toCommon(void) { + stdAc::state_t result; + result.protocol = decode_type_t::LG; + result.model = this->getModel(); + result.power = this->getPower(); + result.mode = this->toCommonMode(this->getMode()); + result.celsius = true; + result.degrees = this->getTemp(); + result.fanspeed = this->toCommonFanSpeed(this->getFan()); + // Not supported. + result.swingv = stdAc::swingv_t::kOff; + result.swingh = stdAc::swingh_t::kOff; + result.quiet = false; + result.turbo = false; + result.light = false; + result.filter = false; + result.clean = false; + result.econo = false; + result.beep = false; + result.sleep = -1; + result.clock = -1; + return result; +} + +// Convert the internal state into a human readable string. +String IRLgAc::toString(void) { + String result = ""; + result.reserve(80); // Reserve some heap for the string to reduce fragging. + result += addModelToString(_protocol, getModel(), false); + result += addBoolToString(getPower(), kPowerStr); + if (getPower()) { // Only display the rest if is in power on state. + result += addModeToString(getMode(), kLgAcAuto, kLgAcCool, + kLgAcHeat, kLgAcDry, kLgAcFan); + result += addTempToString(getTemp()); + result += addFanToString(getFan(), kLgAcFanHigh, kLgAcFanLow, + kLgAcFanAuto, kLgAcFanAuto, kLgAcFanMedium); + } + return result; +} + +bool IRLgAc::isValidLgAc(void) { + return validChecksum(remote_state) && + (GETBITS32(remote_state, kLgAcSignatureOffset, kLgAcSignatureSize) == + kLgAcSignature); +} diff --git a/lib/IRremoteESP8266-2.7.3/src/ir_LG.h b/lib/IRremoteESP8266-2.7.3/src/ir_LG.h new file mode 100644 index 000000000..1147b30b7 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.3/src/ir_LG.h @@ -0,0 +1,108 @@ +// Copyright 2017, 2019 David Conran + +// Supports: +// Brand: LG, Model: 6711A20083V remote +// Brand: LG, Model: AKB74395308 remote +// Brand: LG, Model: S4-W12JA3AA A/C (LG2) +// Brand: LG, Model: AKB75215403 remote (LG2) +// Brand: General Electric, Model: AG1BH09AW101 Split A/C +// Brand: General Electric, Model: 6711AR2853M A/C Remote + +#ifndef IR_LG_H_ +#define IR_LG_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifndef UNIT_TEST +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" +#include "IRutils.h" +#ifdef UNIT_TEST +#include "IRsend_test.h" +#endif + +const uint8_t kLgAcChecksumOffset = 0; // Nr. of bits +const uint8_t kLgAcChecksumSize = kNibbleSize; // Nr. of bits +const uint8_t kLgAcFanOffset = 4; // Nr. of bits +const uint8_t kLgAcFanSize = 3; // Nr. of bits +const uint8_t kLgAcFanLow = 0; // 0b000 +const uint8_t kLgAcFanMedium = 2; // 0b010 +const uint8_t kLgAcFanHigh = 4; // 0b100 +const uint8_t kLgAcFanAuto = 5; // 0b101 +const uint8_t kLgAcTempOffset = 8; // Nr. of bits +const uint8_t kLgAcTempSize = 4; // Nr. of bits +const uint8_t kLgAcTempAdjust = 15; +const uint8_t kLgAcMinTemp = 16; // Celsius +const uint8_t kLgAcMaxTemp = 30; // Celsius +const uint8_t kLgAcModeOffset = 12; // Nr. of bits +const uint8_t kLgAcModeSize = 3; // Nr. of bits +const uint8_t kLgAcCool = 0; // 0b000 +const uint8_t kLgAcDry = 1; // 0b001 +const uint8_t kLgAcFan = 2; // 0b010 +const uint8_t kLgAcAuto = 3; // 0b011 +const uint8_t kLgAcHeat = 4; // 0b100 +const uint8_t kLgAcPowerOffset = 18; // Nr. of bits +const uint8_t kLgAcPowerSize = 2; // Nr. of bits +const uint8_t kLgAcPowerOff = 3; // 0b11 +const uint8_t kLgAcPowerOn = 0; // 0b00 +const uint8_t kLgAcSignatureOffset = 20; // Nr. of bits +const uint8_t kLgAcSignatureSize = 8; // Nr. of bits +const uint8_t kLgAcSignature = 0x88; + +const uint32_t kLgAcOffCommand = 0x88C0051; + +uint8_t calcLGChecksum(uint16_t data); + +// Classes +class IRLgAc { + public: + explicit IRLgAc(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + + void stateReset(void); + static uint8_t calcChecksum(const uint32_t state); + static bool validChecksum(const uint32_t state); + bool isValidLgAc(void); +#if SEND_LG + void send(const uint16_t repeat = kLgDefaultRepeat); + uint8_t calibrate(void) { return _irsend.calibrate(); } +#endif // SEND_LG + void begin(void); + void on(void); + void off(void); + void setPower(const bool on); + bool getPower(void); + void setTemp(const uint8_t degrees); + uint8_t getTemp(void); + void setFan(const uint8_t speed); + uint8_t getFan(void); + void setMode(const uint8_t mode); + uint8_t getMode(void); + uint32_t getRaw(void); + void setRaw(const uint32_t new_code); + uint8_t convertMode(const stdAc::opmode_t mode); + static stdAc::opmode_t toCommonMode(const uint8_t mode); + static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); + static uint8_t convertFan(const stdAc::fanspeed_t speed); + stdAc::state_t toCommon(void); + String toString(void); + void setModel(const lg_ac_remote_model_t model); + lg_ac_remote_model_t getModel(void); +#ifndef UNIT_TEST + + private: + IRsend _irsend; +#else + IRsendTest _irsend; +#endif + // The state of the IR remote in IR code form. + uint32_t remote_state; + uint8_t _temp; + decode_type_t _protocol; + void checksum(void); + void _setTemp(const uint8_t value); +}; + +#endif // IR_LG_H_ diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Lasertag.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Lasertag.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Lasertag.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Lasertag.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Lego.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Lego.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Lego.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Lego.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Lutron.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Lutron.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Lutron.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Lutron.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_MWM.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_MWM.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_MWM.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_MWM.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Magiquest.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Magiquest.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Magiquest.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Magiquest.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Magiquest.h b/lib/IRremoteESP8266-2.7.3/src/ir_Magiquest.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Magiquest.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Magiquest.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Midea.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Midea.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Midea.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Midea.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Midea.h b/lib/IRremoteESP8266-2.7.3/src/ir_Midea.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Midea.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Midea.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Mitsubishi.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Mitsubishi.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Mitsubishi.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Mitsubishi.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Mitsubishi.h b/lib/IRremoteESP8266-2.7.3/src/ir_Mitsubishi.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Mitsubishi.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Mitsubishi.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_MitsubishiHeavy.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_MitsubishiHeavy.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_MitsubishiHeavy.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_MitsubishiHeavy.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_MitsubishiHeavy.h b/lib/IRremoteESP8266-2.7.3/src/ir_MitsubishiHeavy.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_MitsubishiHeavy.h rename to lib/IRremoteESP8266-2.7.3/src/ir_MitsubishiHeavy.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_NEC.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_NEC.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_NEC.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_NEC.cpp diff --git a/lib/IRremoteESP8266-2.7.3/src/ir_NEC.h b/lib/IRremoteESP8266-2.7.3/src/ir_NEC.h new file mode 100644 index 000000000..cf6191100 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.3/src/ir_NEC.h @@ -0,0 +1,74 @@ +// Copyright 2009 Ken Shirriff +// Copyright 2017, 2018 David Conran + +// NEC originally added from https://github.com/shirriff/Arduino-IRremote/ + +#ifndef IR_NEC_H_ +#define IR_NEC_H_ + +#include +#include "IRremoteESP8266.h" + +// Supports: +// Brand: Yamaha, Model: RAV561 remote +// Brand: Yamaha, Model: RXV585B A/V Receiver +// Brand: Aloka, Model: SleepyLights LED Lamp +// Brand: Toshiba, Model: 42TL838 LCD TV + +// Constants +// Ref: +// http://www.sbprojects.com/knowledge/ir/nec.php +const uint16_t kNecTick = 560; +const uint16_t kNecHdrMarkTicks = 16; +const uint16_t kNecHdrMark = kNecHdrMarkTicks * kNecTick; +const uint16_t kNecHdrSpaceTicks = 8; +const uint16_t kNecHdrSpace = kNecHdrSpaceTicks * kNecTick; +const uint16_t kNecBitMarkTicks = 1; +const uint16_t kNecBitMark = kNecBitMarkTicks * kNecTick; +const uint16_t kNecOneSpaceTicks = 3; +const uint16_t kNecOneSpace = kNecOneSpaceTicks * kNecTick; +const uint16_t kNecZeroSpaceTicks = 1; +const uint16_t kNecZeroSpace = kNecZeroSpaceTicks * kNecTick; +const uint16_t kNecRptSpaceTicks = 4; +const uint16_t kNecRptSpace = kNecRptSpaceTicks * kNecTick; +const uint16_t kNecRptLength = 4; +const uint16_t kNecMinCommandLengthTicks = 193; +const uint32_t kNecMinCommandLength = kNecMinCommandLengthTicks * kNecTick; +const uint32_t kNecMinGap = + kNecMinCommandLength - + (kNecHdrMark + kNecHdrSpace + kNECBits * (kNecBitMark + kNecOneSpace) + + kNecBitMark); +const uint16_t kNecMinGapTicks = + kNecMinCommandLengthTicks - + (kNecHdrMarkTicks + kNecHdrSpaceTicks + + kNECBits * (kNecBitMarkTicks + kNecOneSpaceTicks) + kNecBitMarkTicks); + +// IR codes and structure for kids ALOKA SleepyLights LED Lamp. +// https://aloka-designs.com/ +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1004 +// +// May be useful for someone wanting to control the lamp. +// +// The lamp is toggled On and Off with the same power button. +// The colour, when selected, is the brightest and there are 4 levels of +// brightness that decrease on each send of the colour. A fifth send of the +// colour resets to brightest again. +// +// Remote buttons defined left to right, top line to bottom line on the remote. +const uint32_t kAlokaPower = 0xFF609F; +const uint32_t kAlokaLedWhite = 0xFF906F; +const uint32_t kAlokaLedGreen = 0xFF9867; +const uint32_t kAlokaLedBlue = 0xFFD827; +const uint32_t kAlokaLedPinkRed = 0xFF8877; +const uint32_t kAlokaLedRed = 0xFFA857; +const uint32_t kAlokaLedLightGreen = 0xFFE817; +const uint32_t kAlokaLedMidBlue = 0xFF48B7; +const uint32_t kAlokaLedPink = 0xFF6897; +const uint32_t kAlokaLedOrange = 0xFFB24D; +const uint32_t kAlokaLedYellow = 0xFF00FF; +const uint32_t kAlokaNightFade = 0xFF50AF; +const uint32_t kAlokaNightTimer = 0xFF7887; +const uint32_t kAlokaLedRainbow = 0xFF708F; +// Didn't have a better description for it... +const uint32_t kAlokaLedTreeGrow = 0xFF58A7; +#endif // IR_NEC_H_ diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Neoclima.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Neoclima.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Neoclima.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Neoclima.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Neoclima.h b/lib/IRremoteESP8266-2.7.3/src/ir_Neoclima.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Neoclima.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Neoclima.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Nikai.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Nikai.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Nikai.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Nikai.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Panasonic.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Panasonic.cpp similarity index 97% rename from lib/IRremoteESP8266-2.7.1/src/ir_Panasonic.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Panasonic.cpp index a25f4cb02..511986a11 100644 --- a/lib/IRremoteESP8266-2.7.1/src/ir_Panasonic.cpp +++ b/lib/IRremoteESP8266-2.7.3/src/ir_Panasonic.cpp @@ -25,8 +25,8 @@ // Code by crankyoldgit // Panasonic A/C models supported: // A/C Series/models: -// JKE, LKE, DKE, CKP, RKR, & NKE series. (In theory) -// CS-YW9MKD, CS-Z9RKR (confirmed) +// JKE, LKE, DKE, CKP, PKR, RKR, & NKE series. (In theory) +// CS-YW9MKD, CS-Z9RKR, CS-E7PKR (confirmed) // CS-ME14CKPG / CS-ME12CKPG / CS-ME10CKPG // A/C Remotes: // A75C3747 (confirmed) @@ -202,8 +202,9 @@ bool IRrecv::decodePanasonic(decode_results *results, const uint16_t nbits, //: // Panasonic A/C models supported: // A/C Series/models: -// JKE, LKE, DKE, CKP, RKR, & NKE series. +// JKE, LKE, DKE, CKP, PKR, RKR, & NKE series. // CS-YW9MKD +// CS-E7PKR // A/C Remotes: // A75C3747 // A75C3704 @@ -310,6 +311,8 @@ void IRPanasonicAc::setModel(const panasonic_ac_remote_model_t model) { default: break; } + // Reset the Ion filter. + setIon(getIon()); } panasonic_ac_remote_model_t IRPanasonicAc::getModel(void) { @@ -588,6 +591,22 @@ bool IRPanasonicAc::isOffTimerEnabled(void) { return GETBIT8(remote_state[13], kPanasonicAcOffTimerOffset); } +bool IRPanasonicAc::getIon(void) { + switch (this->getModel()) { + case kPanasonicDke: + return GETBIT8(remote_state[kPanasonicAcIonFilterByte], + kPanasonicAcIonFilterOffset); + default: + return false; + } +} + +void IRPanasonicAc::setIon(const bool on) { + if (this->getModel() == kPanasonicDke) + setBit(&remote_state[kPanasonicAcIonFilterByte], + kPanasonicAcIonFilterOffset, on); +} + // Convert a standard A/C mode into its native mode. uint8_t IRPanasonicAc::convertMode(const stdAc::opmode_t mode) { switch (mode) { @@ -692,10 +711,10 @@ stdAc::state_t IRPanasonicAc::toCommon(void) { result.swingh = this->toCommonSwingH(this->getSwingHorizontal()); result.quiet = this->getQuiet(); result.turbo = this->getPowerful(); + result.filter = this->getIon(); // Not supported. result.econo = false; result.clean = false; - result.filter = false; result.light = false; result.beep = false; result.sleep = -1; @@ -774,6 +793,8 @@ String IRPanasonicAc::toString(void) { } result += addBoolToString(getQuiet(), kQuietStr); result += addBoolToString(getPowerful(), kPowerfulStr); + if (getModel() == kPanasonicDke) + result += addBoolToString(getIon(), kIonStr); result += addLabeledString(minsToString(getClock()), kClockStr); result += addLabeledString( isOnTimerEnabled() ? minsToString(getOnTimer()) : kOffStr, @@ -798,8 +819,9 @@ String IRPanasonicAc::toString(void) { // // Panasonic A/C models supported: // A/C Series/models: -// JKE, LKE, DKE, & NKE series. +// JKE, LKE, DKE, PKR, & NKE series. // CS-YW9MKD +// CS-E7PKR // A/C Remotes: // A75C3747 (Confirmed) // A75C3704 diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Panasonic.h b/lib/IRremoteESP8266-2.7.3/src/ir_Panasonic.h similarity index 94% rename from lib/IRremoteESP8266-2.7.1/src/ir_Panasonic.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Panasonic.h index 89c2e5395..42e771fb3 100644 --- a/lib/IRremoteESP8266-2.7.1/src/ir_Panasonic.h +++ b/lib/IRremoteESP8266-2.7.3/src/ir_Panasonic.h @@ -4,19 +4,20 @@ // Brand: Panasonic, Model: TV // Brand: Panasonic, Model: JKE series A/C // Brand: Panasonic, Model: DKE series A/C +// Brand: Panasonic, Model: DKW series A/C (DKE) +// Brand: Panasonic, Model: PKR series A/C (DKE) // Brand: Panasonic, Model: CKP series A/C +// Brand: Panasonic, Model: NKE series A/C +// Brand: Panasonic, Model: RKR series A/C // Brand: Panasonic, Model: CS-ME10CKPG A/C // Brand: Panasonic, Model: CS-ME12CKPG A/C // Brand: Panasonic, Model: CS-ME14CKPG A/C -// Brand: Panasonic, Model: RKR series A/C +// Brand: Panasonic, Model: CS-E7PKR A/C (DKE) // Brand: Panasonic, Model: CS-Z9RKR A/C -// Brand: Panasonic, Model: NKE series A/C // Brand: Panasonic, Model: CS-YW9MKD A/C -// Brand: Panasonic, Model: A75C3747 remote -// Brand: Panasonic, Model: A75C3704 remote // Brand: Panasonic, Model: A75C2311 remote (CKP) -// Brand: Panasonic, Model: A75C3747 remote -// Brand: Panasonic, Model: A75C3747 remote +// Brand: Panasonic, Model: A75C2616-1 remote (DKE) +// Brand: Panasonic, Model: A75C3704 remote // Brand: Panasonic, Model: A75C3747 remote #ifndef IR_PANASONIC_H_ @@ -84,6 +85,9 @@ const uint8_t kPanasonicAcTimeOverflowSize = 3; // Bits const uint16_t kPanasonicAcTimeMax = 23 * 60 + 59; // Mins since midnight. const uint16_t kPanasonicAcTimeSpecial = 0x600; +const uint8_t kPanasonicAcIonFilterByte = 22; // Byte +const uint8_t kPanasonicAcIonFilterOffset = 0; // Bit + const uint8_t kPanasonicKnownGoodState[kPanasonicAcStateLength] = { 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, @@ -121,6 +125,8 @@ class IRPanasonicAc { bool getQuiet(void); void setPowerful(const bool on); bool getPowerful(void); + void setIon(const bool on); + bool getIon(void); void setModel(const panasonic_ac_remote_model_t model); panasonic_ac_remote_model_t getModel(void); void setSwingVertical(const uint8_t elevation); diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Pioneer.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Pioneer.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Pioneer.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Pioneer.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Pronto.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Pronto.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Pronto.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Pronto.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_RC5_RC6.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_RC5_RC6.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_RC5_RC6.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_RC5_RC6.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_RCMM.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_RCMM.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_RCMM.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_RCMM.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Samsung.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Samsung.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Samsung.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Samsung.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Samsung.h b/lib/IRremoteESP8266-2.7.3/src/ir_Samsung.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Samsung.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Samsung.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Sanyo.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Sanyo.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Sanyo.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Sanyo.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Sharp.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Sharp.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Sharp.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Sharp.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Sharp.h b/lib/IRremoteESP8266-2.7.3/src/ir_Sharp.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Sharp.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Sharp.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Sherwood.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Sherwood.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Sherwood.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Sherwood.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Sony.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Sony.cpp similarity index 74% rename from lib/IRremoteESP8266-2.7.1/src/ir_Sony.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Sony.cpp index 6fc39b7b5..d0f4b3c7a 100644 --- a/lib/IRremoteESP8266-2.7.1/src/ir_Sony.cpp +++ b/lib/IRremoteESP8266-2.7.3/src/ir_Sony.cpp @@ -1,9 +1,12 @@ // Copyright 2009 Ken Shirriff // Copyright 2016 marcosamarinho -// Copyright 2017 David Conran +// Copyright 2017,2020 David Conran // Sony Remote Emulation +// Supports: +// Brand: Sony, Model: HT-CT380 Soundbar (Uses 38kHz & 3 repeats) + #include #include "IRrecv.h" #include "IRsend.h" @@ -28,9 +31,11 @@ const uint16_t kSonyRptLengthTicks = 225; const uint16_t kSonyRptLength = kSonyRptLengthTicks * kSonyTick; const uint16_t kSonyMinGapTicks = 50; const uint16_t kSonyMinGap = kSonyMinGapTicks * kSonyTick; +const uint16_t kSonyStdFreq = 40000; // kHz +const uint16_t kSonyAltFreq = 38000; // kHz #if SEND_SONY -// Send a Sony/SIRC(Serial Infra-Red Control) message. +// Send a standard Sony/SIRC(Serial Infra-Red Control) message. (40kHz) // // Args: // data: message to be sent. @@ -46,10 +51,50 @@ const uint16_t kSonyMinGap = kSonyMinGapTicks * kSonyTick; // Ref: // http://www.sbprojects.com/knowledge/ir/sirc.php void IRsend::sendSony(uint64_t data, uint16_t nbits, uint16_t repeat) { + _sendSony(data, nbits, repeat, kSonyStdFreq); +} + +// Send an alternative 38kHz Sony/SIRC(Serial Infra-Red Control) message. +// +// Args: +// data: message to be sent. +// nbits: Nr. of bits of the message to be sent. +// repeat: Nr. of additional times the message is to be sent. (Default: 3) +// +// Status: STABLE / Known working. +// +// Notes: +// - `sendSony38()`` should typically be called with repeat=3 as these Sony +// devices expect the message to be sent at least 4 times. +// - Messages send via this method will be detected by this library as just +// `SONY`, not `SONY_38K` as the library has no way to determine the +// modulation frequency used. Hence, there is no `decodeSony38()`. +// +// Ref: +// http://www.sbprojects.com/knowledge/ir/sirc.php +// https://github.com/crankyoldgit/IRremoteESP8266/issues/1018 +void IRsend::sendSony38(uint64_t data, uint16_t nbits, uint16_t repeat) { + _sendSony(data, nbits, repeat, kSonyAltFreq); +} + +// Internal procedure to generate a Sony/SIRC(Serial Infra-Red Control) message. +// +// Args: +// data: message to be sent. +// nbits: Nr. of bits of the message to be sent. +// repeat: Nr. of additional times the message is to be sent. +// freq: Frequency of the modulation to transmit at. (Hz or kHz) +// +// Status: STABLE / Known working. +// +// Ref: +// http://www.sbprojects.com/knowledge/ir/sirc.php +void IRsend::_sendSony(uint64_t data, uint16_t nbits, uint16_t repeat, + uint16_t freq) { sendGeneric(kSonyHdrMark, kSonySpace, kSonyOneMark, kSonySpace, kSonyZeroMark, kSonySpace, 0, // No Footer mark. - kSonyMinGap, kSonyRptLength, data, nbits, 40, true, repeat, 33); + kSonyMinGap, kSonyRptLength, data, nbits, freq, true, repeat, 33); } // Convert Sony/SIRC command, address, & extended bits into sendSony format. @@ -149,6 +194,7 @@ bool IRrecv::decodeSony(decode_results *results, uint16_t nbits, bool strict) { // Success results->bits = actualBits; results->value = data; + // We can't detect SONY_38K messages so always assume it is just `SONY` 40kHz. results->decode_type = SONY; // Message comes in LSB first. Convert ot MSB first. data = reverseBits(data, actualBits); diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Tcl.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Tcl.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Tcl.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Tcl.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Tcl.h b/lib/IRremoteESP8266-2.7.3/src/ir_Tcl.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Tcl.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Tcl.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Teco.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Teco.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Teco.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Teco.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Teco.h b/lib/IRremoteESP8266-2.7.3/src/ir_Teco.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Teco.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Teco.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Toshiba.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Toshiba.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Toshiba.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Toshiba.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Toshiba.h b/lib/IRremoteESP8266-2.7.3/src/ir_Toshiba.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Toshiba.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Toshiba.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Trotec.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Trotec.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Trotec.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Trotec.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Trotec.h b/lib/IRremoteESP8266-2.7.3/src/ir_Trotec.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Trotec.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Trotec.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Vestel.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Vestel.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Vestel.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Vestel.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Vestel.h b/lib/IRremoteESP8266-2.7.3/src/ir_Vestel.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Vestel.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Vestel.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Whirlpool.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Whirlpool.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Whirlpool.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Whirlpool.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Whirlpool.h b/lib/IRremoteESP8266-2.7.3/src/ir_Whirlpool.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Whirlpool.h rename to lib/IRremoteESP8266-2.7.3/src/ir_Whirlpool.h diff --git a/lib/IRremoteESP8266-2.7.1/src/ir_Whynter.cpp b/lib/IRremoteESP8266-2.7.3/src/ir_Whynter.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/ir_Whynter.cpp rename to lib/IRremoteESP8266-2.7.3/src/ir_Whynter.cpp diff --git a/lib/IRremoteESP8266-2.7.1/src/locale/README.md b/lib/IRremoteESP8266-2.7.3/src/locale/README.md similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/locale/README.md rename to lib/IRremoteESP8266-2.7.3/src/locale/README.md diff --git a/lib/IRremoteESP8266-2.7.1/src/locale/de-CH.h b/lib/IRremoteESP8266-2.7.3/src/locale/de-CH.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/locale/de-CH.h rename to lib/IRremoteESP8266-2.7.3/src/locale/de-CH.h diff --git a/lib/IRremoteESP8266-2.7.1/src/locale/de-DE.h b/lib/IRremoteESP8266-2.7.3/src/locale/de-DE.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/locale/de-DE.h rename to lib/IRremoteESP8266-2.7.3/src/locale/de-DE.h diff --git a/lib/IRremoteESP8266-2.7.1/src/locale/defaults.h b/lib/IRremoteESP8266-2.7.3/src/locale/defaults.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/locale/defaults.h rename to lib/IRremoteESP8266-2.7.3/src/locale/defaults.h diff --git a/lib/IRremoteESP8266-2.7.1/src/locale/en-AU.h b/lib/IRremoteESP8266-2.7.3/src/locale/en-AU.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/locale/en-AU.h rename to lib/IRremoteESP8266-2.7.3/src/locale/en-AU.h diff --git a/lib/IRremoteESP8266-2.7.1/src/locale/en-IE.h b/lib/IRremoteESP8266-2.7.3/src/locale/en-IE.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/locale/en-IE.h rename to lib/IRremoteESP8266-2.7.3/src/locale/en-IE.h diff --git a/lib/IRremoteESP8266-2.7.1/src/locale/en-UK.h b/lib/IRremoteESP8266-2.7.3/src/locale/en-UK.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/locale/en-UK.h rename to lib/IRremoteESP8266-2.7.3/src/locale/en-UK.h diff --git a/lib/IRremoteESP8266-2.7.1/src/locale/en-US.h b/lib/IRremoteESP8266-2.7.3/src/locale/en-US.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/locale/en-US.h rename to lib/IRremoteESP8266-2.7.3/src/locale/en-US.h diff --git a/lib/IRremoteESP8266-2.7.1/src/locale/es-ES.h b/lib/IRremoteESP8266-2.7.3/src/locale/es-ES.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/locale/es-ES.h rename to lib/IRremoteESP8266-2.7.3/src/locale/es-ES.h diff --git a/lib/IRremoteESP8266-2.7.1/src/locale/fr-FR.h b/lib/IRremoteESP8266-2.7.3/src/locale/fr-FR.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/src/locale/fr-FR.h rename to lib/IRremoteESP8266-2.7.3/src/locale/fr-FR.h diff --git a/lib/IRremoteESP8266-2.7.1/test/IRac_test.cpp b/lib/IRremoteESP8266-2.7.3/test/IRac_test.cpp similarity index 88% rename from lib/IRremoteESP8266-2.7.1/test/IRac_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/IRac_test.cpp index 0d8dfdb12..875485eee 100644 --- a/lib/IRremoteESP8266-2.7.1/test/IRac_test.cpp +++ b/lib/IRremoteESP8266-2.7.3/test/IRac_test.cpp @@ -11,6 +11,7 @@ #include "ir_Haier.h" #include "ir_Hitachi.h" #include "ir_Kelvinator.h" +#include "ir_LG.h" #include "ir_Midea.h" #include "ir_Mitsubishi.h" #include "ir_MitsubishiHeavy.h" @@ -107,29 +108,29 @@ TEST(TestIRac, Coolix) { "f38000d50" // 38kHz Frequency and 50% duty-cycle. // Start of message #1 (i.e. Repeat '0') // Header - "m4480s4480" + "m4692s4416" // Data - "m560s1680m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680" - "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s560m560s1680m560s1680m560s560m560s560" - "m560s1680m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" + "m552s1656m552s552m552s1656m552s1656m552s552m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s552m552s1656m552s1656m552s552m552s1656" + "m552s552m552s552m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s1656m552s1656m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s552m552s1656m552s1656m552s552m552s1656m552s1656m552s552m552s552" + "m552s1656m552s552m552s552m552s1656m552s552m552s552m552s1656m552s1656" // Footer - "m560s5040" + "m552s5244" // End of message #1 (i.e. Repeat '0') // Start of message #2 (i.e. Repeat '1') // Header - "m4480s4480" + "m4692s4416" // Data - "m560s1680m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680" - "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s560m560s1680m560s1680m560s560m560s560" - "m560s1680m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" + "m552s1656m552s552m552s1656m552s1656m552s552m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s552m552s1656m552s1656m552s552m552s1656" + "m552s552m552s552m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s1656m552s1656m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s552m552s1656m552s1656m552s552m552s1656m552s1656m552s552m552s552" + "m552s1656m552s552m552s552m552s1656m552s552m552s552m552s1656m552s1656" // Footer - "m560s105040", + "m552s105244", // End of message #2 (i.e. Repeat '1') // Note: the two messages (#1 & #2) are identical. ac._irsend.outputStr()); @@ -640,6 +641,30 @@ TEST(TestIRac, Kelvinator) { ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); } +TEST(TestIRac, LG) { + IRLgAc ac(0); + IRac irac(0); + IRrecv capture(0); + char expected[] = + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 1 (Dry), Temp: 27C, Fan: 2 (Medium)"; + + ac.begin(); + irac.lg(&ac, + lg_ac_remote_model_t::GE6711AR2853M, // Model + true, // Power + stdAc::opmode_t::kDry, // Mode + 27, // Degrees C + stdAc::fanspeed_t::kMedium); // Fan speed + + ASSERT_EQ(expected, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(LG, ac._irsend.capture.decode_type); + ASSERT_EQ(kLgBits, ac._irsend.capture.bits); + ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); +} + TEST(TestIRac, Midea) { IRMideaAC ac(0); IRac irac(0); @@ -826,6 +851,7 @@ TEST(TestIRac, Panasonic) { stdAc::swingh_t::kLeft, // Horizontal swing true, // Quiet false, // Turbo + false, // Filter 19 * 60 + 17); // Clock ASSERT_EQ(expected_nke, ac.toString()); ac._irsend.makeDecodeResult(); @@ -837,7 +863,8 @@ TEST(TestIRac, Panasonic) { char expected_dke[] = "Model: 3 (DKE), Power: On, Mode: 3 (Cool), Temp: 18C, Fan: 4 (High), " "Swing(V): 2 (High), Swing(H): 6 (Middle), " - "Quiet: Off, Powerful: On, Clock: 19:17, On Timer: Off, Off Timer: Off"; + "Quiet: Off, Powerful: On, Ion: On, " + "Clock: 19:17, On Timer: Off, Off Timer: Off"; ac._irsend.reset(); irac.panasonic(&ac, kPanasonicDke, // Model @@ -849,6 +876,7 @@ TEST(TestIRac, Panasonic) { stdAc::swingh_t::kMiddle, // Horizontal swing false, // Quiet true, // Turbo + true, // Filter 19 * 60 + 17); // Clock ASSERT_EQ(expected_dke, ac.toString()); ac._irsend.makeDecodeResult(); @@ -1450,38 +1478,125 @@ TEST(TestIRac, Issue821) { ASSERT_EQ("Power: On, Light: Toggle", IRAcUtils::resultAcToString(&ac._irsend.capture)); EXPECT_EQ( - "f38000d50m" - "4480s4480" - "m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s560m560s560m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560" - "m560s5040" - "m4480s4480" - "m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s560m560s560m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s560" - "m560s105040" - "m4480s4480" - "m560s1680m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680" - "m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s560m560s560m560s1680m560s560m560s560m560s560" - "m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s1680m560s1680" - "m560s5040" - "m4480s4480" - "m560s1680m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680" - "m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s560m560s560m560s1680m560s560m560s560m560s560" - "m560s1680m560s560m560s1680m560s1680m560s560m560s1680m560s1680m560s1680" - "m560s105040", + "f38000d50" + "m4692s4416" + "m552s1656m552s552m552s1656m552s1656m552s552m552s1656m552s552m552s1656" + "m552s552m552s1656m552s552m552s552m552s1656m552s552m552s1656m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s552m552s1656m552s552m552s1656" + "m552s552m552s552m552s552m552s552m552s1656m552s552m552s1656m552s552" + "m552s1656m552s552m552s1656m552s552m552s552m552s1656m552s552m552s1656" + "m552s552m552s1656m552s552m552s1656m552s1656m552s552m552s1656m552s552" + "m552s5244" + "m4692s4416" + "m552s1656m552s552m552s1656m552s1656m552s552m552s1656m552s552m552s1656" + "m552s552m552s1656m552s552m552s552m552s1656m552s552m552s1656m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s552m552s1656m552s552m552s1656" + "m552s552m552s552m552s552m552s552m552s1656m552s552m552s1656m552s552" + "m552s1656m552s552m552s1656m552s552m552s552m552s1656m552s552m552s1656" + "m552s552m552s1656m552s552m552s1656m552s1656m552s552m552s1656m552s552" + "m552s105244" + "m4692s4416" + "m552s1656m552s552m552s1656m552s1656m552s552m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s552m552s1656m552s1656m552s552m552s1656" + "m552s552m552s552m552s552m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s1656m552s1656m552s1656m552s552m552s552m552s552m552s552m552s552" + "m552s552m552s1656m552s552m552s552m552s1656m552s552m552s552m552s552" + "m552s1656m552s552m552s1656m552s1656m552s552m552s1656m552s1656m552s1656" + "m552s5244" + "m4692s4416" + "m552s1656m552s552m552s1656m552s1656m552s552m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s552m552s1656m552s1656m552s552m552s1656" + "m552s552m552s552m552s552m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s1656m552s1656m552s1656m552s552m552s552m552s552m552s552m552s552" + "m552s552m552s1656m552s552m552s552m552s1656m552s552m552s552m552s552" + "m552s1656m552s552m552s1656m552s1656m552s552m552s1656m552s1656m552s1656" + "m552s105244", ac._irsend.outputStr()); } + +// Check power toggling in Whirlpool common a/c handling. +TEST(TestIRac, Issue1001) { + stdAc::state_t desired; // New desired state + stdAc::state_t prev; // Previously desired state + stdAc::state_t result; // State we need to send to get to `desired` + prev.protocol = decode_type_t::WHIRLPOOL_AC; + prev.model = 1; + prev.power = true; + prev.mode = stdAc::opmode_t::kAuto; + prev.degrees = 24; + prev.celsius = true; + prev.fanspeed = stdAc::fanspeed_t::kAuto; + prev.swingv = stdAc::swingv_t::kOff; + prev.swingh = stdAc::swingh_t::kOff; + prev.quiet = false; + prev.turbo = false; + prev.econo = false; + prev.light = false; + prev.filter = false; + prev.clean = false; + prev.beep = false; + prev.sleep = -1; + + desired = prev; + desired.power = false; + + IRac irac(0); + IRrecv capture(0); + IRWhirlpoolAc ac(0); + + ac.begin(); + ASSERT_TRUE(prev.power); + ASSERT_FALSE(desired.power); + result = irac.handleToggles(irac.cleanState(desired), &prev); + ASSERT_TRUE(result.power); + irac.sendAc(desired, &prev); + ASSERT_FALSE(desired.power); + irac.whirlpool(&ac, + (whirlpool_ac_remote_model_t)result.model, // Model + result.power, // Power + result.mode, // Mode + result.degrees, // Celsius + result.fanspeed, // Fan speed + result.swingv, // Veritcal swing + result.turbo, // Turbo + result.light, // Light + result.sleep); // Sleep + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(WHIRLPOOL_AC, ac._irsend.capture.decode_type); + ASSERT_EQ(kWhirlpoolAcBits, ac._irsend.capture.bits); + ASSERT_EQ("Model: 1 (DG11J13A), Power Toggle: On, Mode: 1 (Auto), Temp: 24C, " + "Fan: 0 (Auto), Swing: Off, Light: Off, Clock: 00:00, " + "On Timer: Off, Off Timer: Off, Sleep: Off, Super: Off, " + "Command: 1 (Power)", + IRAcUtils::resultAcToString(&ac._irsend.capture)); + + // Now check if the mode is set to "Off" instead of just change to power off. + // i.e. How Home Assistant expects things to work. + ac._irsend.reset(); + desired.power = true; + desired.mode = stdAc::opmode_t::kOff; + result = irac.handleToggles(irac.cleanState(desired), &prev); + ASSERT_TRUE(result.power); + irac.sendAc(desired, &prev); + ASSERT_TRUE(desired.power); + irac.whirlpool(&ac, + (whirlpool_ac_remote_model_t)result.model, // Model + result.power, // Power + result.mode, // Mode + result.degrees, // Celsius + result.fanspeed, // Fan speed + result.swingv, // Veritcal swing + result.turbo, // Turbo + result.light, // Light + result.sleep); // Sleep + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(WHIRLPOOL_AC, ac._irsend.capture.decode_type); + ASSERT_EQ(kWhirlpoolAcBits, ac._irsend.capture.bits); + ASSERT_EQ("Model: 1 (DG11J13A), Power Toggle: On, Mode: 1 (Auto), Temp: 24C, " + "Fan: 0 (Auto), Swing: Off, Light: Off, Clock: 00:00, " + "On Timer: Off, Off Timer: Off, Sleep: Off, Super: Off, " + "Command: 1 (Power)", + IRAcUtils::resultAcToString(&ac._irsend.capture)); +} diff --git a/lib/IRremoteESP8266-2.7.1/test/IRrecv_test.cpp b/lib/IRremoteESP8266-2.7.3/test/IRrecv_test.cpp similarity index 95% rename from lib/IRremoteESP8266-2.7.1/test/IRrecv_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/IRrecv_test.cpp index cda7b747f..9dff78c75 100644 --- a/lib/IRremoteESP8266-2.7.1/test/IRrecv_test.cpp +++ b/lib/IRremoteESP8266-2.7.3/test/IRrecv_test.cpp @@ -565,8 +565,8 @@ TEST(TestMatchGeneric, NormalWithNoAtleast) { IRrecv irrecv(1); irsend.begin(); - uint16_t good_entries_trailing_space = 12; - uint16_t good_trailing_space_data[good_entries_trailing_space] = { + const uint16_t kgood_entries_trailing_space = 12; + uint16_t good_trailing_space_data[kgood_entries_trailing_space] = { 8000, // Header mark 4000, // Header space 500, 2000, // Bit #0 (1) @@ -576,8 +576,8 @@ TEST(TestMatchGeneric, NormalWithNoAtleast) { 3000, // Footer mark 15000}; // Footer space - uint16_t good_entries_no_trailing_space = 11; - uint16_t good_no_trailing_space_data[good_entries_no_trailing_space] = { + const uint16_t kgood_entries_no_trailing_space = 11; + uint16_t good_no_trailing_space_data[kgood_entries_no_trailing_space] = { 8000, // Header mark 4000, // Header space 500, 2000, // Bit #0 (1) @@ -588,7 +588,7 @@ TEST(TestMatchGeneric, NormalWithNoAtleast) { uint16_t offset = kStartOffset; irsend.reset(); - irsend.sendRaw(good_trailing_space_data, good_entries_trailing_space, 38000); + irsend.sendRaw(good_trailing_space_data, kgood_entries_trailing_space, 38000); irsend.makeDecodeResult(); uint64_t result_data = 0; uint16_t entries_used = 0; @@ -607,7 +607,7 @@ TEST(TestMatchGeneric, NormalWithNoAtleast) { ASSERT_NE(0, entries_used); EXPECT_EQ(0b1010, result_data); EXPECT_EQ(irsend.capture.rawlen - kStartOffset, entries_used); - EXPECT_EQ(good_entries_trailing_space, entries_used); + EXPECT_EQ(kgood_entries_trailing_space, entries_used); // Same again but with a footer space mis-match, which should fail. result_data = 0; @@ -628,7 +628,7 @@ TEST(TestMatchGeneric, NormalWithNoAtleast) { // Same again as first part but with no footer space data as the last entry. irsend.reset(); result_data = 0; - irsend.sendRaw(good_no_trailing_space_data, good_entries_no_trailing_space, + irsend.sendRaw(good_no_trailing_space_data, kgood_entries_no_trailing_space, 38000); irsend.makeDecodeResult(); entries_used = irrecv.matchGeneric( @@ -646,7 +646,7 @@ TEST(TestMatchGeneric, NormalWithNoAtleast) { ASSERT_NE(0, entries_used); EXPECT_EQ(0b1010, result_data); EXPECT_EQ(irsend.capture.rawlen - kStartOffset, entries_used); - EXPECT_EQ(good_entries_no_trailing_space, entries_used); + EXPECT_EQ(kgood_entries_no_trailing_space, entries_used); } @@ -655,8 +655,8 @@ TEST(TestMatchGeneric, NormalWithAtleast) { IRrecv irrecv(1); irsend.begin(); - uint16_t good_entries_trailing_space = 12; - uint16_t good_trailing_space_data[good_entries_trailing_space] = { + const uint16_t kgood_entries_trailing_space = 12; + uint16_t good_trailing_space_data[kgood_entries_trailing_space] = { 8000, // Header mark 4000, // Header space 500, 2000, // Bit #0 (1) @@ -666,8 +666,8 @@ TEST(TestMatchGeneric, NormalWithAtleast) { 3000, // Footer mark 15000}; // Footer space - uint16_t good_entries_no_trailing_space = 11; - uint16_t good_no_trailing_space_data[good_entries_no_trailing_space] = { + const uint16_t kgood_entries_no_trailing_space = 11; + uint16_t good_no_trailing_space_data[kgood_entries_no_trailing_space] = { 8000, // Header mark 4000, // Header space 500, 2000, // Bit #0 (1) @@ -678,7 +678,7 @@ TEST(TestMatchGeneric, NormalWithAtleast) { uint16_t offset = kStartOffset; irsend.reset(); - irsend.sendRaw(good_trailing_space_data, good_entries_trailing_space, 38000); + irsend.sendRaw(good_trailing_space_data, kgood_entries_trailing_space, 38000); irsend.makeDecodeResult(); uint64_t result_data = 0; uint16_t entries_used = 0; @@ -697,7 +697,7 @@ TEST(TestMatchGeneric, NormalWithAtleast) { ASSERT_NE(0, entries_used); EXPECT_EQ(0b1010, result_data); EXPECT_EQ(irsend.capture.rawlen - kStartOffset, entries_used); - EXPECT_EQ(good_entries_trailing_space, entries_used); + EXPECT_EQ(kgood_entries_trailing_space, entries_used); // Same again but with a footer space under-match. result_data = 0; @@ -716,7 +716,7 @@ TEST(TestMatchGeneric, NormalWithAtleast) { ASSERT_NE(0, entries_used); EXPECT_EQ(0b1010, result_data); EXPECT_EQ(irsend.capture.rawlen - kStartOffset, entries_used); - EXPECT_EQ(good_entries_trailing_space, entries_used); + EXPECT_EQ(kgood_entries_trailing_space, entries_used); // Same again but with a footer space under-match using less bits so the // atleast footer isn't the last entry in the buffer. @@ -737,7 +737,7 @@ TEST(TestMatchGeneric, NormalWithAtleast) { EXPECT_EQ(0b101, result_data); // -2 because we reduced nbits by 1. EXPECT_EQ(irsend.capture.rawlen - kStartOffset - 2, entries_used); - EXPECT_EQ(good_entries_trailing_space - 2, entries_used); + EXPECT_EQ(kgood_entries_trailing_space - 2, entries_used); // Same again but with a footer space over-match, which should fail. result_data = 0; @@ -758,7 +758,7 @@ TEST(TestMatchGeneric, NormalWithAtleast) { // Same as first part but with no footer space data as the last entry. irsend.reset(); result_data = 0; - irsend.sendRaw(good_no_trailing_space_data, good_entries_no_trailing_space, + irsend.sendRaw(good_no_trailing_space_data, kgood_entries_no_trailing_space, 38000); irsend.makeDecodeResult(); entries_used = irrecv.matchGeneric( @@ -776,7 +776,7 @@ TEST(TestMatchGeneric, NormalWithAtleast) { ASSERT_NE(0, entries_used); EXPECT_EQ(0b1010, result_data); EXPECT_EQ(irsend.capture.rawlen - kStartOffset, entries_used); - EXPECT_EQ(good_entries_no_trailing_space, entries_used); + EXPECT_EQ(kgood_entries_no_trailing_space, entries_used); } TEST(TestMatchGeneric, FailureCases) { @@ -784,8 +784,8 @@ TEST(TestMatchGeneric, FailureCases) { IRrecv irrecv(1); irsend.begin(); - uint16_t entries = 11; - uint16_t data[entries] = { + const uint16_t kentries = 11; + uint16_t data[kentries] = { 8000, // Header mark 4000, // Header space 500, 2000, // Bit #0 (1) @@ -796,7 +796,7 @@ TEST(TestMatchGeneric, FailureCases) { uint16_t offset = kStartOffset; irsend.reset(); - irsend.sendRaw(data, entries, 38000); + irsend.sendRaw(data, kentries, 38000); irsend.makeDecodeResult(); uint16_t entries_used = 0; @@ -942,8 +942,8 @@ TEST(TestMatchGeneric, MissingHeaderFooter) { IRrecv irrecv(1); irsend.begin(); - uint16_t entries = 11; - uint16_t data[entries] = { + const uint16_t kentries = 11; + uint16_t data[kentries] = { 8000, // Header mark 4000, // Header space 500, 2000, // Bit #0 (1) @@ -954,7 +954,7 @@ TEST(TestMatchGeneric, MissingHeaderFooter) { uint16_t offset = kStartOffset; irsend.reset(); - irsend.sendRaw(data, entries, 38000); + irsend.sendRaw(data, kentries, 38000); irsend.makeDecodeResult(); uint16_t entries_used = 0; @@ -976,7 +976,7 @@ TEST(TestMatchGeneric, MissingHeaderFooter) { ASSERT_NE(0, entries_used); EXPECT_EQ(0b1010, result_data); EXPECT_EQ(irsend.capture.rawlen - kStartOffset - 1, entries_used); - EXPECT_EQ(entries - 1, entries_used); + EXPECT_EQ(kentries - 1, entries_used); // No header match (should fail) entries_used = irrecv.matchGeneric( @@ -1010,7 +1010,7 @@ TEST(TestMatchGeneric, MissingHeaderFooter) { ASSERT_NE(0, entries_used); EXPECT_EQ(0b1010, result_data); EXPECT_EQ(irsend.capture.rawlen - offset, entries_used); - EXPECT_EQ(entries - 2, entries_used); + EXPECT_EQ(kentries - 2, entries_used); } TEST(TestMatchGeneric, BitOrdering) { @@ -1018,8 +1018,8 @@ TEST(TestMatchGeneric, BitOrdering) { IRrecv irrecv(1); irsend.begin(); - uint16_t entries = 11; - uint16_t data[entries] = { + const uint16_t kentries = 11; + uint16_t data[kentries] = { 8000, // Header mark 4000, // Header space 500, 2000, // Bit #0 (1) @@ -1030,7 +1030,7 @@ TEST(TestMatchGeneric, BitOrdering) { uint16_t offset = kStartOffset; irsend.reset(); - irsend.sendRaw(data, entries, 38000); + irsend.sendRaw(data, kentries, 38000); irsend.makeDecodeResult(); uint16_t entries_used = 0; @@ -1052,7 +1052,7 @@ TEST(TestMatchGeneric, BitOrdering) { ASSERT_NE(0, entries_used); EXPECT_EQ(0b1010, result_data); EXPECT_EQ(irsend.capture.rawlen - kStartOffset, entries_used); - EXPECT_EQ(entries, entries_used); + EXPECT_EQ(kentries, entries_used); // LSB order entries_used = irrecv.matchGeneric( @@ -1070,7 +1070,7 @@ TEST(TestMatchGeneric, BitOrdering) { ASSERT_NE(0, entries_used); EXPECT_EQ(0b0101, result_data); EXPECT_EQ(irsend.capture.rawlen - kStartOffset, entries_used); - EXPECT_EQ(entries, entries_used); + EXPECT_EQ(kentries, entries_used); } TEST(TestMatchGeneric, UsingBytes) { @@ -1078,8 +1078,8 @@ TEST(TestMatchGeneric, UsingBytes) { IRrecv irrecv(1); irsend.begin(); - uint16_t entries = 32; - uint16_t data[entries] = { + const uint16_t kentries = 32; + uint16_t data[kentries] = { // No header 500, 2000, // Byte #0 Bit #0 (1) 500, 1000, // Byte #0 Bit #1 (0) @@ -1100,7 +1100,7 @@ TEST(TestMatchGeneric, UsingBytes) { uint16_t offset = kStartOffset; irsend.reset(); - irsend.sendRaw(data, entries, 38000); + irsend.sendRaw(data, kentries, 38000); irsend.makeDecodeResult(); uint16_t entries_used = 0; @@ -1123,7 +1123,7 @@ TEST(TestMatchGeneric, UsingBytes) { EXPECT_EQ(0b10101010, result_data[0]); EXPECT_EQ(0b11110000, result_data[1]); EXPECT_EQ(irsend.capture.rawlen - kStartOffset, entries_used); - EXPECT_EQ(entries, entries_used); + EXPECT_EQ(kentries, entries_used); // LSB order entries_used = irrecv.matchGeneric( @@ -1142,7 +1142,7 @@ TEST(TestMatchGeneric, UsingBytes) { EXPECT_EQ(0b01010101, result_data[0]); EXPECT_EQ(0b00001111, result_data[1]); EXPECT_EQ(irsend.capture.rawlen - kStartOffset, entries_used); - EXPECT_EQ(entries, entries_used); + EXPECT_EQ(kentries, entries_used); // Asking for too much. entries_used = irrecv.matchGeneric( diff --git a/lib/IRremoteESP8266-2.7.1/test/IRrecv_test.h b/lib/IRremoteESP8266-2.7.3/test/IRrecv_test.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/IRrecv_test.h rename to lib/IRremoteESP8266-2.7.3/test/IRrecv_test.h diff --git a/lib/IRremoteESP8266-2.7.1/test/IRsend_test.cpp b/lib/IRremoteESP8266-2.7.3/test/IRsend_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/IRsend_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/IRsend_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/IRsend_test.h b/lib/IRremoteESP8266-2.7.3/test/IRsend_test.h similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/IRsend_test.h rename to lib/IRremoteESP8266-2.7.3/test/IRsend_test.h diff --git a/lib/IRremoteESP8266-2.7.1/test/IRutils_test.cpp b/lib/IRremoteESP8266-2.7.3/test/IRutils_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/IRutils_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/IRutils_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/Makefile b/lib/IRremoteESP8266-2.7.3/test/Makefile similarity index 99% rename from lib/IRremoteESP8266-2.7.1/test/Makefile rename to lib/IRremoteESP8266-2.7.3/test/Makefile index ad75937b8..cdf133913 100644 --- a/lib/IRremoteESP8266-2.7.1/test/Makefile +++ b/lib/IRremoteESP8266-2.7.3/test/Makefile @@ -265,7 +265,7 @@ ir_RCMM_test : $(COMMON_OBJ) ir_RCMM_test.o $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $@ ir_LG.o : $(USER_DIR)/ir_LG.h $(USER_DIR)/ir_LG.cpp $(COMMON_DEPS) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_LG.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_LG.cpp ir_LG_test.o : ir_LG_test.cpp $(USER_DIR)/ir_LG.h $(COMMON_TEST_DEPS) $(GTEST_HEADERS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c ir_LG_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Aiwa_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Aiwa_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Aiwa_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Aiwa_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Amcor_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Amcor_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Amcor_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Amcor_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Argo_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Argo_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Argo_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Argo_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Carrier_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Carrier_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Carrier_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Carrier_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Coolix_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Coolix_test.cpp similarity index 69% rename from lib/IRremoteESP8266-2.7.1/test/ir_Coolix_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Coolix_test.cpp index 514e16dba..226e1aa68 100644 --- a/lib/IRremoteESP8266-2.7.1/test/ir_Coolix_test.cpp +++ b/lib/IRremoteESP8266-2.7.3/test/ir_Coolix_test.cpp @@ -17,66 +17,66 @@ TEST(TestSendCoolix, SendDataOnly) { irsend.sendCOOLIX(0x0); EXPECT_EQ( "f38000d50" - "m4480s4480" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s5040" - "m4480s4480" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s105040", + "m4692s4416" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s5244" + "m4692s4416" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s105244", irsend.outputStr()); irsend.reset(); irsend.sendCOOLIX(0xAA55AA); EXPECT_EQ( "f38000d50" - "m4480s4480" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5040" - "m4480s4480" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s105040", + "m4692s4416" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s5244" + "m4692s4416" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s105244", irsend.outputStr()); irsend.reset(); irsend.sendCOOLIX(0xFFFFFF); EXPECT_EQ( "f38000d50" - "m4480s4480" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s5040" - "m4480s4480" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s105040", + "m4692s4416" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s5244" + "m4692s4416" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s105244", irsend.outputStr()); } @@ -89,50 +89,50 @@ TEST(TestSendCoolix, SendWithRepeats) { irsend.sendCOOLIX(0xAA55AA, kCoolixBits, 1); // 1 repeat. EXPECT_EQ( "f38000d50" - "m4480s4480" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5040" - "m4480s4480" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s105040", + "m4692s4416" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s5244" + "m4692s4416" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s105244", irsend.outputStr()); irsend.sendCOOLIX(0xAA55AA, kCoolixBits, 2); // 2 repeats. EXPECT_EQ( "f38000d50" - "m4480s4480" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5040" - "m4480s4480" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s5040" - "m4480s4480" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680" - "m560s105040", + "m4692s4416" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s5244" + "m4692s4416" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s5244" + "m4692s4416" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656" + "m552s105244", irsend.outputStr()); } @@ -145,56 +145,56 @@ TEST(TestSendCoolix, SendUnusualSize) { irsend.sendCOOLIX(0x0, 8); EXPECT_EQ( "f38000d50" - "m4480s4480" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s5040" - "m4480s4480" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" - "m560s105040", + "m4692s4416" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s5244" + "m4692s4416" + "m552s552m552s552m552s552m552s552m552s552m552s552m552s552m552s552" + "m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" + "m552s105244", irsend.outputStr()); irsend.reset(); irsend.sendCOOLIX(0x1234567890ABCDEF, 64); EXPECT_EQ( "f38000d50" - "m4480s4480" - "m560s560m560s560m560s560m560s1680m560s560m560s560m560s1680m560s560" - "m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560m560s1680" - "m560s560m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560" - "m560s1680m560s1680m560s560m560s560m560s1680m560s560m560s1680m560s1680" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s560m560s1680" - "m560s560m560s1680m560s1680m560s1680m560s1680m560s560m560s560m560s560" - "m560s1680m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680" - "m560s1680m560s560m560s560m560s1680m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s560m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s1680" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s560" - "m560s1680m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680" - "m560s560m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560" - "m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s1680m560s560m560s560m560s560m560s560" - "m560s5040" - "m4480s4480" - "m560s560m560s560m560s560m560s1680m560s560m560s560m560s1680m560s560" - "m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s560m560s1680" - "m560s560m560s560m560s1680m560s1680m560s560m560s1680m560s560m560s560" - "m560s1680m560s1680m560s560m560s560m560s1680m560s560m560s1680m560s1680" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s1680m560s560" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s560m560s1680" - "m560s560m560s1680m560s1680m560s1680m560s1680m560s560m560s560m560s560" - "m560s1680m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680" - "m560s1680m560s560m560s560m560s1680m560s560m560s560m560s560m560s560" - "m560s560m560s1680m560s1680m560s560m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s1680" - "m560s560m560s1680m560s560m560s1680m560s560m560s1680m560s560m560s560" - "m560s1680m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680" - "m560s560m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560" - "m560s1680m560s1680m560s1680m560s560m560s1680m560s1680m560s1680m560s1680" - "m560s560m560s560m560s560m560s1680m560s560m560s560m560s560m560s560" - "m560s105040", + "m4692s4416" + "m552s552m552s552m552s552m552s1656m552s552m552s552m552s1656m552s552" + "m552s1656m552s1656m552s1656m552s552m552s1656m552s1656m552s552m552s1656" + "m552s552m552s552m552s1656m552s1656m552s552m552s1656m552s552m552s552" + "m552s1656m552s1656m552s552m552s552m552s1656m552s552m552s1656m552s1656" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s1656m552s552" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s552m552s1656" + "m552s552m552s1656m552s1656m552s1656m552s1656m552s552m552s552m552s552" + "m552s1656m552s552m552s552m552s552m552s552m552s1656m552s1656m552s1656" + "m552s1656m552s552m552s552m552s1656m552s552m552s552m552s552m552s552" + "m552s552m552s1656m552s1656m552s552m552s1656m552s1656m552s1656m552s1656" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s1656" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s552" + "m552s1656m552s1656m552s552m552s552m552s1656m552s1656m552s552m552s1656" + "m552s552m552s552m552s1656m552s1656m552s552m552s552m552s1656m552s552" + "m552s1656m552s1656m552s1656m552s552m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s1656m552s552m552s552m552s552m552s552" + "m552s5244" + "m4692s4416" + "m552s552m552s552m552s552m552s1656m552s552m552s552m552s1656m552s552" + "m552s1656m552s1656m552s1656m552s552m552s1656m552s1656m552s552m552s1656" + "m552s552m552s552m552s1656m552s1656m552s552m552s1656m552s552m552s552" + "m552s1656m552s1656m552s552m552s552m552s1656m552s552m552s1656m552s1656" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s1656m552s552" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s552m552s1656" + "m552s552m552s1656m552s1656m552s1656m552s1656m552s552m552s552m552s552" + "m552s1656m552s552m552s552m552s552m552s552m552s1656m552s1656m552s1656" + "m552s1656m552s552m552s552m552s1656m552s552m552s552m552s552m552s552" + "m552s552m552s1656m552s1656m552s552m552s1656m552s1656m552s1656m552s1656" + "m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s1656" + "m552s552m552s1656m552s552m552s1656m552s552m552s1656m552s552m552s552" + "m552s1656m552s1656m552s552m552s552m552s1656m552s1656m552s552m552s1656" + "m552s552m552s552m552s1656m552s1656m552s552m552s552m552s1656m552s552" + "m552s1656m552s1656m552s1656m552s552m552s1656m552s1656m552s1656m552s1656" + "m552s552m552s552m552s552m552s1656m552s552m552s552m552s552m552s552" + "m552s105244", irsend.outputStr()); // Bit sizes must be a multiple of 8. @@ -719,33 +719,33 @@ TEST(TestCoolixACClass, Issue722) { // Raw data supplied by @mariusmotea "f38000d50" // 4434,4376, - "m4480s4480" + "m4692s4416" // 566,1614,592,504,566,1618,566,1616,568,528,564,532,564,1616,568,532, - "m560s1680m560s560m560s1680m560s1680m560s560m560s560m560s1680m560s560" + "m552s1656m552s552m552s1656m552s1656m552s552m552s552m552s1656m552s552" // 566,530,566,1620,568,528,566,530,566,1618,564,1618,566,530,564,1624, - "m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s560m560s1680" + "m552s552m552s1656m552s552m552s552m552s1656m552s1656m552s552m552s1656" // 538,560,566,530,564,1620,566,1618,566,1618,566,1616,566,1616,566,1620, - "m560s560m560s560m560s1680m560s1680m560s1680m560s1680m560s1680m560s1680" + "m552s552m552s552m552s1656m552s1656m552s1656m552s1656m552s1656m552s1656" // 568,1620,566,1616,566,530,566,530,564,530,562,532,564,530,566,530, - "m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560m560s560" + "m552s1656m552s1656m552s552m552s552m552s552m552s552m552s552m552s552" // 566,1622,566,1616,540,1642,566,528,566,530,566,1616,566,530,566,532, - "m560s1680m560s1680m560s1680m560s560m560s560m560s1680m560s560m560s560" + "m552s1656m552s1656m552s1656m552s552m552s552m552s1656m552s552m552s552" // 564,532,564,530,566,530,566,1614,566,1616,562,532,564,1620,566,1618, - "m560s560m560s560m560s560m560s1680m560s1680m560s560m560s1680m560s1680" + "m552s552m552s552m552s552m552s1656m552s1656m552s552m552s1656m552s1656" // 538,5254,4432,4364,566,1616,568,530,564,1620,568,1616,564,532,564,530, - "m560s5040m4480s4480m560s1680m560s560m560s1680m560s1680m560s560m560s560" + "m552s5244m4692s4416m552s1656m552s552m552s1656m552s1656m552s552m552s552" // 566,1616,566,532,564,532,566,1620,568,528,566,530,566,1616,564,1618, - "m560s1680m560s560m560s560m560s1680m560s560m560s560m560s1680m560s1680" + "m552s1656m552s552m552s552m552s1656m552s552m552s552m552s1656m552s1656" // 566,530,566,1622,566,532,566,528,566,1620,568,1614,566,1618,566,1618, - "m560s560m560s1680m560s560m560s560m560s1680m560s1680m560s1680m560s1680" + "m552s552m552s1656m552s552m552s552m552s1656m552s1656m552s1656m552s1656" // 566,1614,568,1618,566,1622,568,1616,566,530,564,530,566,530,566,528, - "m560s1680m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560" + "m552s1656m552s1656m552s1656m552s1656m552s552m552s552m552s552m552s552" // 564,530,566,532,566,1622,564,1616,566,1616,564,532,564,530,564,1616, - "m560s560m560s560m560s1680m560s1680m560s1680m560s560m560s560m560s1680" + "m552s552m552s552m552s1656m552s1656m552s1656m552s552m552s552m552s1656" // 564,530,564,532,566,530,564,530,566,528,564,1618,564,1618,564,532, - "m560s560m560s560m560s560m560s560m560s560m560s1680m560s1680m560s560" + "m552s552m552s552m552s552m552s552m552s552m552s1656m552s1656m552s552" // 564,1620,566,1618,562 // Raw data matches what is expected. - "m560s1680m560s1680m560s105040", ac._irsend.outputStr()); + "m552s1656m552s1656m552s105244", ac._irsend.outputStr()); } TEST(TestCoolixACClass, Issue985) { diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Daikin_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Daikin_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Daikin_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Daikin_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Denon_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Denon_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Denon_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Denon_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Dish_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Dish_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Dish_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Dish_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Electra_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Electra_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Electra_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Electra_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Fujitsu_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Fujitsu_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Fujitsu_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Fujitsu_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_GICable_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_GICable_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_GICable_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_GICable_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_GlobalCache_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_GlobalCache_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_GlobalCache_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_GlobalCache_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Goodweather_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Goodweather_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Goodweather_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Goodweather_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Gree_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Gree_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Gree_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Gree_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Haier_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Haier_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Haier_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Haier_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Hitachi_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Hitachi_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Hitachi_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Hitachi_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Inax_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Inax_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Inax_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Inax_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_JVC_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_JVC_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_JVC_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_JVC_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Kelvinator_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Kelvinator_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Kelvinator_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Kelvinator_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_LG_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_LG_test.cpp similarity index 59% rename from lib/IRremoteESP8266-2.7.1/test/ir_LG_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_LG_test.cpp index d1e1b8659..1c2b2a856 100644 --- a/lib/IRremoteESP8266-2.7.1/test/ir_LG_test.cpp +++ b/lib/IRremoteESP8266-2.7.3/test/ir_LG_test.cpp @@ -1,6 +1,7 @@ -// Copyright 2017 David Conran +// Copyright 2017, 2019 David Conran #include "ir_LG.h" +#include "IRac.h" #include "IRsend.h" #include "IRsend_test.h" #include "gtest/gtest.h" @@ -18,6 +19,10 @@ TEST(TestCalcLGChecksum, General) { EXPECT_EQ(0xE, calcLGChecksum(0xABCD)); EXPECT_EQ(0x1, calcLGChecksum(0x4AE5)); EXPECT_EQ(0xC, calcLGChecksum(0xFFFF)); + EXPECT_EQ(0x1, calcLGChecksum(0xC005)); + EXPECT_EQ(0x1, IRLgAc::calcChecksum(0x88C0051)); + EXPECT_EQ(0x4, calcLGChecksum(0xC035)); + EXPECT_EQ(0x4, IRLgAc::calcChecksum(0x88C0354)); } // Tests for sendLG(). @@ -457,6 +462,7 @@ TEST(TestDecodeLG, Issue620) { // Resend the same code as the report is a sent code doesn't decode // to the same message code. + IRLgAc ac(0); irsend.sendLG(0x8808721); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); @@ -465,6 +471,11 @@ TEST(TestDecodeLG, Issue620) { EXPECT_EQ(0x8808721, irsend.capture.value); EXPECT_EQ(0x88, irsend.capture.address); EXPECT_EQ(0x872, irsend.capture.command); + ac.setRaw(irsend.capture.value); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ("Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 22C, Fan: 2 (Medium)", + ac.toString()); // The following seems to match the rawData above. EXPECT_EQ( "f38000d50" @@ -478,3 +489,390 @@ TEST(TestDecodeLG, Issue620) { "s55550", irsend.outputStr()); } + +TEST(TestIRLgAcClass, SetAndGetPower) { + IRLgAc ac(0); + ac.on(); + EXPECT_TRUE(ac.getPower()); + ac.off(); + EXPECT_FALSE(ac.getPower()); + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + ac.setPower(false); + EXPECT_FALSE(ac.getPower()); +} + +TEST(TestIRLgAcClass, SetAndGetTemp) { + IRLgAc ac(0); + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + ac.setTemp(kLgAcMinTemp); + EXPECT_EQ(kLgAcMinTemp, ac.getTemp()); + ac.setTemp(kLgAcMinTemp - 1); + EXPECT_EQ(kLgAcMinTemp, ac.getTemp()); + ac.setTemp(kLgAcMaxTemp); + EXPECT_EQ(kLgAcMaxTemp, ac.getTemp()); + ac.setTemp(kLgAcMaxTemp + 1); + EXPECT_EQ(kLgAcMaxTemp, ac.getTemp()); +} + +TEST(TestIRLgAcClass, SetAndGetMode) { + IRLgAc ac(0); + ac.setMode(kLgAcCool); + ac.setFan(kLgAcFanAuto); + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + EXPECT_EQ(kLgAcCool, ac.getMode()); + EXPECT_EQ(kLgAcFanAuto, ac.getFan()); + ac.setMode(kLgAcHeat); + EXPECT_EQ(kLgAcHeat, ac.getMode()); + ac.setMode(kLgAcDry); + EXPECT_EQ(kLgAcDry, ac.getMode()); +} + +TEST(TestIRLgAcClass, SetAndGetFan) { + IRLgAc ac(0); + ac.setMode(kLgAcCool); + ac.setFan(kLgAcFanAuto); + EXPECT_EQ(kLgAcFanAuto, ac.getFan()); + ac.setFan(kLgAcFanLow); + EXPECT_EQ(kLgAcFanLow, ac.getFan()); + ac.setFan(kLgAcFanHigh); + EXPECT_EQ(kLgAcFanHigh, ac.getFan()); + ac.setFan(kLgAcFanAuto + 1); + EXPECT_EQ(kLgAcFanAuto, ac.getFan()); + ac.setFan(kLgAcFanLow - 1); + EXPECT_EQ(kLgAcFanAuto, ac.getFan()); +} + +TEST(TestIRLgAcClass, toCommon) { + IRLgAc ac(0); + ac.setPower(true); + ac.setMode(kLgAcCool); + ac.setTemp(20); + ac.setFan(kLgAcFanHigh); + // Now test it. + ASSERT_EQ(decode_type_t::LG, ac.toCommon().protocol); + ASSERT_EQ(lg_ac_remote_model_t::GE6711AR2853M, ac.toCommon().model); + ASSERT_TRUE(ac.toCommon().power); + ASSERT_TRUE(ac.toCommon().celsius); + ASSERT_EQ(20, ac.toCommon().degrees); + ASSERT_EQ(stdAc::opmode_t::kCool, ac.toCommon().mode); + ASSERT_EQ(stdAc::fanspeed_t::kMax, ac.toCommon().fanspeed); + // Unsupported. + ASSERT_EQ(stdAc::swingv_t::kOff, ac.toCommon().swingv); + ASSERT_EQ(stdAc::swingh_t::kOff, ac.toCommon().swingh); + ASSERT_FALSE(ac.toCommon().turbo); + ASSERT_FALSE(ac.toCommon().clean); + ASSERT_FALSE(ac.toCommon().light); + ASSERT_FALSE(ac.toCommon().quiet); + ASSERT_FALSE(ac.toCommon().econo); + ASSERT_FALSE(ac.toCommon().filter); + ASSERT_FALSE(ac.toCommon().beep); + ASSERT_EQ(-1, ac.toCommon().sleep); + ASSERT_EQ(-1, ac.toCommon().clock); + + // Change models + ac.setModel(AKB75215403); + ASSERT_EQ(lg_ac_remote_model_t::AKB75215403, ac.toCommon().model); +} + +TEST(TestIRLgAcClass, HumanReadable) { + IRLgAc ac(0); + + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: Off", + ac.toString()); + ac.setMode(kLgAcHeat); + ac.setTemp(kLgAcMaxTemp); + ac.on(); + ac.setFan(kLgAcFanHigh); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 4 (Heat), Temp: 30C, Fan: 4 (High)", + ac.toString()); + ac.setMode(kLgAcCool); + ac.setFan(kLgAcFanLow); + ac.setTemp(kLgAcMinTemp); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 16C, Fan: 0 (Low)", + ac.toString()); + ac.setTemp(ac.getTemp() + 1); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 17C, Fan: 0 (Low)", + ac.toString()); + ac.setTemp(ac.getTemp() - 1); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 16C, Fan: 0 (Low)", + ac.toString()); + ac.setPower(false); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: Off", + ac.toString()); +} + +TEST(TestIRLgAcClass, SetAndGetRaw) { + IRLgAc ac(0); + + ac.setRaw(0x8800A4E); + ASSERT_EQ(0x8800A4E, ac.getRaw()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 25C, Fan: 4 (High)", + ac.toString()); + + ac.setRaw(0x88C0051); + ASSERT_EQ(0x88C0051, ac.getRaw()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: Off", + ac.toString()); +} + +TEST(TestIRLgAcClass, MessageConstruction) { + IRLgAc ac(0); + + ac.on(); + ac.setMode(kLgAcCool); + ac.setTemp(25); + ac.setFan(kLgAcFanHigh); + ASSERT_EQ(0x8800A4E, ac.getRaw()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 25C, Fan: 4 (High)", + ac.toString()); +} + +TEST(TestIRLgAcClass, isValidLgAc) { + IRLgAc ac(0); + + ac.setRaw(0x8800A4E); + ASSERT_TRUE(ac.isValidLgAc()); + + // Make the checksum wrong. + ac.setRaw(0x8800A4F); + ASSERT_FALSE(ac.isValidLgAc()); + + ac.setRaw(0x88C0051); + ASSERT_TRUE(ac.isValidLgAc()); + + // Use a wrong signature. + ac.setRaw(0x8000A4E); + ASSERT_FALSE(ac.isValidLgAc()); +} + +TEST(TestUtils, Housekeeping) { + ASSERT_EQ("LG", typeToString(decode_type_t::LG)); + ASSERT_EQ(decode_type_t::LG, strToDecodeType("LG")); + ASSERT_FALSE(hasACState(decode_type_t::LG)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::LG)); + + ASSERT_EQ("LG2", typeToString(decode_type_t::LG2)); + ASSERT_EQ(decode_type_t::LG2, strToDecodeType("LG2")); + ASSERT_FALSE(hasACState(decode_type_t::LG2)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::LG2)); +} + +TEST(TestIRLgAcClass, KnownExamples) { + IRLgAc ac(0); + // Ref: + // https://github.com/crankyoldgit/IRremoteESP8266/issues/1008#issuecomment-570646648 + + // Temp + ac.setRaw(0x880C152); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 4 (Heat), Temp: 16C, Fan: 5 (Auto)", + ac.toString()); + + ac.setRaw(0x880CF50); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 4 (Heat), Temp: 30C, Fan: 5 (Auto)", + ac.toString()); + + // Modes + ac.setRaw(0x880960F); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 1 (Dry), Temp: 21C, Fan: 0 (Low)", + ac.toString()); + + ac.setRaw(0x880C758); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 4 (Heat), Temp: 22C, Fan: 5 (Auto)", + ac.toString()); + + ac.setRaw(0x8808855); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 23C, Fan: 5 (Auto)", + ac.toString()); + + // Fan speeds + ac.setRaw(0x880870F); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 22C, Fan: 0 (Low)", + ac.toString()); + + ac.setRaw(0x8808721); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 22C, Fan: 2 (Medium)", + ac.toString()); + + ac.setRaw(0x8808743); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 22C, Fan: 4 (High)", + ac.toString()); + + ac.setRaw(0x8808754); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 22C, Fan: 5 (Auto)", + ac.toString()); + + ac.setRaw(0x880A745); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 2 (Fan), Temp: 22C, Fan: 4 (High)", + ac.toString()); + + // https://github.com/crankyoldgit/IRremoteESP8266/issues/1008#issuecomment-570794029 + ac.setRaw(0x8800347); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 18C, Fan: 4 (High)", + ac.toString()); + ac.setRaw(0x8808440); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 19C, Fan: 4 (High)", + ac.toString()); + ac.setRaw(0x8800459); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 19C, Fan: 5 (Auto)", + ac.toString()); + ac.setRaw(0x8809946); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 1 (Dry), Temp: 24C, Fan: 4 (High)", + ac.toString()); + ac.setRaw(0x880A341); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 2 (Fan), Temp: 18C, Fan: 4 (High)", + ac.toString()); + ac.setRaw(0x8810045); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 15C, Fan: 4 (High)", + ac.toString()); + ac.setRaw(0x8810056); + ASSERT_TRUE(ac.isValidLgAc()); + EXPECT_EQ( + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 15C, Fan: 5 (Auto)", + ac.toString()); +} + +// Verify decoding of LG2 message. +TEST(TestDecodeLG2, Issue1008) { + IRsendTest irsend(0); + IRrecv capture(0); + irsend.begin(); + + irsend.reset(); + // From https://github.com/crankyoldgit/IRremoteESP8266/issues/1008#issuecomment-570794029 + // First entry. + uint16_t rawData[59] = { + 3272, 9844, 506, 1588, 536, 498, 534, 498, 536, 498, 534, 1540, 534, 506, + 534, 498, 534, 500, 532, 500, 534, 498, 534, 498, 534, 506, 534, 500, 534, + 498, 534, 498, 534, 498, 534, 500, 534, 498, 534, 1566, 508, 1566, 508, + 500, 534, 1540, 534, 506, 534, 500, 534, 500, 534, 1560, 508, 1540, 534, + 1558, 508}; // UNKNOWN AFC3034C + irsend.sendRaw(rawData, 59, 38000); + irsend.makeDecodeResult(); + + ASSERT_TRUE(capture.decode(&irsend.capture)); + ASSERT_EQ(LG2, irsend.capture.decode_type); + EXPECT_EQ(kLgBits, irsend.capture.bits); + EXPECT_EQ(0x8800347, irsend.capture.value); + + irsend.reset(); + IRLgAc ac(0); + ac.setRaw(0x8800347); + ac.setModel(lg_ac_remote_model_t::AKB75215403); // aka. 2 + ac.send(); + + char expected[] = + "Model: 2 (AKB75215403), " + "Power: On, Mode: 0 (Cool), Temp: 18C, Fan: 4 (High)"; + ASSERT_EQ(expected, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(LG2, ac._irsend.capture.decode_type); + ASSERT_EQ(kLgBits, ac._irsend.capture.bits); + ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); +} + +TEST(TestIRLgAcClass, DifferentModels) { + IRLgAc ac(0); + IRrecv capture(0); + + ac.setRaw(0x8800347); + + ac.setModel(lg_ac_remote_model_t::GE6711AR2853M); // aka. 1 + ac._irsend.reset(); + ac.send(); + + char expected1[] = + "Model: 1 (GE6711AR2853M), " + "Power: On, Mode: 0 (Cool), Temp: 18C, Fan: 4 (High)"; + ASSERT_EQ(expected1, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(LG, ac._irsend.capture.decode_type); // Not "LG2" + ASSERT_EQ(kLgBits, ac._irsend.capture.bits); + ASSERT_EQ(expected1, IRAcUtils::resultAcToString(&ac._irsend.capture)); + + + ac.setModel(lg_ac_remote_model_t::AKB75215403); // aka. 2 + ac._irsend.reset(); + ac.send(); + + char expected2[] = + "Model: 2 (AKB75215403), " + "Power: On, Mode: 0 (Cool), Temp: 18C, Fan: 4 (High)"; + ASSERT_EQ(expected2, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(LG2, ac._irsend.capture.decode_type); // Not "LG" + ASSERT_EQ(kLgBits, ac._irsend.capture.bits); + ASSERT_EQ(expected2, IRAcUtils::resultAcToString(&ac._irsend.capture)); +} diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Lasertag_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Lasertag_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Lasertag_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Lasertag_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Lego_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Lego_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Lego_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Lego_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Lutron_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Lutron_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Lutron_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Lutron_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_MWM_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_MWM_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_MWM_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_MWM_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Magiquest_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Magiquest_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Magiquest_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Magiquest_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Midea_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Midea_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Midea_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Midea_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_MitsubishiHeavy_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_MitsubishiHeavy_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_MitsubishiHeavy_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_MitsubishiHeavy_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Mitsubishi_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Mitsubishi_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Mitsubishi_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Mitsubishi_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_NEC_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_NEC_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_NEC_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_NEC_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Neoclima_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Neoclima_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Neoclima_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Neoclima_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Nikai_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Nikai_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Nikai_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Nikai_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Panasonic_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Panasonic_test.cpp similarity index 96% rename from lib/IRremoteESP8266-2.7.1/test/ir_Panasonic_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Panasonic_test.cpp index 471a324c8..97f9bbb28 100644 --- a/lib/IRremoteESP8266-2.7.1/test/ir_Panasonic_test.cpp +++ b/lib/IRremoteESP8266-2.7.3/test/ir_Panasonic_test.cpp @@ -736,6 +736,26 @@ TEST(TestIRPanasonicAcClass, QuietAndPowerful) { EXPECT_FALSE(pana.getPowerful()); } +TEST(TestIRPanasonicAcClass, SetAndGetIon) { + IRPanasonicAc ac(0); + // Ion Filter only works for DKE. + ac.setModel(kPanasonicDke); + ac.setIon(true); + EXPECT_TRUE(ac.getIon()); + ac.setIon(false); + EXPECT_FALSE(ac.getIon()); + ac.setIon(true); + EXPECT_TRUE(ac.getIon()); + + // Now try a different (a guess at unsupported) model. + ac.setModel(kPanasonicRkr); + EXPECT_FALSE(ac.getIon()); + ac.setIon(true); + EXPECT_FALSE(ac.getIon()); + ac.setIon(false); + EXPECT_FALSE(ac.getIon()); +} + TEST(TestIRPanasonicAcClass, HumanReadable) { IRPanasonicAc pana(0); EXPECT_EQ( @@ -767,7 +787,7 @@ TEST(TestIRPanasonicAcClass, HumanReadable) { EXPECT_EQ( "Model: 3 (DKE), Power: Off, Mode: 4 (Heat), Temp: 30C, " "Fan: 4 (High), Swing(V): 15 (Auto), " - "Swing(H): 11 (Right), Quiet: On, Powerful: Off, " + "Swing(H): 11 (Right), Quiet: On, Powerful: Off, Ion: Off, " "Clock: 00:00, On Timer: Off, Off Timer: Off", pana.toString()); } @@ -1180,3 +1200,38 @@ TEST(TestIRPanasonicAcClass, toCommon) { ASSERT_EQ(kPanasonicAcSwingVMiddle, IRPanasonicAc::convertSwingV(stdAc::swingv_t::kMiddle)); } + +// +// Test for DKE/DKW model / see issue #1024 +TEST(TestDecodePanasonicAC, DkeIonRealMessages) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + // Data from Issue #1024 + // 0x0220E004000000060220E004004F3280AF0D000660000001000630 + uint8_t dkeIonOff[kPanasonicAcStateLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x4F, 0x32, 0x80, 0xAF, 0x0D, + 0x00, 0x06, 0x60, 0x00, 0x00, 0x01, 0x00, 0x06, 0x30}; + + // 0x0220E004000000060220E004004F3280AF0D000660000101000631 + uint8_t dkeIonOn[kPanasonicAcStateLength] = { + 0x02, 0x20, 0xE0, 0x04, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x20, 0xE0, 0x04, 0x00, 0x4F, 0x32, 0x80, 0xAF, 0x0D, + 0x00, 0x06, 0x60, 0x00, 0x01, 0x01, 0x00, 0x06, 0x31}; + + IRPanasonicAc ac(0); + ac.setRaw(dkeIonOff); + EXPECT_EQ( + "Model: 3 (DKE), Power: On, Mode: 4 (Heat), Temp: 25C, Fan: 7 (Auto), " + "Swing(V): 15 (Auto), Swing(H): 13 (Auto), Quiet: Off, Powerful: Off, " + "Ion: Off, Clock: 00:00, On Timer: 00:00, Off Timer: 00:00", + ac.toString()); + ac.setRaw(dkeIonOn); + EXPECT_EQ( + "Model: 3 (DKE), Power: On, Mode: 4 (Heat), Temp: 25C, Fan: 7 (Auto), " + "Swing(V): 15 (Auto), Swing(H): 13 (Auto), Quiet: Off, Powerful: Off, " + "Ion: On, Clock: 00:00, On Timer: 00:00, Off Timer: 00:00", + ac.toString()); +} diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Pioneer_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Pioneer_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Pioneer_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Pioneer_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Pronto_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Pronto_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Pronto_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Pronto_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_RC5_RC6_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_RC5_RC6_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_RC5_RC6_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_RC5_RC6_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_RCMM_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_RCMM_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_RCMM_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_RCMM_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Samsung_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Samsung_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Samsung_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Samsung_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Sanyo_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Sanyo_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Sanyo_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Sanyo_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Sharp_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Sharp_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Sharp_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Sharp_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Sherwood_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Sherwood_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Sherwood_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Sherwood_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Sony_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Sony_test.cpp similarity index 61% rename from lib/IRremoteESP8266-2.7.1/test/ir_Sony_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Sony_test.cpp index 51bacbd6d..18fc58334 100644 --- a/lib/IRremoteESP8266-2.7.1/test/ir_Sony_test.cpp +++ b/lib/IRremoteESP8266-2.7.3/test/ir_Sony_test.cpp @@ -360,3 +360,228 @@ TEST(TestEncodeSony, Issue476) { EXPECT_EQ(0xE2, (0x7156 >> 7) & 0xFF); // extended (top 8 of 15 bits) EXPECT_EQ(0x6AB47, irsend.encodeSony(20, 0x56, 0x1A, 0xE2)); } + +// Encoding & Decode 15 bit Sony messages. Issue #1018 +TEST(TestEncodeSony, Issue1018) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + irsend.sendSony(0x240C, 15); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(SONY, irsend.capture.decode_type); + EXPECT_EQ(15, irsend.capture.bits); + EXPECT_EQ(0x240C, irsend.capture.value); // 15 bits + EXPECT_EQ(0x30, irsend.capture.address); + EXPECT_EQ(0x12, irsend.capture.command); + EXPECT_EQ( + "f40000d33" + "m2400s600" // Message + "m600s600m1200s600m600s600m600s600m1200s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + "m600s22200" + "m2400s600" // Repeat #1 + "m600s600m1200s600m600s600m600s600m1200s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + "m600s22200" + "m2400s600" // Repeat #2 + "m600s600m1200s600m600s600m600s600m1200s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + "m600s22200", + irsend.outputStr()); + + irsend.reset(); + uint16_t rawData[127] = { + 2448, 550, + 648, 544, 1250, 546, 648, 548, 648, 550, 1272, 524, 648, 550, 644, 550, + 674, 524, 648, 550, 648, 544, 674, 524, 1270, 524, 1246, 550, 674, 524, + 648, 22404, + 2474, 524, + 674, 520, 1250, 548, 648, 544, 674, 524, 1270, 524, 648, 550, 648, 546, + 674, 524, 648, 546, 652, 546, 674, 524, 1270, 524, 1272, 522, 674, 520, + 648, 22404, + 2452, 544, + 674, 524, 1270, 524, 674, 518, 674, 522, 1246, 550, 674, 524, 648, 544, + 674, 524, 648, 546, 674, 524, 674, 518, 1276, 518, 1276, 524, 648, 546, + 674, 22380, + 2474, 520, + 674, 524, 1250, 544, 674, 524, 674, 518, 1276, 520, 674, 522, 674, 524, + 674, 520, 674, 524, 674, 524, 674, 518, 1276, 518, 1276, 524, 672, 524, + 648}; // SONY 240C + + irsend.sendRaw(rawData, 127, 40); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(SONY, irsend.capture.decode_type); + EXPECT_EQ(15, irsend.capture.bits); + EXPECT_EQ(0x240C, irsend.capture.value); // 15 bits + EXPECT_EQ(0x30, irsend.capture.address); + EXPECT_EQ(0x12, irsend.capture.command); + EXPECT_EQ( + "f40000d50" + "m2448s550" // Message + "m648s544m1250s546m648s548m648s550m1272s524m648s550m644s550" + "m674s524m648s550m648s544m674s524m1270s524m1246s550m674s524" + "m648s22404" + "m2474s524" // Repeat #1 + "m674s520m1250s548m648s544m674s524m1270s524m648s550m648s546" + "m674s524m648s546m652s546m674s524m1270s524m1272s522m674s520" + "m648s22404" + "m2452s544" // Repeat #2 + "m674s524m1270s524m674s518m674s522m1246s550m674s524m648s544" + "m674s524m648s546m674s524m674s518m1276s518m1276s524m648s546" + "m674s22380" + "m2474s520" // Repeat #3 + "m674s524m1250s544m674s524m674s518m1276s520m674s522m674s524" + "m674s520m674s524m674s524m674s518m1276s518m1276s524m672s524" + "m648", + irsend.outputStr()); + + // Now see if we can reproduce it with `sendSony` + irsend.reset(); + irsend.sendSony(0x240C, 15, 3); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(SONY, irsend.capture.decode_type); + EXPECT_EQ(15, irsend.capture.bits); + EXPECT_EQ(0x240C, irsend.capture.value); // 15 bits + EXPECT_EQ(0x30, irsend.capture.address); + EXPECT_EQ(0x12, irsend.capture.command); + + // Compare expected result with real `rawData` result. + // Comparison notes: + // * Seems visually the same. i.e. '1' where '1's should be etc. + // * Timings are *roughly* the same. They should be within device + // tollerance. + // TL;DR: Looks fine/the same/as expected. + EXPECT_EQ( + "f40000d33" + "m2400s600" // Message + // "m2448s550" (Commented out data is from `rawData` sample above.) + "m600s600m1200s600m600s600m600s600m1200s600m600s600m600s600" + // "m648s544m1250s546m648s548m648s550m1272s524m648s550m644s550" + "m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + // "m674s524m648s550m648s544m674s524m1270s524m1246s550m674s524" + "m600s22200" + // "m648s22404" + "m2400s600" // Repeat #1 + // "m2474s524" + "m600s600m1200s600m600s600m600s600m1200s600m600s600m600s600" + // "m674s520m1250s548m648s544m674s524m1270s524m648s550m648s546" + "m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + // "m674s524m648s546m652s546m674s524m1270s524m1272s522m674s520" + "m600s22200" + // "m648s22404" + "m2400s600" // Repeat #2 + // "m2452s544" + "m600s600m1200s600m600s600m600s600m1200s600m600s600m600s600" + // "m674s524m1270s524m674s518m674s522m1246s550m674s524m648s544" + "m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + // "m674s524m648s546m674s524m674s518m1276s518m1276s524m648s546" + "m600s22200" + // "m674s22380" + "m2400s600" // Repeat #3 + // "m2474s520" + "m600s600m1200s600m600s600m600s600m1200s600m600s600m600s600" + // "m674s524m1250s544m674s524m674s518m1276s520m674s522m674s524" + "m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + // "m674s520m674s524m674s524m674s518m1276s518m1276s524m672s524" + "m600s22200", + // "m648" // (Trailing space is ignored in real captures.) + irsend.outputStr()); + + // Now see if we can reproduce it with `sendSony38` + irsend.reset(); + irsend.sendSony38(0x240C, 15); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(SONY, irsend.capture.decode_type); + EXPECT_EQ(15, irsend.capture.bits); + EXPECT_EQ(0x240C, irsend.capture.value); // 15 bits + EXPECT_EQ(0x30, irsend.capture.address); + EXPECT_EQ(0x12, irsend.capture.command); +} + +// Test sending typical data only. +TEST(TestSendSony38, SendDataOnly) { + IRsendTest irsend(0); + irsend.begin(); + + irsend.reset(); + irsend.sendSony38(0); + // We expect three 20-bit commands to be sent. + EXPECT_EQ( + "f38000d33" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s18600" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s18600" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s18600" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m600s600m600s600m600s600m600s18600", + irsend.outputStr()); + + irsend.reset(); + irsend.sendSony38(0x240C, kSony20Bits); + // We expect three 20-bit commands to be sent. + EXPECT_EQ( + "f38000d33" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200" + "m2400s600m600s600m600s600m600s600m600s600m600s600m600s600m1200s600" + "m600s600m600s600m1200s600m600s600m600s600m600s600m600s600m600s600" + "m600s600m1200s600m1200s600m600s600m600s16200", + irsend.outputStr()); + + irsend.reset(); + irsend.sendSony38(0x240C, kSony15Bits); + // We expect three 15-bit commands to be sent. + EXPECT_EQ( + "f38000d33" + "m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + "m600s22200" + "m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + "m600s22200" + "m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + "m600s22200" + "m2400s600m600s600m1200s600m600s600m600s600m1200s600m600s600" + "m600s600m600s600m600s600m600s600m600s600m1200s600m1200s600m600s600" + "m600s22200", + irsend.outputStr()); + + irsend.reset(); + irsend.sendSony38(0xA90, kSony12Bits); + // We expect three 15-bit commands to be sent. + EXPECT_EQ( + "f38000d33" + "m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600" + "m600s600m1200s600m600s600m600s600m600s600m600s25800" + "m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600" + "m600s600m1200s600m600s600m600s600m600s600m600s25800" + "m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600" + "m600s600m1200s600m600s600m600s600m600s600m600s25800" + "m2400s600m1200s600m600s600m1200s600m600s600m1200s600m600s600" + "m600s600m1200s600m600s600m600s600m600s600m600s25800", + irsend.outputStr()); +} diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Tcl_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Tcl_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Tcl_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Tcl_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Teco_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Teco_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Teco_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Teco_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Toshiba_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Toshiba_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Toshiba_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Toshiba_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Trotec_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Trotec_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Trotec_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Trotec_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Vestel_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Vestel_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Vestel_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Vestel_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Whirlpool_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Whirlpool_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Whirlpool_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Whirlpool_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/test/ir_Whynter_test.cpp b/lib/IRremoteESP8266-2.7.3/test/ir_Whynter_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/test/ir_Whynter_test.cpp rename to lib/IRremoteESP8266-2.7.3/test/ir_Whynter_test.cpp diff --git a/lib/IRremoteESP8266-2.7.1/tools/Makefile b/lib/IRremoteESP8266-2.7.3/tools/Makefile similarity index 99% rename from lib/IRremoteESP8266-2.7.1/tools/Makefile rename to lib/IRremoteESP8266-2.7.3/tools/Makefile index bf23fbce6..6868f97db 100644 --- a/lib/IRremoteESP8266-2.7.1/tools/Makefile +++ b/lib/IRremoteESP8266-2.7.3/tools/Makefile @@ -118,7 +118,7 @@ ir_RCMM.o : $(USER_DIR)/ir_RCMM.cpp $(COMMON_DEPS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_RCMM.cpp ir_LG.o : $(USER_DIR)/ir_LG.h $(USER_DIR)/ir_LG.cpp $(COMMON_DEPS) - $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $(USER_DIR)/ir_LG.cpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_LG.cpp ir_Mitsubishi.o : $(USER_DIR)/ir_Mitsubishi.h $(USER_DIR)/ir_Mitsubishi.cpp $(COMMON_DEPS) $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $(USER_DIR)/ir_Mitsubishi.cpp diff --git a/lib/IRremoteESP8266-2.7.1/tools/RawToGlobalCache.sh b/lib/IRremoteESP8266-2.7.3/tools/RawToGlobalCache.sh similarity index 100% rename from lib/IRremoteESP8266-2.7.1/tools/RawToGlobalCache.sh rename to lib/IRremoteESP8266-2.7.3/tools/RawToGlobalCache.sh diff --git a/lib/IRremoteESP8266-2.7.1/tools/auto_analyse_raw_data.py b/lib/IRremoteESP8266-2.7.3/tools/auto_analyse_raw_data.py similarity index 97% rename from lib/IRremoteESP8266-2.7.1/tools/auto_analyse_raw_data.py rename to lib/IRremoteESP8266-2.7.3/tools/auto_analyse_raw_data.py index d673d52d4..5bea3926a 100755 --- a/lib/IRremoteESP8266-2.7.1/tools/auto_analyse_raw_data.py +++ b/lib/IRremoteESP8266-2.7.3/tools/auto_analyse_raw_data.py @@ -65,6 +65,8 @@ class RawIRMessage(): def _usec_compare(self, seen, expected): """Compare two usec values and see if they match within a subtractive margin.""" + if expected is None: + return False return expected - self.margin < seen <= expected def _usec_compares(self, usecs, expecteds): @@ -214,19 +216,25 @@ class RawIRMessage(): if len(self.marks) > 2: # Possible leader mark? self.ldr_mark = self.marks[0] self.hdr_mark = self.marks[1] - else: + elif len(self.marks) > 1: # At least two marks # Largest mark is likely the kHdrMark self.hdr_mark = self.marks[0] + else: + # Probably no header mark. + self.hdr_mark = 0 - if self.is_space_encoded() and len(self.spaces) >= 3: + if self.is_space_encoded() and len(self.spaces) >= 2: if self.verbose and len(self.marks) > 2: self.output.write("DANGER: Unusual number of mark timings!") # We should have 3 space candidates at least. # They should be: zero_space (smallest), one_space, & hdr_space (largest) spaces = list(self.spaces) - self.zero_space = spaces.pop() - self.one_space = spaces.pop() - self.hdr_space = spaces.pop() + if spaces: + self.zero_space = spaces.pop() + if spaces: + self.one_space = spaces.pop() + if spaces: + self.hdr_space = spaces.pop() # Rest are probably message gaps self.gaps = spaces @@ -302,11 +310,15 @@ def convert_rawdata(data_str): def dump_constants(message, defines, name="", output=sys.stdout): """Dump the key constants and generate the C++ #defines.""" ldr_mark = None + hdr_mark = 0 + hdr_space = 0 if message.ldr_mark is not None: ldr_mark = avg_list(message.mark_buckets[message.ldr_mark]) - hdr_mark = avg_list(message.mark_buckets[message.hdr_mark]) + if message.hdr_mark != 0: + hdr_mark = avg_list(message.mark_buckets[message.hdr_mark]) bit_mark = avg_list(message.mark_buckets[message.bit_mark]) - hdr_space = avg_list(message.space_buckets[message.hdr_space]) + if message.hdr_space is not None: + hdr_space = avg_list(message.space_buckets[message.hdr_space]) one_space = avg_list(message.space_buckets[message.one_space]) zero_space = avg_list(message.space_buckets[message.zero_space]) diff --git a/lib/IRremoteESP8266-2.7.1/tools/auto_analyse_raw_data_test.py b/lib/IRremoteESP8266-2.7.3/tools/auto_analyse_raw_data_test.py similarity index 84% rename from lib/IRremoteESP8266-2.7.1/tools/auto_analyse_raw_data_test.py rename to lib/IRremoteESP8266-2.7.3/tools/auto_analyse_raw_data_test.py index c2fd7ba64..fa3a87933 100755 --- a/lib/IRremoteESP8266-2.7.1/tools/auto_analyse_raw_data_test.py +++ b/lib/IRremoteESP8266-2.7.3/tools/auto_analyse_raw_data_test.py @@ -1165,6 +1165,224 @@ class TestAutoAnalyseRawData(unittest.TestCase): '}\n' '#endif // DECODE_FOO\n') + def test_no_headers(self): + """Tests for no space or mark headers in parse_and_report() function.""" + + # Tests for mark or space headers. (Issue #1014) + output = StringIO() + input_str = """ + uint16_t rawData[257] = {472, 1016, 490, 536, 446, 1038, 464, 544, 490, + 516, 492, 1008, 418, 592, 462, 1042, 476, 532, 444, 1062, 474, 532, 470, + 1014, 492, 1010, 446, 562, 460, 1046, 474, 532, 472, 534, 416, 590, 458, + 548, 486, 520, 490, 516, 490, 534, 470, 534, 470, 534, 470, 536, 416, + 590, 460, 546, 488, 518, 490, 536, 468, 536, 470, 534, 470, 536, 442, + 564, 414, 1092, 470, 536, 468, 536, 416, 590, 414, 592, 486, 520, 490, + 536, 470, 534, 470, 534, 468, 536, 416, 590, 432, 574, 486, 520, 490, + 536, 470, 534, 468, 536, 468, 536, 468, 538, 420, 590, 454, 546, 488, + 518, 488, 536, 468, 536, 468, 536, 468, 536, 440, 566, 414, 592, 462, + 546, 490, 536, 468, 536, 468, 538, 468, 536, 468, 538, 414, 592, 460, + 546, 488, 518, 490, 536, 468, 536, 470, 536, 468, 536, 442, 564, 414, + 592, 462, 546, 490, 518, 488, 536, 470, 534, 470, 536, 470, 536, 416, + 590, 460, 548, 488, 518, 490, 536, 470, 534, 470, 534, 470, 536, 468, + 536, 414, 592, 462, 546, 490, 518, 488, 534, 470, 536, 468, 536, 468, + 536, 414, 590, 462, 546, 488, 518, 466, 560, 444, 560, 446, 560, 446, + 560, 444, 562, 416, 592, 462, 546, 464, 542, 464, 560, 444, 560, 446, + 560, 446, 560, 416, 590, 460, 546, 464, 544, 464, 562, 444, 560, 446, + 560, 446, 560, 444, 560, 416, 592, 462, 1042, 446, 560, 444, 560, 416, + 592, 462, 544, 488, 520, 466, 558, 446, 560, 446};""" + analyse.parse_and_report(input_str, 200, True, "", output) + self.assertEqual( + output.getvalue(), 'Found 257 timing entries.\n' + 'Potential Mark Candidates:\n' + '[492]\n' + 'Potential Space Candidates:\n' + '[1092, 592]\n' + '\n' + 'Guessing encoding type:\n' + 'Looks like it uses space encoding. Yay!\n' + '\n' + 'Guessing key value:\n' + 'kHdrMark = 0\n' + 'kHdrSpace = 0\n' + 'kBitMark = 460\n' + 'kOneSpace = 1037\n' + 'kZeroSpace = 547\n' + '\n' + 'Decoding protocol based on analysis so far:\n' + '\n' + 'kBitMark(UNEXPECTED)10100101010110100000000000000000010000000000000000' + '0000000000000000000000000000000000000000000000000000000000000000000000' + '10000000\n' + ' Bits: 128\n' + ' Hex: 0xA55A0000400000000000000000000080 (MSB first)\n' + ' 0x01000000000000000000000200005AA5 (LSB first)\n' + ' Dec: 219789926041586294144261994014272651392 (MSB first)\n' + ' 1329227995784915872903807068870302373 (LSB first)\n' + ' Bin: 0b101001010101101000000000000000000100000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000000010000000' + ' (MSB first)\n' + ' 0b000000010000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000001000000000000000000101101010100101' + ' (LSB first)\n' + '\n' + 'Total Nr. of suspected bits: 128\n' + '\n' + 'Generating a VERY rough code outline:\n' + '\n' + '// Copyright 2019 David Conran (crankyoldgit)\n' + '// Support for TBD protocol\n' + '\n' + '#include "IRrecv.h"\n' + '#include "IRsend.h"\n' + '#include "IRutils.h"\n' + '\n' + "// WARNING: This probably isn't directly usable. It's a guide only.\n" + '\n' + '// See https://github.com/crankyoldgit/IRremoteESP8266/wiki/' + 'Adding-support-for-a-new-IR-protocol\n' + '// for details of how to include this in the library.\n' + 'const uint16_t kHdrMark = 0;\n' + 'const uint16_t kBitMark = 460;\n' + 'const uint16_t kHdrSpace = 0;\n' + 'const uint16_t kOneSpace = 1037;\n' + 'const uint16_t kZeroSpace = 547;\n' + 'const uint16_t kFreq = 38000; // Hz. (Guessing the most common' + ' frequency.)\n' + 'const uint16_t kBits = 128; // Move to IRremoteESP8266.h\n' + 'const uint16_t kStateLength = 16; // Move to IRremoteESP8266.h\n' + 'const uint16_t kOverhead = 1;\n' + "// DANGER: More than 64 bits detected. A uint64_t for 'data' won't" + ' work!\n' + '#if SEND_TBD\n' + '// Function should be safe up to 64 bits.\n' + 'void IRsend::sendTBD(const uint64_t data, const uint16_t nbits, const' + ' uint16_t repeat) {\n' + ' enableIROut(kFreq);\n' + ' for (uint16_t r = 0; r <= repeat; r++) {\n' + ' uint64_t send_data = data;\n' + ' // Data Section #1\n' + ' // e.g. data = 0xA55A0000400000000000000000000080, nbits = 128\n' + ' sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, send_data,' + ' 128, true);\n' + ' send_data >>= 128;\n' + ' // Footer\n' + ' mark(kBitMark);\n' + ' space(kDefaultMessageGap); // A 100% made up guess of the gap' + ' between messages.\n' + ' }\n' + '}\n' + '#endif // SEND_TBD\n' + '\n' + '#if SEND_TBD\n' + '// Alternative >64bit function to send TBD messages\n' + '// Where data is:\n' + '// uint8_t data[kStateLength] = {0xA5, 0x5A, 0x00, 0x00, 0x40, 0x00,' + ' 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80};\n' + '//\n' + '// Args:\n' + '// data: An array of bytes containing the IR command.\n' + '// It is assumed to be in MSB order for this code.\n' + '// nbytes: Nr. of bytes of data in the array. (>=kStateLength)\n' + '// repeat: Nr. of times the message is to be repeated.\n' + '//\n' + '// Status: ALPHA / Untested.\n' + 'void IRsend::sendTBD(const uint8_t data[], const uint16_t nbytes,' + ' const uint16_t repeat) {\n' + ' for (uint16_t r = 0; r <= repeat; r++) {\n' + ' uint16_t pos = 0;\n' + ' // Data Section #1\n' + ' // e.g.\n' + ' // bits = 128; bytes = 16;\n' + ' // *(data + pos) = {0xA5, 0x5A, 0x00, 0x00, 0x40, 0x00, 0x00,' + ' 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80};\n' + ' sendGeneric(0, 0,\n' + ' kBitMark, kOneSpace,\n' + ' kBitMark, kZeroSpace,\n' + ' kBitMark, kDefaultMessageGap,\n' + ' data + pos, 16, // Bytes\n' + ' kFreq, true, kNoRepeat, kDutyDefault);\n' + ' pos += 16; // Adjust by how many bytes of data we sent\n' + ' }\n' + '}\n' + '#endif // SEND_TBD\n' + '\n' + "// DANGER: More than 64 bits detected. A uint64_t for 'data' won't" + ' work!\n' + '#if DECODE_TBD\n' + '// Function should be safe up to 64 bits.\n' + 'bool IRrecv::decodeTBD(decode_results *results, const uint16_t nbits,' + ' const bool strict) {\n' + ' if (results->rawlen < 2 * nbits + kOverhead)\n' + ' return false; // Too short a message to match.\n' + ' if (strict && nbits != kBits)\n' + ' return false;\n' + '\n' + ' uint16_t offset = kStartOffset;\n' + ' uint64_t data = 0;\n' + ' match_result_t data_result;\n' + '\n' + ' // Data Section #1\n' + ' // e.g. data_result.data = 0xA55A0000400000000000000000000080, nbits' + ' = 128\n' + ' data_result = matchData(&(results->rawbuf[offset]), 128,\n' + ' kBitMark, kOneSpace,\n' + ' kBitMark, kZeroSpace);\n' + ' offset += data_result.used;\n' + ' if (data_result.success == false) return false; // Fail\n' + ' data <<= 128; // Make room for the new bits of data.\n' + ' data |= data_result.data;\n' + '\n' + ' // Footer\n' + ' if (!matchMark(results->rawbuf[offset++], kBitMark))\n' + ' return false;\n' + '\n' + ' // Success\n' + ' results->decode_type = decode_type_t::TBD;\n' + ' results->bits = nbits;\n' + ' results->value = data;\n' + ' results->command = 0;\n' + ' results->address = 0;\n' + ' return true;\n' + '}\n' + '#endif // DECODE_TBD\n' + '\n' + '// Note: This should be 64+ bit safe.\n' + '#if DECODE_TBD\n' + '// Function should be safe over 64 bits.\n' + 'bool IRrecv::decodeTBD(decode_results *results, const uint16_t nbits,' + ' const bool strict) {\n' + ' if (results->rawlen < 2 * nbits + kOverhead)\n' + ' return false; // Too short a message to match.\n' + ' if (strict && nbits != kBits)\n' + ' return false;\n' + '\n' + ' uint16_t offset = kStartOffset;\n' + ' uint16_t pos = 0;\n' + ' uint16_t used = 0;\n' + '\n' + ' // Data Section #1\n' + ' // e.g.\n' + ' // bits = 128; bytes = 16;\n' + ' // *(results->state + pos) = {0xA5, 0x5A, 0x00, 0x00, 0x40, 0x00,' + ' 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80};\n' + ' used = matchGeneric(results->rawbuf + offset, results->state + pos,' + '\n' + ' results->rawlen - offset, 128,\n' + ' 0, 0,\n' + ' kBitMark, kOneSpace,\n' + ' kBitMark, kZeroSpace,\n' + ' kBitMark, kDefaultMessageGap, true);\n' + ' if (used == 0) return false; // We failed to find any data.\n' + ' offset += used; // Adjust for how much of the message we read.\n' + ' pos += 16; // Adjust by how many bytes of data we read\n' + '\n' + ' // Success\n' + ' results->decode_type = decode_type_t::TBD;\n' + ' results->bits = nbits;\n' + ' return true;\n' + '}\n' + '#endif // DECODE_TBD\n') + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/lib/IRremoteESP8266-2.7.1/tools/gc_decode.cpp b/lib/IRremoteESP8266-2.7.3/tools/gc_decode.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/tools/gc_decode.cpp rename to lib/IRremoteESP8266-2.7.3/tools/gc_decode.cpp diff --git a/lib/IRremoteESP8266-2.7.1/tools/generate_irtext_h.sh b/lib/IRremoteESP8266-2.7.3/tools/generate_irtext_h.sh similarity index 100% rename from lib/IRremoteESP8266-2.7.1/tools/generate_irtext_h.sh rename to lib/IRremoteESP8266-2.7.3/tools/generate_irtext_h.sh diff --git a/lib/IRremoteESP8266-2.7.1/tools/mkkeywords b/lib/IRremoteESP8266-2.7.3/tools/mkkeywords similarity index 100% rename from lib/IRremoteESP8266-2.7.1/tools/mkkeywords rename to lib/IRremoteESP8266-2.7.3/tools/mkkeywords diff --git a/lib/IRremoteESP8266-2.7.1/tools/mode2_decode.cpp b/lib/IRremoteESP8266-2.7.3/tools/mode2_decode.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.1/tools/mode2_decode.cpp rename to lib/IRremoteESP8266-2.7.3/tools/mode2_decode.cpp diff --git a/lib/IRremoteESP8266-2.7.1/tools/scrape_supported_devices.py b/lib/IRremoteESP8266-2.7.3/tools/scrape_supported_devices.py similarity index 73% rename from lib/IRremoteESP8266-2.7.1/tools/scrape_supported_devices.py rename to lib/IRremoteESP8266-2.7.3/tools/scrape_supported_devices.py index 574eac351..c859bbf06 100755 --- a/lib/IRremoteESP8266-2.7.1/tools/scrape_supported_devices.py +++ b/lib/IRremoteESP8266-2.7.3/tools/scrape_supported_devices.py @@ -9,14 +9,17 @@ import time CODE_URL = "https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_" BRAND_MODEL = re.compile(r"Brand: *(?P.+), *Model: *(?P.+)") -ENUMS = re.compile(r"enum \w+ {(.+?)};", re.DOTALL) +ENUMS = re.compile(r"enum (\w+) {(.+?)};", re.DOTALL) ENUM_ENTRY = re.compile(r"^\s+(\w+)", re.MULTILINE) -DECODED_PROTOCOLS = re.compile(r".*results->decode_type *=.*?(\w+);") -AC_FN = re.compile(r"ir_(.+).h") +DECODED_PROTOCOLS = re.compile(r".*(?:results->decode_type *=.*?|" + r"typeguess\s*=\s*decode_type_t::)(\w+);") +AC_FN = re.compile(r"ir_(.+)\.h") +AC_MODEL_ENUM_RE = re.compile(r"(.+)_ac_remote_model_t") +IRSEND_FN_RE = re.compile(r"IRsend\.h") +ALL_FN = re.compile(r"ir_(.+)\.(h|cpp)") -ALL_FN = re.compile(r"ir_(.+).(h|cpp)") - -EXCLUDED_PROTOCOLS = ["UNKNOWN", "UNUSED", "kLastDecodeType"] +EXCLUDED_PROTOCOLS = ["UNKNOWN", "UNUSED", "kLastDecodeType", "typeguess"] +EXCLUDED_ACS = ["Magiquest", "NEC"] MARKDOWN_HEADER = """ MCU State: %s Current State:%s"), fnId - TUYA_MCU_FUNC_REL1 + 1, Tuya.buffer[10]?"On":"Off",bitRead(power, fnId - TUYA_MCU_FUNC_REL1)?"On":"Off"); - if ((power || Settings.light_dimmer > 0) && (Tuya.buffer[10] != bitRead(power, fnId - TUYA_MCU_FUNC_REL1))) { - ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1 + 1, Tuya.buffer[10], SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction - } - } else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Relay-%d-Inverted --> MCU State: %s Current State:%s"), fnId - TUYA_MCU_FUNC_REL1_INV + 1, Tuya.buffer[10]?"Off":"On",bitRead(power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1?"Off":"On"); - if (Tuya.buffer[10] != bitRead(power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1) { - ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1_INV + 1, Tuya.buffer[10] ^ 1, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction - } - } else if (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Switch-%d --> MCU State: %d Current State:%d"),fnId - TUYA_MCU_FUNC_SWT1 + 1,Tuya.buffer[10], SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1)); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: fnId=%d is set for dpId=%d"), fnId, Tuya.buffer[dpidStart]); + // if (TuyaFuncIdValid(fnId)) { + if (Tuya.buffer[dpidStart + 1] == 1) { // Data Type 1 - if (SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1) != Tuya.buffer[10]) { - SwitchSetVirtual(fnId - TUYA_MCU_FUNC_SWT1, Tuya.buffer[10]); - SwitchHandler(1); + if (fnId >= TUYA_MCU_FUNC_REL1 && fnId <= TUYA_MCU_FUNC_REL8) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Relay-%d --> MCU State: %s Current State:%s"), fnId - TUYA_MCU_FUNC_REL1 + 1, Tuya.buffer[dpidStart + 4]?"On":"Off",bitRead(power, fnId - TUYA_MCU_FUNC_REL1)?"On":"Off"); + if ((power || Settings.light_dimmer > 0) && (Tuya.buffer[dpidStart + 4] != bitRead(power, fnId - TUYA_MCU_FUNC_REL1))) { + ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1 + 1, Tuya.buffer[dpidStart + 4], SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction + } + } else if (fnId >= TUYA_MCU_FUNC_REL1_INV && fnId <= TUYA_MCU_FUNC_REL8_INV) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Relay-%d-Inverted --> MCU State: %s Current State:%s"), fnId - TUYA_MCU_FUNC_REL1_INV + 1, Tuya.buffer[dpidStart + 4]?"Off":"On",bitRead(power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1?"Off":"On"); + if (Tuya.buffer[dpidStart + 4] != bitRead(power, fnId - TUYA_MCU_FUNC_REL1_INV) ^ 1) { + ExecuteCommandPower(fnId - TUYA_MCU_FUNC_REL1_INV + 1, Tuya.buffer[dpidStart + 4] ^ 1, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction + } + } else if (fnId >= TUYA_MCU_FUNC_SWT1 && fnId <= TUYA_MCU_FUNC_SWT4) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Switch-%d --> MCU State: %d Current State:%d"),fnId - TUYA_MCU_FUNC_SWT1 + 1,Tuya.buffer[dpidStart + 4], SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1)); + + if (SwitchGetVirtual(fnId - TUYA_MCU_FUNC_SWT1) != Tuya.buffer[dpidStart + 4]) { + SwitchSetVirtual(fnId - TUYA_MCU_FUNC_SWT1, Tuya.buffer[dpidStart + 4]); + SwitchHandler(1); + } } + } + else if (Tuya.buffer[dpidStart + 1] == 2) { // Data Type 2 + bool tuya_energy_enabled = (XNRG_16 == energy_flg); + uint16_t packetValue = Tuya.buffer[dpidStart + 6] << 8 | Tuya.buffer[dpidStart + 7]; + if (fnId == TUYA_MCU_FUNC_DIMMER) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Dim State=%d"), packetValue); + Tuya.new_dim = changeUIntScale(packetValue, 0, Settings.dimmer_hw_max, 0, 100); + if ((power || Settings.flag3.tuya_apply_o20) && // SetOption54 - Apply SetOption20 settings to Tuya device + (Tuya.new_dim > 0) && (abs(Tuya.new_dim - Settings.light_dimmer) > 1)) { + Tuya.ignore_dim = true; - } - else if (Tuya.buffer[5] == 8) { // Long value packet - bool tuya_energy_enabled = (XNRG_16 == energy_flg); - uint16_t packetValue = Tuya.buffer[12] << 8 | Tuya.buffer[13]; - if (fnId == TUYA_MCU_FUNC_DIMMER) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: RX Dim State=%d"), packetValue); - Tuya.new_dim = changeUIntScale(packetValue, 0, Settings.dimmer_hw_max, 0, 100); - if ((power || Settings.flag3.tuya_apply_o20) && // SetOption54 - Apply SetOption20 settings to Tuya device - (Tuya.new_dim > 0) && (abs(Tuya.new_dim - Settings.light_dimmer) > 1)) { - Tuya.ignore_dim = true; - - snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), Tuya.new_dim ); - ExecuteCommand(scmnd, SRC_SWITCH); + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), Tuya.new_dim ); + ExecuteCommand(scmnd, SRC_SWITCH); + } } - } -#ifdef USE_ENERGY_SENSOR - else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_VOLTAGE) { - Energy.voltage[0] = (float)packetValue / 10; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Voltage=%d"), Tuya.buffer[6], packetValue); - } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_CURRENT) { - Energy.current[0] = (float)packetValue / 1000; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Current=%d"), Tuya.buffer[6], packetValue); - } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER) { - Energy.active_power[0] = (float)packetValue / 10; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Active_Power=%d"), Tuya.buffer[6], packetValue); + #ifdef USE_ENERGY_SENSOR + else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_VOLTAGE) { + Energy.voltage[0] = (float)packetValue / 10; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Voltage=%d"), Tuya.buffer[dpidStart], packetValue); + } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_CURRENT) { + Energy.current[0] = (float)packetValue / 1000; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Current=%d"), Tuya.buffer[dpidStart], packetValue); + } else if (tuya_energy_enabled && fnId == TUYA_MCU_FUNC_POWER) { + Energy.active_power[0] = (float)packetValue / 10; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Rx ID=%d Active_Power=%d"), Tuya.buffer[dpidStart], packetValue); - if (Tuya.lastPowerCheckTime != 0 && Energy.active_power[0] > 0) { - Energy.kWhtoday += (float)Energy.active_power[0] * (Rtc.utc_time - Tuya.lastPowerCheckTime) / 36; - EnergyUpdateToday(); + if (Tuya.lastPowerCheckTime != 0 && Energy.active_power[0] > 0) { + Energy.kWhtoday += (float)Energy.active_power[0] * (Rtc.utc_time - Tuya.lastPowerCheckTime) / 36; + EnergyUpdateToday(); + } + Tuya.lastPowerCheckTime = Rtc.utc_time; } - Tuya.lastPowerCheckTime = Rtc.utc_time; - } -#endif // USE_ENERGY_SENSOR + #endif // USE_ENERGY_SENSOR - } - // } else { - // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Unknown FnId=%s for dpId=%s"), fnId, Tuya.buffer[6]); - // } + } + // } else { + // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TYA: Unknown FnId=%s for dpId=%s"), fnId, Tuya.buffer[6]); + dpidStart += dpDataLen + 4; + } } void TuyaLowPowerModePacketProcess(void) { @@ -671,10 +678,17 @@ void TuyaSerialInput(void) if (len > 0) { ResponseAppend_P(PSTR(",\"CmndData\":\"%s\""), ToHex_P((unsigned char*)&Tuya.buffer[6], len, hex_char, sizeof(hex_char))); if (TUYA_CMD_STATE == Tuya.buffer[3]) { - uint16_t dpDataLen = Tuya.buffer[8] << 8 | Tuya.buffer[9]; - ResponseAppend_P(PSTR(",\"DpId\":%d,\"DpIdType\":%d,\"DpIdData\":\"%s\""), Tuya.buffer[6], Tuya.buffer[7], ToHex_P((unsigned char*)&Tuya.buffer[10], dpDataLen, hex_char, sizeof(hex_char))); - if (TUYA_TYPE_STRING == Tuya.buffer[7]) { - ResponseAppend_P(PSTR(",\"Type3Data\":\"%.*s\""), dpDataLen, (char *)&Tuya.buffer[10]); + //55 AA 03 07 00 0D 01 04 00 01 02 02 02 00 04 00 00 00 1A 40 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + uint8_t dpidStart = 6; + while (dpidStart + 4 < Tuya.byte_counter) { + uint16_t dpDataLen = Tuya.buffer[dpidStart + 2] << 8 | Tuya.buffer[dpidStart + 3]; + ResponseAppend_P(PSTR(",\"%d\":{\"DpId\":%d,\"DpIdType\":%d,\"DpIdData\":\"%s\""), Tuya.buffer[dpidStart], Tuya.buffer[dpidStart], Tuya.buffer[dpidStart + 1], ToHex_P((unsigned char*)&Tuya.buffer[dpidStart + 4], dpDataLen, hex_char, sizeof(hex_char))); + if (TUYA_TYPE_STRING == Tuya.buffer[dpidStart + 1]) { + ResponseAppend_P(PSTR(",\"Type3Data\":\"%.*s\""), dpDataLen, (char *)&Tuya.buffer[dpidStart + 4]); + } + ResponseAppend_P(PSTR("}")); + dpidStart += dpDataLen + 4; } } } @@ -794,7 +808,7 @@ bool Xdrv16(uint8_t function) case FUNC_MODULE_INIT: result = TuyaModuleSelected(); break; - case FUNC_INIT: + case FUNC_PRE_INIT: TuyaInit(); break; case FUNC_SET_DEVICE_POWER: diff --git a/tasmota/xdrv_17_rcswitch.ino b/tasmota/xdrv_17_rcswitch.ino index 4462a5e21..9cd2d14d8 100644 --- a/tasmota/xdrv_17_rcswitch.ino +++ b/tasmota/xdrv_17_rcswitch.ino @@ -105,7 +105,7 @@ void CmndRfSend(void) int repeat = 10; int pulse = 350; - char dataBufUc[XdrvMailbox.data_len]; + char dataBufUc[XdrvMailbox.data_len + 1]; UpperCase(dataBufUc, XdrvMailbox.data); StaticJsonBuffer<150> jsonBuf; // ArduinoJSON entry used to calculate jsonBuf: JSON_OBJECT_SIZE(5) + 40 = 134 JsonObject &root = jsonBuf.parseObject(dataBufUc); diff --git a/tasmota/xdrv_20_hue.ino b/tasmota/xdrv_20_hue.ino index 37de3a902..9bd88193c 100644 --- a/tasmota/xdrv_20_hue.ino +++ b/tasmota/xdrv_20_hue.ino @@ -100,7 +100,8 @@ void HueRespondToMSearch(void) } else { snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE)); } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_HUE " %s " D_TO " %s:%d"), + // Do not use AddLog_P2 here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9 + PrepLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_HUE " %s " D_TO " %s:%d"), message, udp_remote_ip.toString().c_str(), udp_remote_port); udp_response_mutex = false; @@ -279,7 +280,7 @@ void HueLightStatus1(uint8_t device, String *response) #ifdef USE_SHUTTER if (ShutterState(device)) { - bri = (float)(Settings.shutter_invert[device-1] ? 100 - Settings.shutter_position[device-1] : Settings.shutter_position[device-1]) / 100; + bri = (float)((Settings.shutter_options[device-1] & 1) ? 100 - Settings.shutter_position[device-1] : Settings.shutter_position[device-1]) / 100; } #endif @@ -681,7 +682,7 @@ void HueLights(String *path) if (change) { #ifdef USE_SHUTTER if (ShutterState(device)) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Settings.shutter_invert: %d"), Settings.shutter_invert[device-1]); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Settings.shutter_invert: %d"), Settings.shutter_options[device-1] & 1); ShutterSetPosition(device, bri * 100.0f ); } else #endif diff --git a/tasmota/xdrv_21_wemo.ino b/tasmota/xdrv_21_wemo.ino index 6aef27311..85d462876 100644 --- a/tasmota/xdrv_21_wemo.ino +++ b/tasmota/xdrv_21_wemo.ino @@ -74,7 +74,8 @@ void WemoRespondToMSearch(int echo_type) } else { snprintf_P(message, sizeof(message), PSTR(D_FAILED_TO_SEND_RESPONSE)); } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"), + // Do not use AddLog_P2 here (interrupt routine) if syslog or mqttlog is enabled. UDP/TCP will force exception 9 + PrepLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP D_WEMO " " D_JSON_TYPE " %d, %s " D_TO " %s:%d"), echo_type, message, udp_remote_ip.toString().c_str(), udp_remote_port); udp_response_mutex = false; diff --git a/tasmota/xdrv_23_zigbee_3_devices.ino b/tasmota/xdrv_23_zigbee_3_devices.ino index 1d793f730..984842380 100644 --- a/tasmota/xdrv_23_zigbee_3_devices.ino +++ b/tasmota/xdrv_23_zigbee_3_devices.ino @@ -22,6 +22,10 @@ #include #include +#ifndef ZIGBEE_SAVE_DELAY_SECONDS +#define ZIGBEE_SAVE_DELAY_SECONDS 10; // wait for 10s before saving Zigbee info +#endif +const uint16_t kZigbeeSaveDelaySeconds = ZIGBEE_SAVE_DELAY_SECONDS; // wait for x seconds typedef int32_t (*Z_DeviceTimer)(uint16_t shortaddr, uint16_t cluster, uint16_t endpoint, uint32_t value); @@ -57,6 +61,18 @@ class Z_Devices { public: Z_Devices() {}; + // Probe the existence of device keys + // Results: + // - 0x0000 = not found + // - 0xFFFF = bad parameter + // - 0x = the device's short address + uint16_t isKnownShortAddr(uint16_t shortaddr) const; + uint16_t isKnownLongAddr(uint64_t longaddr) const; + uint16_t isKnownIndex(uint32_t index) const; + uint16_t isKnownFriendlyName(const char * name) const; + + uint64_t getDeviceLongAddr(uint16_t shortaddr) const; + // Add new device, provide ShortAddr and optional longAddr // If it is already registered, update information, otherwise create the entry void updateDevice(uint16_t shortaddr, uint64_t longaddr = 0); @@ -74,13 +90,14 @@ public: void setManufId(uint16_t shortaddr, const char * str); void setModelId(uint16_t shortaddr, const char * str); - void setFriendlyNameId(uint16_t shortaddr, const char * str); + void setFriendlyName(uint16_t shortaddr, const char * str); + const String * getFriendlyName(uint16_t) const; // device just seen on the network, update the lastSeen field void updateLastSeen(uint16_t shortaddr); // Dump json - String dump(uint32_t dump_mode, int32_t device_num = 0) const; + String dump(uint32_t dump_mode, uint16_t status_shortaddr = 0) const; // Timers void resetTimer(uint32_t shortaddr); @@ -89,13 +106,33 @@ public: // Append or clear attributes Json structure void jsonClear(uint16_t shortaddr); - void jsonAppend(uint16_t shortaddr, JsonObject &values); + void jsonAppend(uint16_t shortaddr, const JsonObject &values); const JsonObject *jsonGet(uint16_t shortaddr); - const void jsonPublish(uint16_t shortaddr); // publish the json message and clear buffer + void jsonPublishFlush(uint16_t shortaddr); // publish the json message and clear buffer bool jsonIsConflict(uint16_t shortaddr, const JsonObject &values); + void jsonPublishNow(uint16_t shortaddr, JsonObject &values); + + // Iterator + size_t devicesSize(void) const { + return _devices.size(); + } + const Z_Device &devicesAt(size_t i) const { + return _devices.at(i); + } + + // Remove device from list + bool removeDevice(uint16_t shortaddr); + + // Mark data as 'dirty' and requiring to save in Flash + void dirty(void); + void clean(void); // avoid writing to flash the last changes + + // Find device by name, can be short_addr, long_addr, number_in_array or name + uint16_t parseDeviceParam(const char * param, bool short_must_be_known = false) const; private: std::vector _devices = {}; + uint32_t _saveTimer = 0; template < typename T> static bool findInVector(const std::vector & vecOfElements, const T & element); @@ -107,10 +144,12 @@ private: static int32_t findClusterEndpoint(const std::vector & vecOfElements, uint16_t element); Z_Device & getShortAddr(uint16_t shortaddr); // find Device from shortAddr, creates it if does not exist + const Z_Device & getShortAddrConst(uint16_t shortaddr) const ; // find Device from shortAddr, creates it if does not exist Z_Device & getLongAddr(uint64_t longaddr); // find Device from shortAddr, creates it if does not exist - int32_t findShortAddr(uint16_t shortaddr); - int32_t findLongAddr(uint64_t longaddr); + int32_t findShortAddr(uint16_t shortaddr) const; + int32_t findLongAddr(uint64_t longaddr) const; + int32_t findFriendlyName(const char * name) const; void _updateLastSeen(Z_Device &device) { if (&device != nullptr) { @@ -124,6 +163,9 @@ private: Z_Devices zigbee_devices = Z_Devices(); +// Local coordinator information +uint64_t localIEEEAddr = 0; + // https://thispointer.com/c-how-to-find-an-element-in-vector-and-get-its-index/ template < typename T> bool Z_Devices::findInVector(const std::vector & vecOfElements, const T & element) { @@ -187,6 +229,7 @@ Z_Device & Z_Devices::createDeviceEntry(uint16_t shortaddr, uint64_t longaddr) { nullptr, nullptr }; device.json_buffer = new DynamicJsonBuffer(); _devices.push_back(device); + dirty(); return _devices.back(); } @@ -198,7 +241,7 @@ Z_Device & Z_Devices::createDeviceEntry(uint16_t shortaddr, uint64_t longaddr) { // Out: // index in _devices of entry, -1 if not found // -int32_t Z_Devices::findShortAddr(uint16_t shortaddr) { +int32_t Z_Devices::findShortAddr(uint16_t shortaddr) const { if (!shortaddr) { return -1; } // does not make sense to look for 0x0000 shortaddr (localhost) int32_t found = 0; if (shortaddr) { @@ -217,7 +260,7 @@ int32_t Z_Devices::findShortAddr(uint16_t shortaddr) { // Out: // index in _devices of entry, -1 if not found // -int32_t Z_Devices::findLongAddr(uint64_t longaddr) { +int32_t Z_Devices::findLongAddr(uint64_t longaddr) const { if (!longaddr) { return -1; } int32_t found = 0; if (longaddr) { @@ -228,6 +271,71 @@ int32_t Z_Devices::findLongAddr(uint64_t longaddr) { } return -1; } +// +// Scan all devices to find a corresponding friendlyNme +// Looks info device.friendlyName entry +// In: +// friendlyName (null terminated, should not be empty) +// Out: +// index in _devices of entry, -1 if not found +// +int32_t Z_Devices::findFriendlyName(const char * name) const { + if (!name) { return -1; } // if pointer is null + size_t name_len = strlen(name); + int32_t found = 0; + if (name_len) { + for (auto &elem : _devices) { + if (elem.friendlyName == name) { return found; } + found++; + } + } + return -1; +} + +// Probe if device is already known but don't create any entry +uint16_t Z_Devices::isKnownShortAddr(uint16_t shortaddr) const { + int32_t found = findShortAddr(shortaddr); + if (found >= 0) { + return shortaddr; + } else { + return 0; // unknown + } +} + +uint16_t Z_Devices::isKnownLongAddr(uint64_t longaddr) const { + int32_t found = findLongAddr(longaddr); + if (found >= 0) { + const Z_Device & device = devicesAt(found); + return device.shortaddr; // can be zero, if not yet registered + } else { + return 0; + } +} + +uint16_t Z_Devices::isKnownIndex(uint32_t index) const { + if (index < devicesSize()) { + const Z_Device & device = devicesAt(index); + return device.shortaddr; + } else { + return 0; + } +} + +uint16_t Z_Devices::isKnownFriendlyName(const char * name) const { + if ((!name) || (0 == strlen(name))) { return 0xFFFF; } // Error + int32_t found = findFriendlyName(name); + if (found >= 0) { + const Z_Device & device = devicesAt(found); + return device.shortaddr; // can be zero, if not yet registered + } else { + return 0; + } +} + +uint64_t Z_Devices::getDeviceLongAddr(uint16_t shortaddr) const { + const Z_Device & device = getShortAddrConst(shortaddr); + return device.longaddr; +} // // We have a seen a shortaddr on the network, get the corresponding @@ -238,9 +346,18 @@ Z_Device & Z_Devices::getShortAddr(uint16_t shortaddr) { if (found >= 0) { return _devices[found]; } -//Serial.printf("Device entry created for shortaddr = 0x%02X, found = %d\n", shortaddr, found); + //Serial.printf("Device entry created for shortaddr = 0x%02X, found = %d\n", shortaddr, found); return createDeviceEntry(shortaddr, 0); } +// Same version but Const +const Z_Device & Z_Devices::getShortAddrConst(uint16_t shortaddr) const { + if (!shortaddr) { return *(Z_Device*) nullptr; } // this is not legal + int32_t found = findShortAddr(shortaddr); + if (found >= 0) { + return _devices[found]; + } + return *((Z_Device*)nullptr); +} // find the Device object by its longaddr (unique key if not null) Z_Device & Z_Devices::getLongAddr(uint64_t longaddr) { @@ -252,6 +369,17 @@ Z_Device & Z_Devices::getLongAddr(uint64_t longaddr) { return createDeviceEntry(0, longaddr); } +// Remove device from list, return true if it was known, false if it was not recorded +bool Z_Devices::removeDevice(uint16_t shortaddr) { + int32_t found = findShortAddr(shortaddr); + if (found >= 0) { + _devices.erase(_devices.begin() + found); + dirty(); + return true; + } + return false; +} + // // We have just seen a device on the network, update the info based on short/long addr // In: @@ -270,15 +398,18 @@ void Z_Devices::updateDevice(uint16_t shortaddr, uint64_t longaddr) { // erase the previous shortaddr _devices.erase(_devices.begin() + s_found); updateLastSeen(shortaddr); + dirty(); } } else if (s_found >= 0) { // shortaddr already exists but longaddr not // add the longaddr to the entry _devices[s_found].longaddr = longaddr; updateLastSeen(shortaddr); + dirty(); } else if (l_found >= 0) { // longaddr entry exists, update shortaddr _devices[l_found].shortaddr = shortaddr; + dirty(); } else { // neither short/lonf addr are found. if (shortaddr || longaddr) { @@ -298,6 +429,7 @@ void Z_Devices::addEndoint(uint16_t shortaddr, uint8_t endpoint) { _updateLastSeen(device); if (findEndpointInVector(device.endpoints, ep_profile) < 0) { device.endpoints.push_back(ep_profile); + dirty(); } } @@ -310,8 +442,12 @@ void Z_Devices::addEndointProfile(uint16_t shortaddr, uint8_t endpoint, uint16_t int32_t found = findEndpointInVector(device.endpoints, ep_profile); if (found < 0) { device.endpoints.push_back(ep_profile); + dirty(); } else { - device.endpoints[found] = ep_profile; + if (device.endpoints[found] != ep_profile) { + device.endpoints[found] = ep_profile; + dirty(); + } } } @@ -324,10 +460,12 @@ void Z_Devices::addCluster(uint16_t shortaddr, uint8_t endpoint, uint16_t cluste if (!out) { if (!findInVector(device.clusters_in, ep_cluster)) { device.clusters_in.push_back(ep_cluster); + dirty(); } } else { // out if (!findInVector(device.clusters_out, ep_cluster)) { device.clusters_out.push_back(ep_cluster); + dirty(); } } } @@ -352,21 +490,41 @@ void Z_Devices::setManufId(uint16_t shortaddr, const char * str) { Z_Device & device = getShortAddr(shortaddr); if (&device == nullptr) { return; } // don't crash if not found _updateLastSeen(device); + if (!device.manufacturerId.equals(str)) { + dirty(); + } device.manufacturerId = str; } void Z_Devices::setModelId(uint16_t shortaddr, const char * str) { Z_Device & device = getShortAddr(shortaddr); if (&device == nullptr) { return; } // don't crash if not found _updateLastSeen(device); + if (!device.modelId.equals(str)) { + dirty(); + } device.modelId = str; } -void Z_Devices::setFriendlyNameId(uint16_t shortaddr, const char * str) { +void Z_Devices::setFriendlyName(uint16_t shortaddr, const char * str) { Z_Device & device = getShortAddr(shortaddr); if (&device == nullptr) { return; } // don't crash if not found _updateLastSeen(device); + if (!device.friendlyName.equals(str)) { + dirty(); + } device.friendlyName = str; } +const String * Z_Devices::getFriendlyName(uint16_t shortaddr) const { + int32_t found = findShortAddr(shortaddr); + if (found >= 0) { + const Z_Device & device = devicesAt(found); + if (device.friendlyName.length() > 0) { + return &device.friendlyName; + } + } + return nullptr; +} + // device just seen on the network, update the lastSeen field void Z_Devices::updateLastSeen(uint16_t shortaddr) { Z_Device & device = getShortAddr(shortaddr); @@ -398,19 +556,22 @@ void Z_Devices::setTimer(uint32_t shortaddr, uint32_t wait_ms, uint16_t cluster, // Run timer at each tick void Z_Devices::runTimer(void) { - uint32_t now = millis(); - for (std::vector::iterator it = _devices.begin(); it != _devices.end(); ++it) { Z_Device &device = *it; uint16_t shortaddr = device.shortaddr; uint32_t timer = device.timer; - if ((timer) && (timer <= now)) { + if ((timer) && TimeReached(timer)) { device.timer = 0; // cancel the timer before calling, so the callback can set another timer // trigger the timer (*device.func)(device.shortaddr, device.cluster, device.endpoint, device.value); } } + // save timer + if ((_saveTimer) && TimeReached(_saveTimer)) { + saveZigbeeDevices(); + _saveTimer = 0; + } } void Z_Devices::jsonClear(uint16_t shortaddr) { @@ -482,7 +643,7 @@ bool Z_Devices::jsonIsConflict(uint16_t shortaddr, const JsonObject &values) { return false; } -void Z_Devices::jsonAppend(uint16_t shortaddr, JsonObject &values) { +void Z_Devices::jsonAppend(uint16_t shortaddr, const JsonObject &values) { Z_Device & device = getShortAddr(shortaddr); if (&device == nullptr) { return; } // don't crash if not found if (&values == nullptr) { return; } @@ -490,6 +651,16 @@ void Z_Devices::jsonAppend(uint16_t shortaddr, JsonObject &values) { if (nullptr == device.json) { device.json = &(device.json_buffer->createObject()); } + // Prepend Device, will be removed later if redundant + char sa[8]; + snprintf_P(sa, sizeof(sa), PSTR("0x%04X"), shortaddr); + device.json->set(F(D_JSON_ZIGBEE_DEVICE), sa); + // Prepend Friendly Name if it has one + const String * fname = zigbee_devices.getFriendlyName(shortaddr); + if (fname) { + device.json->set(F(D_JSON_ZIGBEE_NAME), (char*)fname->c_str()); // (char*) forces ArduinoJson to make a copy of the cstring + } + // copy all values from 'values' to 'json' CopyJsonObject(*device.json, values); } @@ -500,40 +671,125 @@ const JsonObject *Z_Devices::jsonGet(uint16_t shortaddr) { return device.json; } -const void Z_Devices::jsonPublish(uint16_t shortaddr) { - const JsonObject *json = zigbee_devices.jsonGet(shortaddr); - if (json == nullptr) { return; } // don't crash if not found +void Z_Devices::jsonPublishFlush(uint16_t shortaddr) { + Z_Device & device = getShortAddr(shortaddr); + if (&device == nullptr) { return; } // don't crash if not found + JsonObject * json = device.json; + if (json == nullptr) { return; } // abort if nothing in buffer + + const String * fname = zigbee_devices.getFriendlyName(shortaddr); + bool use_fname = (Settings.flag4.zigbee_use_names) && (fname); // should we replace shortaddr with friendlyname? + + // if (use_fname) { + // // we need to add the Device short_addr inside the JSON + // char sa[8]; + // snprintf_P(sa, sizeof(sa), PSTR("0x%04X"), shortaddr); + // json->set(F(D_JSON_ZIGBEE_DEVICE), sa); + // } else if (fname) { + // json->set(F(D_JSON_NAME), (char*) fname); + // } + + // Remove redundant "Name" or "Device" + if (use_fname) { + json->remove(F(D_JSON_ZIGBEE_NAME)); + } else { + json->remove(F(D_JSON_ZIGBEE_DEVICE)); + } String msg = ""; json->printTo(msg); zigbee_devices.jsonClear(shortaddr); - Response_P(PSTR("{\"" D_CMND_ZIGBEE_RECEIVED "\":{\"0x%04X\":%s}}"), shortaddr, msg.c_str()); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); - XdrvRulesProcess(); + + if (use_fname) { + Response_P(PSTR("{\"" D_JSON_ZIGBEE_RECEIVED "\":{\"%s\":%s}}"), fname->c_str(), msg.c_str()); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); + XdrvRulesProcess(); + // DEPRECATED TODO + Response_P(PSTR("{\"" D_JSON_ZIGBEE_RECEIVED_LEGACY "\":{\"%s\":%s}}"), fname->c_str(), msg.c_str()); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); + XdrvRulesProcess(); + } else { + Response_P(PSTR("{\"" D_JSON_ZIGBEE_RECEIVED "\":{\"0x%04X\":%s}}"), shortaddr, msg.c_str()); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); + XdrvRulesProcess(); + // DEPRECATED TODO + Response_P(PSTR("{\"" D_JSON_ZIGBEE_RECEIVED_LEGACY "\":{\"0x%04X\":%s}}"), shortaddr, msg.c_str()); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); + XdrvRulesProcess(); + } + // MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); + // XdrvRulesProcess(); } +void Z_Devices::jsonPublishNow(uint16_t shortaddr, JsonObject & values) { + jsonPublishFlush(shortaddr); // flush any previous buffer + jsonAppend(shortaddr, values); + jsonPublishFlush(shortaddr); // publish now +} + +void Z_Devices::dirty(void) { + _saveTimer = kZigbeeSaveDelaySeconds * 1000 + millis(); +} +void Z_Devices::clean(void) { + _saveTimer = 0; +} + +// Parse the command parameters for either: +// - a short address starting with "0x", example: 0x1234 +// - a long address starting with "0x", example: 0x7CB03EBB0A0292DD +// - a number 0..99, the index number in ZigbeeStatus +// - a friendly name, between quotes, example: "Room_Temp" +uint16_t Z_Devices::parseDeviceParam(const char * param, bool short_must_be_known) const { + if (nullptr == param) { return 0; } + size_t param_len = strlen(param); + char dataBuf[param_len + 1]; + strcpy(dataBuf, param); + RemoveSpace(dataBuf); + uint16_t shortaddr = 0; + + if (strlen(dataBuf) < 4) { + // simple number 0..99 + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 99)) { + shortaddr = zigbee_devices.isKnownIndex(XdrvMailbox.payload - 1); + } + } else if ((dataBuf[0] == '0') && (dataBuf[1] == 'x')) { + // starts with 0x + if (strlen(dataBuf) < 18) { + // expect a short address + shortaddr = strtoull(dataBuf, nullptr, 0); + if (short_must_be_known) { + shortaddr = zigbee_devices.isKnownShortAddr(shortaddr); + } + // else we don't check if it's already registered to force unregistered devices + } else { + // expect a long address + uint64_t longaddr = strtoull(dataBuf, nullptr, 0); + shortaddr = zigbee_devices.isKnownLongAddr(longaddr); + } + } else { + // expect a Friendly Name + shortaddr = zigbee_devices.isKnownFriendlyName(dataBuf); + } + + return shortaddr; +} // Dump the internal memory of Zigbee devices -// Mode = 1: simple dump of devices addresses and names -// Mode = 2: Mode 1 + also dump the endpoints, profiles and clusters -String Z_Devices::dump(uint32_t dump_mode, int32_t device_num) const { +// Mode = 1: simple dump of devices addresses +// Mode = 2: simple dump of devices addresses and names +// Mode = 3: Mode 2 + also dump the endpoints, profiles and clusters +String Z_Devices::dump(uint32_t dump_mode, uint16_t status_shortaddr) const { DynamicJsonBuffer jsonBuffer; JsonArray& json = jsonBuffer.createArray(); JsonArray& devices = json; - //JsonArray& devices = json.createNestedArray(F("ZigbeeDevices")); - - // if device_num == 0, then we show all devices. - // When no payload, the default is -99. In this case change it to 0. - if (device_num < 0) { device_num = 0; } - - uint32_t device_current = 1; - for (std::vector::const_iterator it = _devices.begin(); it != _devices.end(); ++it, ++device_current) { - // ignore non-current device, if specified device is non-zero - if ((device_num > 0) && (device_num != device_current)) { continue; } + for (std::vector::const_iterator it = _devices.begin(); it != _devices.end(); ++it) { const Z_Device& device = *it; uint16_t shortaddr = device.shortaddr; - char hex[20]; + char hex[22]; + + // ignore non-current device, if specified device is non-zero + if ((status_shortaddr) && (status_shortaddr != shortaddr)) { continue; } JsonObject& dev = devices.createNestedObject(); @@ -545,7 +801,9 @@ String Z_Devices::dump(uint32_t dump_mode, int32_t device_num) const { } if (2 <= dump_mode) { - Uint64toHex(device.longaddr, hex, 64); + hex[0] = '0'; // prefix with '0x' + hex[1] = 'x'; + Uint64toHex(device.longaddr, &hex[2], 64); dev[F("IEEEAddr")] = hex; if (device.modelId.length() > 0) { dev[F(D_JSON_MODEL D_JSON_ID)] = device.modelId; diff --git a/tasmota/xdrv_23_zigbee_4_persistence.ino b/tasmota/xdrv_23_zigbee_4_persistence.ino new file mode 100644 index 000000000..fcf1dcdc3 --- /dev/null +++ b/tasmota/xdrv_23_zigbee_4_persistence.ino @@ -0,0 +1,334 @@ +/* + xdrv_23_zigbee.ino - zigbee support for Tasmota + + Copyright (C) 2020 Theo Arends and Stephan Hadinger + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_ZIGBEE + +// Ensure persistence of devices into Flash +// +// Structure: +// (from file info): +// uint16 - start address in Flash (offset) +// uint16 - length in bytes (makes sure parsing stops) +// +// File structure: +// uint8 - number of devices, 0=none, 0xFF=invalid entry (probably Flash was erased) +// +// [Array of devices] +// [Offset = 2] +// uint8 - length of revice record +// uint16 - short address +// uint64 - long IEEE address +// uint8 - number of endpoints +// [Array of endpoints] +// uint8 - endpoint number +// uint16 - profileID of the endpoint +// Array of uint8 - clusters In codes, 0xFF end marker +// Array of uint8 - clusters Out codes, 0xFF end marker +// +// str - ModelID (null terminated C string, 32 chars max) +// str - Manuf (null terminated C string, 32 chars max) +// reserved for extensions + +// Memory footprint +const static uint16_t z_spi_start_sector = 0xFF; // Force last bank of first MB +const static uint8_t* z_spi_start = (uint8_t*) 0x402FF000; // 0x402FF000 +const static uint8_t* z_dev_start = z_spi_start + 0x0800; // 0x402FF800 - 2KB +const static size_t z_spi_len = 0x1000; // 4kb blocs +const static size_t z_block_offset = 0x0800; +const static size_t z_block_len = 0x0800; // 2kb + +class z_flashdata_t { +public: + uint32_t name; // simple 4 letters name. Currently 'skey', 'crt ', 'crt1', 'crt2' + uint16_t len; // len of object + uint16_t reserved; // align on 4 bytes boundary +}; + +const static uint32_t ZIGB_NAME = 0x3167697A; // 'zig1' little endian +const static size_t Z_MAX_FLASH = z_block_len - sizeof(z_flashdata_t); // 2040 + +// encoding for the most commonly 32 clusters, used for binary encoding +const uint16_t Z_ClusterNumber[] PROGMEM = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0100, 0x0101, 0x0102, + 0x0201, 0x0202, 0x0203, 0x0204, + 0x0300, 0x0301, + 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, + 0x0500, 0x0501, 0x0502, + 0x0700, 0x0701, 0x0702, + 0x0B00, 0x0B01, 0x0B02, 0x0B03, 0x0B04, 0x0B05, + 0x1000, + 0xFC0F, +}; + +// convert a 1 byte cluster code to the actual cluster number +uint16_t fromClusterCode(uint8_t c) { + if (c >= sizeof(Z_ClusterNumber)/sizeof(Z_ClusterNumber[0])) { + return 0xFFFF; // invalid + } + return pgm_read_word(&Z_ClusterNumber[c]); +} + +// convert a cluster number to 1 byte, or 0xFF if not in table +uint8_t toClusterCode(uint16_t c) { + for (uint32_t i = 0; i < sizeof(Z_ClusterNumber)/sizeof(Z_ClusterNumber[0]); i++) { + if (c == pgm_read_word(&Z_ClusterNumber[i])) { + return i; + } + } + return 0xFF; // not found +} + +class SBuffer hibernateDevice(const struct Z_Device &device) { + SBuffer buf(128); + + buf.add8(0x00); // overall length, will be updated later + buf.add16(device.shortaddr); + buf.add64(device.longaddr); + uint32_t endpoints = device.endpoints.size(); + if (endpoints > 254) { endpoints = 254; } + buf.add8(endpoints); + // iterate on endpoints + for (std::vector::const_iterator ite = device.endpoints.begin() ; ite != device.endpoints.end(); ++ite) { + uint32_t ep_profile = *ite; + uint8_t endpoint = (ep_profile >> 16) & 0xFF; + uint16_t profileId = ep_profile & 0xFFFF; + + buf.add8(endpoint); + buf.add16(profileId); + for (std::vector::const_iterator itc = device.clusters_in.begin() ; itc != device.clusters_in.end(); ++itc) { + uint16_t cluster = *itc & 0xFFFF; + uint8_t c_endpoint = (*itc >> 16) & 0xFF; + + if (endpoint == c_endpoint) { + uint8_t clusterCode = toClusterCode(cluster); + if (0xFF != clusterCode) { buf.add8(clusterCode); } + } + } + buf.add8(0xFF); // end of endpoint marker + + for (std::vector::const_iterator itc = device.clusters_out.begin() ; itc != device.clusters_out.end(); ++itc) { + uint16_t cluster = *itc & 0xFFFF; + uint8_t c_endpoint = (*itc >> 16) & 0xFF; + + if (endpoint == c_endpoint) { + uint8_t clusterCode = toClusterCode(cluster); + if (0xFF != clusterCode) { buf.add8(clusterCode); } + } + } + buf.add8(0xFF); // end of endpoint marker + } + + // ModelID + size_t model_len = device.modelId.length(); + if (model_len > 32) { model_len = 32; } // max 32 chars + buf.addBuffer(device.modelId.c_str(), model_len); + buf.add8(0x00); // end of string marker + + // ManufID + size_t manuf_len = device.manufacturerId.length(); + if (manuf_len > 32) {manuf_len = 32; } // max 32 chars + buf.addBuffer(device.manufacturerId.c_str(), manuf_len); + buf.add8(0x00); // end of string marker + + // FriendlyName + size_t frname_len = device.friendlyName.length(); + if (frname_len > 32) {frname_len = 32; } // max 32 chars + buf.addBuffer(device.friendlyName.c_str(), frname_len); + buf.add8(0x00); // end of string marker + + // update overall length + buf.set8(0, buf.len()); + + return buf; +} + +class SBuffer hibernateDevices(void) { + SBuffer buf(2048); + + size_t devices_size = zigbee_devices.devicesSize(); + if (devices_size > 32) { devices_size = 32; } // arbitrarily limit to 32 devices, for now + buf.add8(devices_size); // number of devices + + for (uint32_t i = 0; i < devices_size; i++) { + const Z_Device & device = zigbee_devices.devicesAt(i); + const SBuffer buf_device = hibernateDevice(device); + buf.addBuffer(buf_device); + } + + size_t buf_len = buf.len(); + if (buf_len > 2040) { + AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Devices list too big to fit in Flash (%d)"), buf_len); + } + + // Log + char *hex_char = (char*) malloc((buf_len * 2) + 2); + if (hex_char) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "ZbFlashStore %s"), + ToHex_P(buf.getBuffer(), buf_len, hex_char, (buf_len * 2) + 2)); + free(hex_char); + } + + return buf; +} + +void hidrateDevices(const SBuffer &buf) { + uint32_t buf_len = buf.len(); + if (buf_len <= 10) { return; } + + uint32_t k = 0; + uint32_t num_devices = buf.get8(k++); + + for (uint32_t i = 0; (i < num_devices) && (k < buf_len); i++) { + uint32_t dev_record_len = buf.get8(k); + + SBuffer buf_d = buf.subBuffer(k, dev_record_len); + + uint32_t d = 1; // index in device buffer + uint16_t shortaddr = buf_d.get16(d); d += 2; + uint64_t longaddr = buf_d.get64(d); d += 8; + zigbee_devices.updateDevice(shortaddr, longaddr); // update device's addresses + + uint32_t endpoints = buf_d.get8(d++); + for (uint32_t j = 0; j < endpoints; j++) { + uint8_t ep = buf_d.get8(d++); + uint16_t ep_profile = buf_d.get16(d); d += 2; + zigbee_devices.addEndointProfile(shortaddr, ep, ep_profile); + + // in clusters + while (d < dev_record_len) { // safe guard against overflow + uint8_t ep_cluster = buf_d.get8(d++); + if (0xFF == ep_cluster) { break; } // end of block + zigbee_devices.addCluster(shortaddr, ep, fromClusterCode(ep_cluster), false); + } + // out clusters + while (d < dev_record_len) { // safe guard against overflow + uint8_t ep_cluster = buf_d.get8(d++); + if (0xFF == ep_cluster) { break; } // end of block + zigbee_devices.addCluster(shortaddr, ep, fromClusterCode(ep_cluster), true); + } + } + + // parse 3 strings + char empty[] = ""; + + // ManufID + uint32_t s_len = buf_d.strlen_s(d); + char *ptr = s_len ? buf_d.charptr(d) : empty; + zigbee_devices.setModelId(shortaddr, ptr); + d += s_len + 1; + + // ManufID + s_len = buf_d.strlen_s(d); + ptr = s_len ? buf_d.charptr(d) : empty; + zigbee_devices.setManufId(shortaddr, ptr); + d += s_len + 1; + + // FriendlyName + s_len = buf_d.strlen_s(d); + ptr = s_len ? buf_d.charptr(d) : empty; + zigbee_devices.setFriendlyName(shortaddr, ptr); + d += s_len + 1; + + // next iteration + k += dev_record_len; + } +} + +void loadZigbeeDevices(void) { + z_flashdata_t flashdata; + memcpy_P(&flashdata, z_dev_start, sizeof(z_flashdata_t)); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "Zigbee signature in Flash: %08X - %d"), flashdata.name, flashdata.len); + + // Check the signature + if ((flashdata.name == ZIGB_NAME) && (flashdata.len > 0)) { + uint16_t buf_len = flashdata.len; + // parse what seems to be a valid entry + SBuffer buf(buf_len); + buf.addBuffer(z_dev_start + sizeof(z_flashdata_t), buf_len); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee devices data in Flash (%d bytes)"), buf_len); + hidrateDevices(buf); + zigbee_devices.clean(); // don't write back to Flash what we just loaded + } else { + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "No zigbee devices data in Flash")); + } +} + +void saveZigbeeDevices(void) { + SBuffer buf = hibernateDevices(); + size_t buf_len = buf.len(); + if (buf_len > Z_MAX_FLASH) { + AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Buffer too big to fit in Flash (%d bytes)"), buf_len); + return; + } + + // first copy SPI buffer into ram + uint8_t *spi_buffer = (uint8_t*) malloc(z_spi_len); + if (!spi_buffer) { + AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Cannot allocate 4KB buffer")); + return; + } + // copy the flash into RAM to make local change, and write back the whole buffer + ESP.flashRead(z_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE); + + z_flashdata_t *flashdata = (z_flashdata_t*)(spi_buffer + z_block_offset); + flashdata->name = ZIGB_NAME; + flashdata->len = buf_len; + flashdata->reserved = 0; + + memcpy(spi_buffer + z_block_offset + sizeof(z_flashdata_t), buf.getBuffer(), buf_len); + + // buffer is now ready, write it back + if (ESP.flashEraseSector(z_spi_start_sector)) { + ESP.flashWrite(z_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE); + } + + free(spi_buffer); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data store in Flash (0x%08X - %d bytes)"), z_dev_start, buf_len); +} + +// Erase the flash area containing the ZigbeeData +void eraseZigbeeDevices(void) { + zigbee_devices.clean(); // avoid writing data to flash after erase + // first copy SPI buffer into ram + uint8_t *spi_buffer = (uint8_t*) malloc(z_spi_len); + if (!spi_buffer) { + AddLog_P2(LOG_LEVEL_ERROR, PSTR(D_LOG_ZIGBEE "Cannot allocate 4KB buffer")); + return; + } + // copy the flash into RAM to make local change, and write back the whole buffer + ESP.flashRead(z_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE); + + // Fill the Zigbee area with 0xFF + memset(spi_buffer + z_block_offset, 0xFF, z_block_len); + + // buffer is now ready, write it back + if (ESP.flashEraseSector(z_spi_start_sector)) { + ESP.flashWrite(z_spi_start_sector * SPI_FLASH_SEC_SIZE, (uint32_t*) spi_buffer, SPI_FLASH_SEC_SIZE); + } + + free(spi_buffer); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Zigbee Devices Data erased (0x%08X - %d bytes)"), z_dev_start, z_block_len); +} + +#endif // USE_ZIGBEE diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 58b055d2b..d97e5e7d4 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -39,10 +39,10 @@ class ZCLFrame { public: ZCLFrame(uint8_t frame_control, uint16_t manuf_code, uint8_t transact_seq, uint8_t cmd_id, - const char *buf, size_t buf_len, uint16_t clusterid = 0, uint16_t groupid = 0, - uint16_t srcaddr = 0, uint8_t srcendpoint = 0, uint8_t dstendpoint = 0, uint8_t wasbroadcast = 0, - uint8_t linkquality = 0, uint8_t securityuse = 0, uint8_t seqnumber = 0, - uint32_t timestamp = 0): + const char *buf, size_t buf_len, uint16_t clusterid, uint16_t groupid, + uint16_t srcaddr, uint8_t srcendpoint, uint8_t dstendpoint, uint8_t wasbroadcast, + uint8_t linkquality, uint8_t securityuse, uint8_t seqnumber, + uint32_t timestamp): _cmd_id(cmd_id), _manuf_code(manuf_code), _transact_seq(transact_seq), _payload(buf_len ? buf_len : 250), // allocate the data frame from source or preallocate big enough _cluster_id(clusterid), _group_id(groupid), @@ -58,7 +58,7 @@ public: void log(void) { char hex_char[_payload.len()*2+2]; ToHex_P((unsigned char*)_payload.getBuffer(), _payload.len(), hex_char, sizeof(hex_char)); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("{\"" D_JSON_ZIGBEEZCL_RECEIVED "\":{" + Response_P(PSTR("{\"" D_JSON_ZIGBEEZCL_RECEIVED "\":{" "\"groupid\":%d," "\"clusterid\":%d," "\"srcaddr\":\"0x%04X\"," "\"srcendpoint\":%d," "\"dstendpoint\":%d," "\"wasbroadcast\":%d," "\"" D_CMND_ZIGBEE_LINKQUALITY "\":%d," "\"securityuse\":%d," "\"seqnumber\":%d," @@ -71,12 +71,18 @@ public: _timestamp, _frame_control, _manuf_code, _transact_seq, _cmd_id, hex_char); + if (Settings.flag3.tuya_serial_mqtt_publish) { + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); + XdrvRulesProcess(); + } else { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); + } } static ZCLFrame parseRawFrame(const SBuffer &buf, uint8_t offset, uint8_t len, uint16_t clusterid, uint16_t groupid, - uint16_t srcaddr = 0, uint8_t srcendpoint = 0, uint8_t dstendpoint = 0, uint8_t wasbroadcast = 0, - uint8_t linkquality = 0, uint8_t securityuse = 0, uint8_t seqnumber = 0, - uint32_t timestamp = 0) { // parse a raw frame and build the ZCL frame object + uint16_t srcaddr, uint8_t srcendpoint, uint8_t dstendpoint, uint8_t wasbroadcast, + uint8_t linkquality, uint8_t securityuse, uint8_t seqnumber, + uint32_t timestamp) { // parse a raw frame and build the ZCL frame object uint32_t i = offset; ZCLHeaderFrameControl_t frame_control; uint16_t manuf_code = 0; @@ -92,7 +98,10 @@ public: cmd_id = buf.get8(i++); ZCLFrame zcl_frame(frame_control.d8, manuf_code, transact_seq, cmd_id, (const char *)(buf.buf() + i), len + offset - i, - clusterid, groupid); + clusterid, groupid, + srcaddr, srcendpoint, dstendpoint, wasbroadcast, + linkquality, securityuse, seqnumber, + timestamp); return zcl_frame; } @@ -356,7 +365,12 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer // TODO case 0x39: // float - i += 4; + { + uint32_t uint32_val = buf.get32(i); + float * float_val = (float*) &uint32_val; + i += 4; + json[attrid_str] = *float_val; + } break; case 0xE0: // ToD @@ -401,7 +415,12 @@ uint32_t parseSingleAttribute(JsonObject& json, char *attrid_str, class SBuffer i += 2; break; case 0x3A: // double precision - i += 8; + { + uint64_t uint64_val = buf.get64(i); + double * double_val = (double*) &uint64_val; + i += 8; + json[attrid_str] = *double_val; + } break; } @@ -473,7 +492,7 @@ void ZCLFrame::parseClusterSpecificCommand(JsonObject& json, uint8_t offset) { uint32_t len = _payload.len(); char attrid_str[12]; - snprintf_P(attrid_str, sizeof(attrid_str), PSTR("%04X!%02X"), _cmd_id, _cluster_id); + snprintf_P(attrid_str, sizeof(attrid_str), PSTR("%04X!%02X"), _cluster_id, _cmd_id); char hex_char[_payload.len()*2+2]; ToHex_P((unsigned char*)_payload.getBuffer(), _payload.len(), hex_char, sizeof(hex_char)); @@ -561,7 +580,7 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = { { 0x000C, 0x0041, "MaxPresentValue", &Z_Copy }, { 0x000C, 0x0045, "MinPresentValue", &Z_Copy }, { 0x000C, 0x0051, "OutOfService", &Z_Copy }, - { 0x000C, 0x0055, "PresentValue", &Z_Copy }, + { 0x000C, 0x0055, "AqaraRotate", &Z_Copy }, { 0x000C, 0x0057, "PriorityArray", &Z_Copy }, { 0x000C, 0x0067, "Reliability", &Z_Copy }, { 0x000C, 0x0068, "RelinquishDefault", &Z_Copy }, @@ -569,6 +588,7 @@ const Z_AttributeConverter Z_PostProcess[] PROGMEM = { { 0x000C, 0x006F, "StatusFlags", &Z_Copy }, { 0x000C, 0x0075, "EngineeringUnits", &Z_Copy }, { 0x000C, 0x0100, "ApplicationType", &Z_Copy }, + { 0x000C, 0xFF05, "Aqara_FF05", &Z_Copy }, // Binary Output cluster { 0x0010, 0x0004, "ActiveText", &Z_Copy }, { 0x0010, 0x001C, "Description", &Z_Copy }, @@ -830,10 +850,10 @@ int32_t Z_FloatDiv10(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObject& // Publish a message for `"Occupancy":0` when the timer expired int32_t Z_OccupancyCallback(uint16_t shortaddr, uint16_t cluster, uint16_t endpoint, uint32_t value) { - // send Occupancy:false message - Response_P(PSTR("{\"" D_CMND_ZIGBEE_RECEIVED "\":{\"0x%04X\":{\"" OCCUPANCY "\":0}}}"), shortaddr); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); - XdrvRulesProcess(); + DynamicJsonBuffer jsonBuffer; + JsonObject& json = jsonBuffer.createObject(); + json[F(OCCUPANCY)] = 0; + zigbee_devices.jsonPublishNow(shortaddr, json); } // Aqara Cube diff --git a/tasmota/xdrv_23_zigbee_6_commands.ino b/tasmota/xdrv_23_zigbee_6_commands.ino index 4c9b0672f..073ab8e4c 100644 --- a/tasmota/xdrv_23_zigbee_6_commands.ino +++ b/tasmota/xdrv_23_zigbee_6_commands.ino @@ -40,11 +40,11 @@ const Z_CommandConverter Z_Commands[] = { { "Color", "0300!07/xxxxyyyy0A00" }, // x, y (uint16) { "CT", "0300!0A/xxxx0A00" }, // Color Temperature Mireds (uint16) { "Shutter", "0102!xx" }, - { "ShutterOpen", "0102!00"}, - { "ShutterClose", "0102!01"}, - { "ShutterStop", "0102!02"}, - { "ShutterLift", "0102!05xx"}, // Lift percentage, 0%=open, 100%=closed - { "ShutterTilt", "0102!08xx"}, // Tilt percentage + { "ShutterOpen", "0102!00" }, + { "ShutterClose", "0102!01" }, + { "ShutterStop", "0102!02" }, + { "ShutterLift", "0102!05xx" }, // Lift percentage, 0%=open, 100%=closed + { "ShutterTilt", "0102!08xx" }, // Tilt percentage }; #define ZLE(x) ((x) & 0xFF), ((x) >> 8) // Little Endian diff --git a/tasmota/xdrv_23_zigbee_7_statemachine.ino b/tasmota/xdrv_23_zigbee_7_statemachine.ino index 520dbd232..5a3d78e85 100644 --- a/tasmota/xdrv_23_zigbee_7_statemachine.ino +++ b/tasmota/xdrv_23_zigbee_7_statemachine.ino @@ -32,7 +32,7 @@ const uint8_t ZIGBEE_STATUS_DEVICE_ANNOUNCE = 30; // Device announces its const uint8_t ZIGBEE_STATUS_NODE_DESC = 31; // Node descriptor const uint8_t ZIGBEE_STATUS_ACTIVE_EP = 32; // Endpoints descriptor const uint8_t ZIGBEE_STATUS_SIMPLE_DESC = 33; // Simple Descriptor (clusters) -const uint8_t ZIGBEE_STATUS_DEVICE_INDICATION = 34; // Device announces its address +const uint8_t ZIGBEE_STATUS_DEVICE_INDICATION = 34; // Device announces its address const uint8_t ZIGBEE_STATUS_CC_VERSION = 50; // Status: CC2530 ZNP Version const uint8_t ZIGBEE_STATUS_CC_INFO = 51; // Status: CC2530 Device Configuration const uint8_t ZIGBEE_STATUS_UNSUPPORTED_VERSION = 98; // Unsupported ZNP version @@ -354,7 +354,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { //ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "starting zigbee coordinator") ZI_SEND(ZBS_STARTUPFROMAPP) // start coordinator ZI_WAIT_RECV(2000, ZBR_STARTUPFROMAPP) // wait for sync ack of command - ZI_WAIT_UNTIL(5000, AREQ_STARTUPFROMAPP) // wait for async message that coordinator started + ZI_WAIT_UNTIL(10000, AREQ_STARTUPFROMAPP) // wait for async message that coordinator started ZI_SEND(ZBS_GETDEVICEINFO) // GetDeviceInfo ZI_WAIT_RECV_FUNC(2000, ZBR_GETDEVICEINFO, &Z_ReceiveDeviceInfo) //ZI_WAIT_RECV(2000, ZBR_GETDEVICEINFO) // memorize info @@ -386,6 +386,7 @@ ZI_SEND(ZBS_STARTUPFROMAPP) // start coordinator ZI_MQTT_STATE(ZIGBEE_STATUS_OK, "Started") ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "Zigbee started") ZI_CALL(&Z_State_Ready, 1) // Now accept incoming messages + ZI_CALL(&Z_Load_Devices, 0) ZI_LABEL(ZIGBEE_LABEL_MAIN_LOOP) ZI_WAIT_FOREVER() ZI_GOTO(ZIGBEE_LABEL_READY) @@ -544,7 +545,7 @@ void ZigbeeStateMachine_Run(void) { } // load current instruction details - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Executing instruction pc=%d"), zigbee.pc); + //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Executing instruction pc=%d"), zigbee.pc); const Zigbee_Instruction *cur_instr_line = &zb_prog[zigbee.pc]; cur_instr = pgm_read_byte(&cur_instr_line->i.i); cur_d8 = pgm_read_byte(&cur_instr_line->i.d8); diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index d396b3fc4..668f85471 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -33,6 +33,9 @@ int32_t Z_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) { uint8_t device_state = buf.get8(14); uint8_t device_associated = buf.get8(15); + // keep track of the local IEEE address + localIEEEAddr = long_adr; + char hex[20]; Uint64toHex(long_adr, hex, 64); Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" @@ -403,7 +406,7 @@ int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t cluster, uint16_t endpo // Post-provess for Aqara Presence Senson Z_AqaraOccupancy(shortaddr, cluster, endpoint, json); - zigbee_devices.jsonPublish(shortaddr); + zigbee_devices.jsonPublishFlush(shortaddr); return 1; } @@ -432,9 +435,7 @@ int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) { snprintf_P(shortaddr, sizeof(shortaddr), PSTR("0x%04X"), srcaddr); DynamicJsonBuffer jsonBuffer; - JsonObject& json_root = jsonBuffer.createObject(); - JsonObject& json1 = json_root.createNestedObject(F(D_CMND_ZIGBEE_RECEIVED)); - JsonObject& json = json1.createNestedObject(shortaddr); + JsonObject& json = jsonBuffer.createObject(); if ( (!zcl_received.isClusterSpecificCommand()) && (ZCL_REPORT_ATTRIBUTES == zcl_received.getCmdId())) { zcl_received.parseRawAttributes(json); @@ -446,8 +447,8 @@ int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) { } String msg(""); msg.reserve(100); - json_root.printTo(msg); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZigbeeZCLRawReceived: %s"), msg.c_str()); + json.printTo(msg); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZCL_RAW_RECEIVED ": {\"0x%04X\":%s}"), srcaddr, msg.c_str()); zcl_received.postProcessAttributes(srcaddr, json); // Add linkquality @@ -457,18 +458,14 @@ int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) { // Prepare for publish if (zigbee_devices.jsonIsConflict(srcaddr, json)) { // there is conflicting values, force a publish of the previous message now and don't coalesce - zigbee_devices.jsonPublish(srcaddr); + zigbee_devices.jsonPublishFlush(srcaddr); } else { zigbee_devices.jsonAppend(srcaddr, json); zigbee_devices.setTimer(srcaddr, USE_ZIGBEE_COALESCE_ATTR_TIMER, clusterid, srcendpoint, 0, &Z_PublishAttributes); } } else { // Publish immediately - msg = ""; - json_root.printTo(msg); - Response_P(PSTR("%s"), msg.c_str()); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); - XdrvRulesProcess(); + zigbee_devices.jsonPublishNow(srcaddr, json); } return -1; } @@ -511,6 +508,12 @@ int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) { } } +int32_t Z_Load_Devices(uint8_t value) { + // try to hidrate from known devices + loadZigbeeDevices(); + return 0; // continue +} + int32_t Z_State_Ready(uint8_t value) { zigbee.init_phase = false; // initialization phase complete return 0; // continue diff --git a/tasmota/xdrv_23_zigbee_9_impl.ino b/tasmota/xdrv_23_zigbee_9_impl.ino index 70c5659ca..6ea08c4ac 100644 --- a/tasmota/xdrv_23_zigbee_9_impl.ino +++ b/tasmota/xdrv_23_zigbee_9_impl.ino @@ -28,16 +28,24 @@ const uint8_t ZIGBEE_SOF_ALT = 0xFF; #include TasmotaSerial *ZigbeeSerial = nullptr; -const char kZigbeeCommands[] PROGMEM = "|" + +const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEE_PERMITJOIN "|" D_CMND_ZIGBEE_STATUS "|" D_CMND_ZIGBEE_RESET "|" D_CMND_ZIGBEE_SEND "|" - D_CMND_ZIGBEE_PROBE "|" D_CMND_ZIGBEE_READ "|" D_CMND_ZIGBEEZNPRECEIVE - ; + D_CMND_ZIGBEE_PROBE "|" D_CMND_ZIGBEE_READ "|" D_CMND_ZIGBEEZNPRECEIVE "|" + D_CMND_ZIGBEE_FORGET "|" D_CMND_ZIGBEE_SAVE "|" D_CMND_ZIGBEE_NAME "|" D_CMND_ZIGBEE_BIND ; + +const char kZigbeeCommands[] PROGMEM = D_PRFX_ZIGBEE "|" // legacy prefix -- deprecated + D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEE_PERMITJOIN "|" + D_CMND_ZIGBEE_STATUS "|" D_CMND_ZIGBEE_RESET "|" D_CMND_ZIGBEE_SEND "|" + D_CMND_ZIGBEE_PROBE "|" D_CMND_ZIGBEE_READ "|" D_CMND_ZIGBEEZNPRECEIVE "|" + D_CMND_ZIGBEE_FORGET "|" D_CMND_ZIGBEE_SAVE "|" D_CMND_ZIGBEE_NAME "|" D_CMND_ZIGBEE_BIND ; void (* const ZigbeeCommand[])(void) PROGMEM = { - &CmndZigbeeZNPSend, &CmndZigbeePermitJoin, - &CmndZigbeeStatus, &CmndZigbeeReset, &CmndZigbeeSend, - &CmndZigbeeProbe, &CmndZigbeeRead, &CmndZigbeeZNPReceive + &CmndZbZNPSend, &CmndZbPermitJoin, + &CmndZbStatus, &CmndZbReset, &CmndZbSend, + &CmndZbProbe, &CmndZbRead, &CmndZbZNPReceive, + &CmndZbForget, &CmndZbSave, &CmndZbName, &CmndZbBind }; int32_t ZigbeeProcessInput(class SBuffer &buf) { @@ -62,7 +70,7 @@ int32_t ZigbeeProcessInput(class SBuffer &buf) { } } - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "ZigbeeProcessInput: recv_prefix_match = %d, recv_filter_match = %d"), recv_prefix_match, recv_filter_match); + //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "ZbProcessInput: recv_prefix_match = %d, recv_filter_match = %d"), recv_prefix_match, recv_filter_match); } // if there is a recv_callback, call it now @@ -101,7 +109,7 @@ int32_t ZigbeeProcessInput(class SBuffer &buf) { res = (*zigbee.recv_unexpected)(res, buf); } } - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "ZigbeeProcessInput: res = %d"), res); + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "ZbProcessInput: res = %d"), res); // change state accordingly if (0 == res) { @@ -134,7 +142,7 @@ void ZigbeeInput(void) while (ZigbeeSerial->available()) { yield(); uint8_t zigbee_in_byte = ZigbeeSerial->read(); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZigbeeInput byte=%d len=%d"), zigbee_in_byte, zigbee_buffer->len()); + //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZbInput byte=%d len=%d"), zigbee_in_byte, zigbee_buffer->len()); if (0 == zigbee_buffer->len()) { // make sure all variables are correctly initialized zigbee_frame_len = 5; @@ -143,14 +151,14 @@ void ZigbeeInput(void) // in this case the first bit (lsb) is missed and Tasmota receives 0xFF instead of 0xFE // We forgive this mistake, and next bytes are automatically resynchronized if (ZIGBEE_SOF_ALT == zigbee_in_byte) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("ZigbeeInput forgiven first byte %02X (only for statistics)"), zigbee_in_byte); + AddLog_P2(LOG_LEVEL_INFO, PSTR("ZbInput forgiven first byte %02X (only for statistics)"), zigbee_in_byte); zigbee_in_byte = ZIGBEE_SOF; } } if ((0 == zigbee_buffer->len()) && (ZIGBEE_SOF != zigbee_in_byte)) { // waiting for SOF (Start Of Frame) byte, discard anything else - AddLog_P2(LOG_LEVEL_INFO, PSTR("ZigbeeInput discarding byte %02X"), zigbee_in_byte); + AddLog_P2(LOG_LEVEL_INFO, PSTR("ZbInput discarding byte %02X"), zigbee_in_byte); continue; // discard } @@ -194,9 +202,13 @@ void ZigbeeInput(void) SBuffer znp_buffer = zigbee_buffer->subBuffer(2, zigbee_frame_len - 3); // remove SOF, LEN and FCS ToHex_P((unsigned char*)znp_buffer.getBuffer(), znp_buffer.len(), hex_char, sizeof(hex_char)); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZNPRECEIVED " %s"), - hex_char); - + Response_P(PSTR("{\"" D_JSON_ZIGBEEZNPRECEIVED "\":\"%s\"}"), hex_char); + if (Settings.flag3.tuya_serial_mqtt_publish) { + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); + XdrvRulesProcess(); + } else { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); + } // now process the message ZigbeeProcessInput(znp_buffer); } @@ -210,7 +222,7 @@ void ZigbeeInit(void) { zigbee.active = false; if ((pin[GPIO_ZIGBEE_RX] < 99) && (pin[GPIO_ZIGBEE_TX] < 99)) { - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("Zigbee: GPIOs Rx:%d Tx:%d"), pin[GPIO_ZIGBEE_RX], pin[GPIO_ZIGBEE_TX]); + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "GPIOs Rx:%d Tx:%d"), pin[GPIO_ZIGBEE_RX], pin[GPIO_ZIGBEE_TX]); // if seriallog_level is 0, we allow GPIO 13/15 to switch to Hardware Serial ZigbeeSerial = new TasmotaSerial(pin[GPIO_ZIGBEE_RX], pin[GPIO_ZIGBEE_TX], seriallog_level ? 1 : 2, 0, 256); // set a receive buffer of 256 bytes ZigbeeSerial->begin(115200); @@ -249,11 +261,12 @@ const unsigned char ZIGBEE_FACTORY_RESET[] PROGMEM = { Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 /* len */, 0x01 /* STARTOPT_CLEAR_CONFIG */}; //"2605030101"; // Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 len, 0x01 STARTOPT_CLEAR_CONFIG // Do a factory reset of the CC2530 -void CmndZigbeeReset(void) { +void CmndZbReset(void) { if (ZigbeeSerial) { switch (XdrvMailbox.payload) { case 1: ZigbeeZNPSend(ZIGBEE_FACTORY_RESET, sizeof(ZIGBEE_FACTORY_RESET)); + eraseZigbeeDevices(); restart_flag = 2; ResponseCmndChar(D_JSON_ZIGBEE_CC2530 " " D_JSON_RESET_AND_RESTARTING); break; @@ -263,14 +276,7 @@ void CmndZigbeeReset(void) { } } -void CmndZigbeeStatus(void) { - if (ZigbeeSerial) { - String dump = zigbee_devices.dump(XdrvMailbox.index, XdrvMailbox.payload); - Response_P(PSTR("{\"%s%d\":%s}"), XdrvMailbox.command, XdrvMailbox.index, dump.c_str()); - } -} - -void CmndZigbeeZNPSendOrReceive(bool send) +void CmndZbZNPSendOrReceive(bool send) { if (ZigbeeSerial && (XdrvMailbox.data_len > 0)) { uint8_t code; @@ -298,14 +304,14 @@ void CmndZigbeeZNPSendOrReceive(bool send) } // For debug purposes only, simulates a message received -void CmndZigbeeZNPReceive(void) +void CmndZbZNPReceive(void) { - CmndZigbeeZNPSendOrReceive(false); + CmndZbZNPSendOrReceive(false); } -void CmndZigbeeZNPSend(void) +void CmndZbZNPSend(void) { - CmndZigbeeZNPSendOrReceive(true); + CmndZbZNPSendOrReceive(true); } void ZigbeeZNPSend(const uint8_t *msg, size_t len) { @@ -320,17 +326,17 @@ void ZigbeeZNPSend(const uint8_t *msg, size_t len) { uint8_t fcs = data_len; ZigbeeSerial->write(ZIGBEE_SOF); // 0xFE - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend SOF %02X"), ZIGBEE_SOF); + //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend SOF %02X"), ZIGBEE_SOF); ZigbeeSerial->write(data_len); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend LEN %02X"), data_len); + //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend LEN %02X"), data_len); for (uint32_t i = 0; i < len; i++) { uint8_t b = pgm_read_byte(msg + i); ZigbeeSerial->write(b); fcs ^= b; - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend byt %02X"), b); + //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend byt %02X"), b); } ZigbeeSerial->write(fcs); // finally send fcs checksum byte - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend FCS %02X"), fcs); + //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend FCS %02X"), fcs); } // Now send a MQTT message to report the sent message char hex_char[(len * 2) + 2]; @@ -421,13 +427,13 @@ void zigbeeZCLSendStr(uint16_t dstAddr, uint8_t endpoint, const char *data) { if (0 == endpoint) { // endpoint is not specified, let's try to find it from shortAddr endpoint = zigbee_devices.findClusterEndpointIn(dstAddr, cluster); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZigbeeSend: guessing endpoint 0x%02X"), endpoint); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: guessing endpoint 0x%02X"), endpoint); } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZigbeeSend: dstAddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %s"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: dstAddr 0x%04X, cluster 0x%04X, endpoint 0x%02X, cmd 0x%02X, data %s"), dstAddr, cluster, endpoint, cmd, data); if (0 == endpoint) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("ZigbeeSend: unspecified endpoint")); + AddLog_P2(LOG_LEVEL_INFO, PSTR("ZbSend: unspecified endpoint")); return; } @@ -440,7 +446,7 @@ void zigbeeZCLSendStr(uint16_t dstAddr, uint8_t endpoint, const char *data) { ResponseCmndDone(); } -void CmndZigbeeSend(void) { +void CmndZbSend(void) { // ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":1} } // ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":"3"} } // ZigbeeSend { "device":"0x1234", "endpoint":"0x03", "send":{"Power":"0xFF"} } @@ -463,11 +469,16 @@ void CmndZigbeeSend(void) { uint8_t endpoint = 0x00; // 0x00 is invalid for the dst endpoint String cmd_str = ""; // the actual low-level command, either specified or computed - const JsonVariant &val_device = getCaseInsensitive(json, PSTR("device")); - if (nullptr != &val_device) { device = strToUInt(val_device); } - const JsonVariant &val_endpoint = getCaseInsensitive(json, PSTR("endpoint")); + const JsonVariant &val_device = getCaseInsensitive(json, PSTR("Device")); + if (nullptr != &val_device) { + device = zigbee_devices.parseDeviceParam(val_device.as()); + if (0xFFFF == device) { ResponseCmndChar("Invalid parameter"); return; } + } + if ((nullptr == &val_device) || (0x000 == device)) { ResponseCmndChar("Unknown device"); return; } + + const JsonVariant &val_endpoint = getCaseInsensitive(json, PSTR("Endpoint")); if (nullptr != &val_endpoint) { endpoint = strToUInt(val_endpoint); } - const JsonVariant val_cmd = getCaseInsensitive(json, PSTR("Send")); + const JsonVariant &val_cmd = getCaseInsensitive(json, PSTR("Send")); if (nullptr != &val_cmd) { // probe the type of the argument // If JSON object, it's high level commands @@ -522,9 +533,9 @@ void CmndZigbeeSend(void) { } } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZigbeeSend: command_template = %s"), cmd_str.c_str()); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: command_template = %s"), cmd_str.c_str()); cmd_str = zigbeeCmdAddParams(cmd_str.c_str(), x, y, z); // fill in parameters - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZigbeeSend: command_final = %s"), cmd_str.c_str()); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbSend: command_final = %s"), cmd_str.c_str()); } else { // we have zero command, pass through until last error for missing command } @@ -535,7 +546,7 @@ void CmndZigbeeSend(void) { // we have an unsupported command type, just ignore it and fallback to missing command } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZigbeeCmd_actual: ZigbeeZCLSend {\"device\":\"0x%04X\",\"endpoint\":%d,\"send\":\"%s\"}"), + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZbCmd_actual: ZigbeeZCLSend {\"device\":\"0x%04X\",\"endpoint\":%d,\"send\":\"%s\"}"), device, endpoint, cmd_str.c_str()); zigbeeZCLSendStr(device, endpoint, cmd_str.c_str()); } else { @@ -545,25 +556,129 @@ void CmndZigbeeSend(void) { } -// Probe a specific device to get its endpoints and supported clusters -void CmndZigbeeProbe(void) { - if (zigbee.init_phase) { ResponseCmndChar(D_ZIGBEE_NOT_STARTED); return; } - char dataBufUc[XdrvMailbox.data_len]; - UpperCase(dataBufUc, XdrvMailbox.data); - RemoveSpace(dataBufUc); - if (strlen(dataBufUc) < 3) { ResponseCmndChar("Invalid destination"); return; } +ZBM(ZBS_BIND_REQ, Z_SREQ | Z_ZDO, ZDO_BIND_REQ, + 0,0, // dstAddr - 16 bits, device to send the bind to + 0,0,0,0,0,0,0,0, // srcAddr - 64 bits, IEEE binding source + 0x00, // source endpoint + 0x00, 0x00, // cluster + 0x03, // DstAddrMode - 0x03 = ADDRESS_64_BIT + 0,0,0,0,0,0,0,0, // dstAddr - 64 bits, IEEE binding destination, i.e. coordinator + 0x01 // dstEndpoint - 0x01 for coordinator +) - // TODO, for now ignore friendly names - uint16_t shortaddr = strtoull(dataBufUc, nullptr, 0); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CmndZigbeeScan: short addr 0x%04X"), shortaddr); +void CmndZbBind(void) { + // ZbBind { "device":"0x1234", "endpoint":1, "cluster":6 } + + // local endpoint is always 1, IEEE addresses are calculated + if (zigbee.init_phase) { ResponseCmndChar(D_ZIGBEE_NOT_STARTED); return; } + DynamicJsonBuffer jsonBuf; + JsonObject &json = jsonBuf.parseObject(XdrvMailbox.data); + if (!json.success()) { ResponseCmndChar(D_JSON_INVALID_JSON); return; } + + // params + // static char delim[] = ", "; // delimiters for parameters + uint16_t device = 0xFFFF; // 0xFFFF is broadcast, so considered valid + uint8_t endpoint = 0x00; // 0x00 is invalid for the dst endpoint + uint16_t cluster = 0; // 0xFFFF is invalid + uint32_t group = 0xFFFFFFFF; // 16 bits values, otherwise 0xFFFFFFFF is unspecified + + const JsonVariant &val_device = getCaseInsensitive(json, PSTR("Device")); + if (nullptr != &val_device) { + device = zigbee_devices.parseDeviceParam(val_device.as()); + if (0xFFFF == device) { ResponseCmndChar("Invalid parameter"); return; } + } + if ((nullptr == &val_device) || (0x000 == device)) { ResponseCmndChar("Unknown device"); return; } + + const JsonVariant &val_endpoint = getCaseInsensitive(json, PSTR("Endpoint")); + if (nullptr != &val_endpoint) { endpoint = strToUInt(val_endpoint); } + const JsonVariant &val_cluster = getCaseInsensitive(json, PSTR("Cluster")); + if (nullptr != &val_cluster) { cluster = strToUInt(val_cluster); } + + // TODO compute endpoint from cluster + + SBuffer buf(sizeof(ZBS_BIND_REQ)); + buf.add8(Z_SREQ | Z_ZDO); + buf.add8(ZDO_BIND_REQ); + buf.add16(device); + buf.add64(zigbee_devices.getDeviceLongAddr(device)); + buf.add8(endpoint); + buf.add16(cluster); + buf.add8(0x03); // DstAddrMode - 0x03 = ADDRESS_64_BIT + buf.add64(localIEEEAddr); // coordinatore IEEE address + buf.add8(0x01); // local endpoint = 1 + + ZigbeeZNPSend(buf.getBuffer(), buf.len()); + + ResponseCmndDone(); +} + +// Probe a specific device to get its endpoints and supported clusters +void CmndZbProbe(void) { + if (zigbee.init_phase) { ResponseCmndChar(D_ZIGBEE_NOT_STARTED); return; } + uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data); + if (0x0000 == shortaddr) { ResponseCmndChar("Unknown device"); return; } + if (0xFFFF == shortaddr) { ResponseCmndChar("Invalid parameter"); return; } // everything is good, we can send the command Z_SendActiveEpReq(shortaddr); ResponseCmndDone(); } +// Specify, read or erase a Friendly Name +void CmndZbName(void) { + // Syntax is: + // ZigbeeName , - assign a friendly name + // ZigbeeName - display the current friendly name + // ZigbeeName , - remove friendly name + // + // Where can be: short_addr, long_addr, device_index, friendly_name + + if (zigbee.init_phase) { ResponseCmndChar(D_ZIGBEE_NOT_STARTED); return; } + + // check if parameters contain a comma ',' + char *p; + char *str = strtok_r(XdrvMailbox.data, ", ", &p); + + // parse first part, + uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data, true); // in case of short_addr, it must be already registered + if (0x0000 == shortaddr) { ResponseCmndChar("Unknown device"); return; } + if (0xFFFF == shortaddr) { ResponseCmndChar("Invalid parameter"); return; } + + if (p == nullptr) { + const String * friendlyName = zigbee_devices.getFriendlyName(shortaddr); + Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), shortaddr, friendlyName ? friendlyName->c_str() : ""); + } else { + zigbee_devices.setFriendlyName(shortaddr, p); + Response_P(PSTR("{\"0x%04X\":{\"" D_JSON_ZIGBEE_NAME "\":\"%s\"}}"), shortaddr, p); + } +} + +// Remove an old Zigbee device from the list of known devices, use ZigbeeStatus to know all registered devices +void CmndZbForget(void) { + if (zigbee.init_phase) { ResponseCmndChar(D_ZIGBEE_NOT_STARTED); return; } + uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data); + if (0x0000 == shortaddr) { ResponseCmndChar("Unknown device"); return; } + if (0xFFFF == shortaddr) { ResponseCmndChar("Invalid parameter"); return; } + + // everything is good, we can send the command + if (zigbee_devices.removeDevice(shortaddr)) { + ResponseCmndDone(); + } else { + ResponseCmndChar("Unknown device"); + } +} + +// Save Zigbee information to flash +void CmndZbSave(void) { + if (zigbee.init_phase) { ResponseCmndChar(D_ZIGBEE_NOT_STARTED); return; } + + saveZigbeeDevices(); + + ResponseCmndDone(); +} + // Send an attribute read command to a device, specifying cluster and list of attributes -void CmndZigbeeRead(void) { +void CmndZbRead(void) { // ZigbeeRead {"Device":"0xF289","Cluster":0,"Endpoint":3,"Attr":5} // ZigbeeRead {"Device":"0xF289","Cluster":"0x0000","Endpoint":"0x0003","Attr":"0x0005"} // ZigbeeRead {"Device":"0xF289","Cluster":0,"Endpoint":3,"Attr":[5,6,7,4]} @@ -579,10 +694,14 @@ void CmndZigbeeRead(void) { size_t attrs_len = 0; uint8_t* attrs = nullptr; // empty string is valid - const JsonVariant &val_device = getCaseInsensitive(json, PSTR("Device")); - if (nullptr != &val_device) { device = strToUInt(val_device); } - const JsonVariant val_cluster = getCaseInsensitive(json, PSTR("Cluster")); + if (nullptr != &val_device) { + device = zigbee_devices.parseDeviceParam(val_device.as()); + if (0xFFFF == device) { ResponseCmndChar("Invalid parameter"); return; } + } + if ((nullptr == &val_device) || (0x000 == device)) { ResponseCmndChar("Unknown device"); return; } + + const JsonVariant &val_cluster = getCaseInsensitive(json, PSTR("Cluster")); if (nullptr != &val_cluster) { cluster = strToUInt(val_cluster); } const JsonVariant &val_endpoint = getCaseInsensitive(json, PSTR("Endpoint")); if (nullptr != &val_endpoint) { endpoint = strToUInt(val_endpoint); } @@ -609,14 +728,18 @@ void CmndZigbeeRead(void) { } } - ZigbeeZCLSend(device, cluster, endpoint, ZCL_READ_ATTRIBUTES, false, attrs, attrs_len, false /* we do want a response */); + if ((0 != endpoint) && (attrs_len > 0)) { + ZigbeeZCLSend(device, cluster, endpoint, ZCL_READ_ATTRIBUTES, false, attrs, attrs_len, false /* we do want a response */); + ResponseCmndDone(); + } else { + ResponseCmndChar("Missing parameters"); + } if (attrs) { delete[] attrs; } - ResponseCmndDone(); } // Allow or Deny pairing of new Zigbee devices -void CmndZigbeePermitJoin(void) +void CmndZbPermitJoin(void) { if (zigbee.init_phase) { ResponseCmndChar(D_ZIGBEE_NOT_STARTED); return; } uint32_t payload = XdrvMailbox.payload; @@ -633,6 +756,20 @@ void CmndZigbeePermitJoin(void) ResponseCmndDone(); } +void CmndZbStatus(void) { + if (ZigbeeSerial) { + if (zigbee.init_phase) { ResponseCmndChar(D_ZIGBEE_NOT_STARTED); return; } + uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data); + if (0xFFFF == shortaddr) { ResponseCmndChar("Invalid parameter"); return; } + if (XdrvMailbox.payload > 0) { + if (0x0000 == shortaddr) { ResponseCmndChar("Unknown device"); return; } + } + + String dump = zigbee_devices.dump(XdrvMailbox.index, shortaddr); + Response_P(PSTR("{\"%s%d\":%s}"), XdrvMailbox.command, XdrvMailbox.index, dump.c_str()); + } +} + /*********************************************************************************************\ * Interface \*********************************************************************************************/ @@ -659,7 +796,8 @@ bool Xdrv23(uint8_t function) ZigbeeInit(); break; case FUNC_COMMAND: - result = DecodeCommand(kZigbeeCommands, ZigbeeCommand); + result = DecodeCommand(kZbCommands, ZigbeeCommand); + result = result || DecodeCommand(kZigbeeCommands, ZigbeeCommand); // deprecated break; } } diff --git a/tasmota/xdrv_24_buzzer.ino b/tasmota/xdrv_24_buzzer.ino index 9cfa7e111..5e582d7db 100644 --- a/tasmota/xdrv_24_buzzer.ino +++ b/tasmota/xdrv_24_buzzer.ino @@ -26,10 +26,12 @@ struct BUZZER { uint32_t tune = 0; + uint32_t tune_reload = 0; bool active = true; bool enable = false; uint8_t inverted = 0; // Buzzer inverted flag (1 = (0 = On, 1 = Off)) uint8_t count = 0; // Number of buzzes + uint8_t mode = 0; // Buzzer mode (0 = regular, 1 = infinite, 2 = follow LED) uint8_t set[2]; uint8_t duration; uint8_t state = 0; @@ -42,13 +44,15 @@ void BuzzerOff(void) DigitalWrite(GPIO_BUZZER, Buzzer.inverted); // Buzzer Off } -//void BuzzerBeep(uint32_t count = 1, uint32_t on = 1, uint32_t off = 1, uint32_t tune = 0); -void BuzzerBeep(uint32_t count, uint32_t on, uint32_t off, uint32_t tune) +//void BuzzerBeep(uint32_t count = 1, uint32_t on = 1, uint32_t off = 1, uint32_t tune = 0, uint32_t mode = 0); +void BuzzerBeep(uint32_t count, uint32_t on, uint32_t off, uint32_t tune, uint32_t mode) { Buzzer.set[0] = off; // off duration in 100 mSec steps Buzzer.set[1] = on; // on duration in 100 mSec steps Buzzer.duration = 1; // Start buzzer on first step - Buzzer.tune = 0; + Buzzer.tune_reload = 0; + Buzzer.mode = mode; + if (tune) { uint32_t tune1 = tune; uint32_t tune2 = tune; @@ -56,15 +60,14 @@ void BuzzerBeep(uint32_t count, uint32_t on, uint32_t off, uint32_t tune) if (!(tune2 & 0x80000000)) { tune2 <<= 1; // Skip leading silence } else { - Buzzer.tune <<= 1; // Add swapped tune - Buzzer.tune |= tune1 & 1; + Buzzer.tune_reload <<= 1; // Add swapped tune + Buzzer.tune_reload |= tune1 & 1; tune1 >>= 1; } } - Buzzer.count = 1; // Allow tune only once - } else { - Buzzer.count = count * 2; // Start buzzer + Buzzer.tune = Buzzer.tune_reload; } + Buzzer.count = count * 2; // Start buzzer AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BUZ: %d(%d),%d,%d,0x%08X(0x%08X)"), count, Buzzer.count, on, off, tune, Buzzer.tune); @@ -74,14 +77,23 @@ void BuzzerBeep(uint32_t count, uint32_t on, uint32_t off, uint32_t tune) } } -void BuzzerBeep(uint32_t count) { - BuzzerBeep(count, 1, 1, 0); +void BuzzerSetStateToLed(uint32_t state) +{ + if (Buzzer.enable && (2 == Buzzer.mode)) { + Buzzer.state = (state != 0); + DigitalWrite(GPIO_BUZZER, (Buzzer.inverted) ? !Buzzer.state : Buzzer.state); + } +} + +void BuzzerBeep(uint32_t count) +{ + BuzzerBeep(count, 1, 1, 0, 0); } void BuzzerEnabledBeep(uint32_t count, uint32_t duration) { if (Settings.flag3.buzzer_enable) { // SetOption67 - Enable buzzer when available - BuzzerBeep(count, duration, 1, 0); + BuzzerBeep(count, duration, 1, 0, 0); } } @@ -109,7 +121,7 @@ void BuzzerInit(void) void BuzzerEvery100mSec(void) { - if (Buzzer.enable) { + if (Buzzer.enable && (Buzzer.mode != 2)) { if (Buzzer.count) { if (Buzzer.duration) { Buzzer.duration--; @@ -118,8 +130,12 @@ void BuzzerEvery100mSec(void) Buzzer.state = Buzzer.tune & 1; Buzzer.tune >>= 1; } else { - Buzzer.count--; + Buzzer.tune = Buzzer.tune_reload; + Buzzer.count -= (Buzzer.tune_reload) ? 2 : 1; Buzzer.state = Buzzer.count & 1; + if (Buzzer.mode) { + Buzzer.count |= 2; + } } Buzzer.duration = Buzzer.set[Buzzer.state]; } @@ -151,21 +167,23 @@ void CmndBuzzer(void) // Buzzer 2 = Beep twice with duration 200mS and pause 100mS // Buzzer 2,3 = Beep twice with duration 300mS and pause 100mS // Buzzer 2,3,4 = Beep twice with duration 300mS and pause 400mS - // Buzzer 2,3,4,0xF54 = Beep a sequence once indicated by 0xF54 = 1111 0101 01 with duration 300mS and pause 400mS + // Buzzer 2,3,4,0xF54 = Beep a sequence twice indicated by 0xF54 = 1111 0101 01 with duration 300mS and pause 400mS + // Buzzer -1 = Beep infinite + // Buzzer -2 = Beep following link led if (XdrvMailbox.data_len > 0) { - if (XdrvMailbox.payload > 0) { - char *p; - uint32_t i = 0; + if (XdrvMailbox.payload != 0) { uint32_t parm[4] = { 0 }; - for (char *str = strtok_r(XdrvMailbox.data, ", ", &p); str && i < 4; str = strtok_r(nullptr, ", ", &p)) { - parm[i] = strtoul(str, nullptr, 0); - i++; + uint32_t mode = 0; + ParseParameters(4, parm); + if (XdrvMailbox.payload <= 0) { + parm[0] = 1; // Default Count + mode = -XdrvMailbox.payload; // 0, 1 or 2 } - for (uint32_t i = 0; i < 3; i++) { - if (parm[i] < 1) { parm[i] = 1; } // Default Count, On time, Off time + for (uint32_t i = 1; i < 3; i++) { + if (parm[i] < 1) { parm[i] = 1; } // Default On time, Off time } - BuzzerBeep(parm[0], parm[1], parm[2], parm[3]); + BuzzerBeep(parm[0], parm[1], parm[2], parm[3], mode); } else { BuzzerBeep(0); } @@ -202,4 +220,4 @@ bool Xdrv24(uint8_t function) return result; } -#endif // USE_BUZZER \ No newline at end of file +#endif // USE_BUZZER diff --git a/tasmota/xdrv_27_shutter.ino b/tasmota/xdrv_27_shutter.ino index ec272487b..c353a1dd4 100644 --- a/tasmota/xdrv_27_shutter.ino +++ b/tasmota/xdrv_27_shutter.ino @@ -34,21 +34,22 @@ uint16_t messwerte[5] = {30,50,70,90,100}; uint16_t last_execute_step; enum ShutterModes { SHT_OFF_OPEN__OFF_CLOSE, SHT_OFF_ON__OPEN_CLOSE, SHT_PULSE_OPEN__PULSE_CLOSE, SHT_OFF_ON__OPEN_CLOSE_STEPPER,}; -enum ShutterButtonStates { SHT_NOT_PRESSED, SHT_PRESSED_MULTI, SHT_PRESSED_HOLD, SHT_PRESSED_IMMEDIATE,}; +enum ShutterButtonStates { SHT_NOT_PRESSED, SHT_PRESSED_MULTI, SHT_PRESSED_HOLD, SHT_PRESSED_IMMEDIATE, SHT_PRESSED_MULTI_SIMULTANEOUS, SHT_PRESSED_HOLD_SIMULTANEOUS, SHT_PRESSED_EXT_HOLD_SIMULTANEOUS,}; const char kShutterCommands[] PROGMEM = D_PRFX_SHUTTER "|" D_CMND_SHUTTER_OPEN "|" D_CMND_SHUTTER_CLOSE "|" D_CMND_SHUTTER_STOP "|" D_CMND_SHUTTER_POSITION "|" D_CMND_SHUTTER_OPENTIME "|" D_CMND_SHUTTER_CLOSETIME "|" D_CMND_SHUTTER_RELAY "|" D_CMND_SHUTTER_SETHALFWAY "|" D_CMND_SHUTTER_SETCLOSE "|" D_CMND_SHUTTER_INVERT "|" D_CMND_SHUTTER_CLIBRATION "|" - D_CMND_SHUTTER_MOTORDELAY "|" D_CMND_SHUTTER_FREQUENCY "|" D_CMND_SHUTTER_BUTTON; + D_CMND_SHUTTER_MOTORDELAY "|" D_CMND_SHUTTER_FREQUENCY "|" D_CMND_SHUTTER_BUTTON "|" D_CMND_SHUTTER_LOCK "|" D_CMND_SHUTTER_ENABLEENDSTOPTIME; void (* const ShutterCommand[])(void) PROGMEM = { &CmndShutterOpen, &CmndShutterClose, &CmndShutterStop, &CmndShutterPosition, &CmndShutterOpenTime, &CmndShutterCloseTime, &CmndShutterRelay, &CmndShutterSetHalfway, &CmndShutterSetClose, &CmndShutterInvert, &CmndShutterCalibration , &CmndShutterMotorDelay, - &CmndShutterFrequency, &CmndShutterButton}; + &CmndShutterFrequency, &CmndShutterButton, &CmndShutterLock, &CmndShutterEnableEndStopTime}; -const char JSON_SHUTTER_POS[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Position\":%d,\"Direction\":%d}"; + const char JSON_SHUTTER_POS[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Position\":%d,\"Direction\":%d}"; + const char JSON_SHUTTER_BUTTON[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Button%d\":%d}"; #include @@ -97,8 +98,12 @@ void ShutterRtc50mS(void) } } +#define SHT_DIV_ROUND(__A, __B) (((__A) + (__B)/2) / (__B)) + int32_t ShutterPercentToRealPosition(uint32_t percent, uint32_t index) { + if (0 == percent) return 0; + if (100 == percent) return Shutter.open_max[index]; if (Settings.shutter_set50percent[index] != 50) { return (percent <= 5) ? Settings.shuttercoeff[2][index] * percent : Settings.shuttercoeff[1][index] * percent + Settings.shuttercoeff[0][index]; } else { @@ -108,21 +113,21 @@ int32_t ShutterPercentToRealPosition(uint32_t percent, uint32_t index) if (0 == Settings.shuttercoeff[j][index]) { AddLog_P2(LOG_LEVEL_ERROR, PSTR("SHT: RESET/INIT CALIBRATION MATRIX DIV 0")); for (uint32_t k = 0; k < 5; k++) { - Settings.shuttercoeff[k][index] = messwerte[k] * 1000 / messwerte[4]; + Settings.shuttercoeff[k][index] = SHT_DIV_ROUND(calibrate_pos[k+1] * 1000, calibrate_pos[5]); } } } for (uint32_t i = 0; i < 5; i++) { - if ((percent * 10) > Settings.shuttercoeff[i][index]) { - realpos = Shutter.open_max[index] * calibrate_pos[i+1] / 100; + if ((percent * 10) >= Settings.shuttercoeff[i][index]) { + realpos = SHT_DIV_ROUND(Shutter.open_max[index] * calibrate_pos[i+1], 100); //AddLog_P2(LOG_LEVEL_INFO, PSTR("Realposition TEMP1: %d, %% %d, coeff %d"), realpos, percent, Settings.shuttercoeff[i][index]); } else { if (0 == i) { - realpos = percent * Shutter.open_max[index] * calibrate_pos[i+1] / Settings.shuttercoeff[i][index] / 10; + realpos = SHT_DIV_ROUND(SHT_DIV_ROUND(percent * Shutter.open_max[index] * calibrate_pos[i+1], Settings.shuttercoeff[i][index]), 10); } else { //uint16_t addon = ( percent*10 - Settings.shuttercoeff[i-1][index] ) * Shutter_Open_Max[index] * (calibrate_pos[i+1] - calibrate_pos[i]) / (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index]) / 100; //AddLog_P2(LOG_LEVEL_INFO, PSTR("Realposition TEMP2: %d, %% %d, coeff %d"), addon, (calibrate_pos[i+1] - calibrate_pos[i]), (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index])); - realpos += ( percent*10 - Settings.shuttercoeff[i-1][index] ) * Shutter.open_max[index] * (calibrate_pos[i+1] - calibrate_pos[i]) / (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index]) / 100; + realpos += SHT_DIV_ROUND(SHT_DIV_ROUND((percent*10 - Settings.shuttercoeff[i-1][index] ) * Shutter.open_max[index] * (calibrate_pos[i+1] - calibrate_pos[i]), Settings.shuttercoeff[i][index] - Settings.shuttercoeff[i-1][index]), 100); } break; } @@ -133,23 +138,25 @@ int32_t ShutterPercentToRealPosition(uint32_t percent, uint32_t index) uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index) { + if (0 >= realpos) return 0; + if (Shutter.open_max[index] <= realpos) return 100; if (Settings.shutter_set50percent[index] != 50) { - return (Settings.shuttercoeff[2][index] * 5 > realpos) ? realpos / Settings.shuttercoeff[2][index] : (realpos-Settings.shuttercoeff[0][index]) / Settings.shuttercoeff[1][index]; + return (Settings.shuttercoeff[2][index] * 5 > realpos) ? SHT_DIV_ROUND(realpos, Settings.shuttercoeff[2][index]) : SHT_DIV_ROUND(realpos-Settings.shuttercoeff[0][index], Settings.shuttercoeff[1][index]); } else { uint16_t realpercent; for (uint32_t i = 0; i < 5; i++) { if (realpos >= Shutter.open_max[index] * calibrate_pos[i+1] / 100) { - realpercent = Settings.shuttercoeff[i][index] /10; + realpercent = SHT_DIV_ROUND(Settings.shuttercoeff[i][index], 10); //AddLog_P2(LOG_LEVEL_INFO, PSTR("Realpercent TEMP1: %d, %% %d, coeff %d"), realpercent, realpos, Shutter_Open_Max[index] * calibrate_pos[i+1] / 100); } else { if (0 == i) { - realpercent = ( realpos - (Shutter.open_max[index] * calibrate_pos[i] / 100) ) * 10 * Settings.shuttercoeff[i][index] / calibrate_pos[i+1] / Shutter.open_max[index]; + realpercent = SHT_DIV_ROUND(SHT_DIV_ROUND((realpos - SHT_DIV_ROUND(Shutter.open_max[index] * calibrate_pos[i], 100)) * 10 * Settings.shuttercoeff[i][index], calibrate_pos[i+1]), Shutter.open_max[index]); } else { //uint16_t addon = ( realpos - (Shutter_Open_Max[index] * calibrate_pos[i] / 100) ) * 10 * (Settings.shuttercoeff[i][index] - Settings.shuttercoeff[i-1][index]) / (calibrate_pos[i+1] - calibrate_pos[i])/ Shutter_Open_Max[index]; //uint16_t addon = ( percent*10 - Settings.shuttercoeff[i-1][index] ) * Shutter_Open_Max[index] * (calibrate_pos[i+1] - calibrate_pos[i]) / (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index]) / 100; //AddLog_P2(LOG_LEVEL_INFO, PSTR("Realpercent TEMP2: %d, delta %d, %% %d, coeff %d"), addon,( realpos - (Shutter_Open_Max[index] * calibrate_pos[i] / 100) ) , (calibrate_pos[i+1] - calibrate_pos[i])* Shutter_Open_Max[index]/100, (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index])); - realpercent += ( realpos - (Shutter.open_max[index] * calibrate_pos[i] / 100) ) * 10 * (Settings.shuttercoeff[i][index] - Settings.shuttercoeff[i-1][index]) / (calibrate_pos[i+1] - calibrate_pos[i]) / Shutter.open_max[index] ; + realpercent += SHT_DIV_ROUND(SHT_DIV_ROUND((realpos - SHT_DIV_ROUND(Shutter.open_max[index] * calibrate_pos[i], 100)) * 10 * (Settings.shuttercoeff[i][index] - Settings.shuttercoeff[i-1][index]), (calibrate_pos[i+1] - calibrate_pos[i])), Shutter.open_max[index]) ; } break; } @@ -226,23 +233,23 @@ void ShutterInit(void) Shutter.real_position[i] = ShutterPercentToRealPosition(Settings.shutter_position[i], i); //Shutter.real_position[i] = Settings.shutter_position[i] <= 5 ? Settings.shuttercoeff[2][i] * Settings.shutter_position[i] : Settings.shuttercoeff[1][i] * Settings.shutter_position[i] + Settings.shuttercoeff[0,i]; - Shutter.start_position[i] = Shutter.real_position[i]; + Shutter.start_position[i] = Shutter.target_position[i] = Shutter.real_position[i]; Shutter.motordelay[i] = Settings.shutter_motordelay[i]; char shutter_open_chr[10]; dtostrfd((float)Shutter.open_time[i] / 10 , 1, shutter_open_chr); char shutter_close_chr[10]; dtostrfd((float)Shutter.close_time[i] / 10, 1, shutter_close_chr); - AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Shutter %d (Relay:%d): Init. Pos: %d [%d %%], Open Vel.: 100 Close Vel.: %d , Max Way: %d, Opentime %s [s], Closetime %s [s], CoeffCalc: c0: %d, c1 %d, c2: %d, c3: %d, c4: %d, binmask %d, is inverted %d, shuttermode %d,motordelay %d"), + AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Shutter %d (Relay:%d): Init. Pos: %d [%d %%], Open Vel.: 100, Close Vel.: %d , Max Way: %d, Opentime %s [s], Closetime %s [s], CoeffCalc: c0: %d, c1 %d, c2: %d, c3: %d, c4: %d, binmask %d, is inverted %d, is locked %d, end stop time enabled %d, shuttermode %d, motordelay %d"), i+1, Settings.shutter_startrelay[i], Shutter.real_position[i], Settings.shutter_position[i], Shutter.close_velocity[i], Shutter.open_max[i], shutter_open_chr, shutter_close_chr, Settings.shuttercoeff[0][i], Settings.shuttercoeff[1][i], Settings.shuttercoeff[2][i], Settings.shuttercoeff[3][i], Settings.shuttercoeff[4][i], - Shutter.mask, Settings.shutter_invert[i], Shutter.mode, Shutter.motordelay[i]); + Shutter.mask, (Settings.shutter_options[i]&1) ? 1 : 0, (Settings.shutter_options[i]&2) ? 1 : 0, (Settings.shutter_options[i]&4) ? 1 : 0, Shutter.mode, Shutter.motordelay[i]); } else { // terminate loop at first INVALID shutter. break; } - + ShutterLimitRealAndTargetPositions(i); Settings.shutter_accuracy = 1; } } @@ -259,11 +266,11 @@ void ShutterReportPosition(bool always) ShutterLogPos(i); } if (i) { ResponseAppend_P(PSTR(",")); } - ResponseAppend_P(JSON_SHUTTER_POS, i+1, Settings.shutter_invert[i] ? 100-position : position, Shutter.direction[i]); + ResponseAppend_P(JSON_SHUTTER_POS, i+1, (Settings.shutter_options[i] & 1) ? 100-position : position, Shutter.direction[i]); } ResponseJsonEnd(); if (always || (1 == shutter_moving)) { - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_PRFX_SHUTTER)); + MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER)); } if (rules_flag.shutter_moving > shutter_moving) { rules_flag.shutter_moved = 1; @@ -274,6 +281,13 @@ void ShutterReportPosition(bool always) //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: rules_flag.shutter_moving: %d, moved %d"), rules_flag.shutter_moving, rules_flag.shutter_moved); } +void ShutterLimitRealAndTargetPositions(uint32_t i) { + if (Shutter.real_position[i]<0) Shutter.real_position[i] = 0; + if (Shutter.real_position[i]>Shutter.open_max[i]) Shutter.real_position[i] = Shutter.open_max[i]; + if (Shutter.target_position[i]<0) Shutter.target_position[i] = 0; + if (Shutter.target_position[i]>Shutter.open_max[i]) Shutter.target_position[i] = Shutter.open_max[i]; +} + void ShutterUpdatePosition(void) { @@ -362,6 +376,7 @@ void ShutterUpdatePosition(void) } break; } + ShutterLimitRealAndTargetPositions(i); Settings.shutter_position[i] = ShutterRealToPercentPosition(Shutter.real_position[i], i); ShutterLogPos(i); @@ -371,7 +386,7 @@ void ShutterUpdatePosition(void) // sending MQTT result to broker snprintf_P(scommand, sizeof(scommand),PSTR(D_SHUTTER "%d"), i+1); GetTopic_P(stopic, STAT, mqtt_topic, scommand); - Response_P("%d", Settings.shutter_invert[i] ? 100 - Settings.shutter_position[i]: Settings.shutter_position[i]); + Response_P("%d", (Settings.shutter_options[i] & 1) ? 100 - Settings.shutter_position[i]: Settings.shutter_position[i]); MqttPublish(stopic, Settings.flag.mqtt_power_retain); // CMND_POWERRETAIN Shutter.direction[i] = 0; @@ -462,6 +477,7 @@ void ShutterRelayChanged(void) //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Shutter %d: source: %s, powerstate_local %ld, Shutter.switched_relay %d, manual change %d"), i+1, GetTextIndexed(stemp1, sizeof(stemp1), last_source, kCommandSource), powerstate_local,Shutter.switched_relay,manual_relays_changed); if (manual_relays_changed) { //Shutter.skip_relay_change = true; + ShutterLimitRealAndTargetPositions(i); if (Shutter.mode == SHT_OFF_ON__OPEN_CLOSE || Shutter.mode == SHT_OFF_ON__OPEN_CLOSE_STEPPER) { ShutterWaitForMotorStop(i); switch (powerstate_local) { @@ -497,6 +513,16 @@ void ShutterRelayChanged(void) } } +bool ShutterButtonIsSimultaneousHold(uint32_t button_index, uint32_t shutter_index) { + // check for simultaneous shutter button hold + uint32 min_shutterbutton_hold_timer = -1; + for (uint32_t i = 0; i < MAX_KEYS; i++) { + if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index) && (Button.hold_timer[i] < min_shutterbutton_hold_timer)) + min_shutterbutton_hold_timer = Button.hold_timer[i]; + } + return (min_shutterbutton_hold_timer > (Button.hold_timer[button_index]>>1)); +} + void ShutterButtonHandler(void) { uint8_t buttonState = SHT_NOT_PRESSED; @@ -534,11 +560,30 @@ void ShutterButtonHandler(void) Button.press_counter[button_index] = 0; // Discard button press to disable functionality } } - if (Button.hold_timer[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10) { // SetOption32 (40) - Button hold - if (Button.press_counter[button_index]<99) + if ((Button.press_counter[button_index]<99) && (Button.hold_timer[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10)) { // press still valid && SetOption32 (40) - Button hold + // check for simultaneous shutter button hold + if (ShutterButtonIsSimultaneousHold(button_index, shutter_index)) { + // simultaneous shutter button hold detected + for (uint32_t i = 0; i < MAX_KEYS; i++) + if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index)) + Button.press_counter[i] = 99; // Remember to discard further action for press & hold within button timings + press_index = 0; + buttonState = SHT_PRESSED_HOLD_SIMULTANEOUS; + } + if (Button.press_counter[button_index]<99) { + press_index = 0; buttonState = SHT_PRESSED_HOLD; + } Button.press_counter[button_index] = 0; } + if ((Button.press_counter[button_index]==0) && (Button.hold_timer[button_index] == loops_per_second * IMMINENT_RESET_FACTOR * Settings.param[P_HOLD_TIME] / 10)) { // SetOption32 (40) - Button held for factor times longer + // check for simultaneous shutter button extend hold + if (ShutterButtonIsSimultaneousHold(button_index, shutter_index)) { + // simultaneous shutter button extend hold detected + press_index = 0; + buttonState = SHT_PRESSED_EXT_HOLD_SIMULTANEOUS; + } + } } } @@ -548,48 +593,83 @@ void ShutterButtonHandler(void) } else { if (!restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0)) { if (Button.press_counter[button_index]<99) { - press_index = Button.press_counter[button_index]; - buttonState = SHT_PRESSED_MULTI; + // check for simultaneous shutter button press + uint32 min_shutterbutton_press_counter = -1; + for (uint32_t i = 0; i < MAX_KEYS; i++) { + if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index) && (Button.press_counter[i] < min_shutterbutton_press_counter)) + min_shutterbutton_press_counter = Button.press_counter[i]; + } + if (min_shutterbutton_press_counter == Button.press_counter[button_index]) { + // simultaneous shutter button press detected + press_index = Button.press_counter[button_index]; + for (uint32_t i = 0; i < MAX_KEYS; i++) + if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index)) + Button.press_counter[i] = 99; // Remember to discard further action for press & hold within button timings + buttonState = SHT_PRESSED_MULTI_SIMULTANEOUS; + } + if ((buttonState != SHT_PRESSED_MULTI_SIMULTANEOUS) && (Button.press_counter[button_index]<99)) { + // no simultaneous shutter button press >3 detected + press_index = Button.press_counter[button_index]; + buttonState = SHT_PRESSED_MULTI; + } } Button.press_counter[button_index] = 0; } } } - if (buttonState != SHT_NOT_PRESSED) { - if (Settings.shutter_startrelay[shutter_index] && Settings.shutter_startrelay[shutter_index] <9) { - if (press_index>3) press_index=3; - press_index = (buttonState == SHT_PRESSED_HOLD) ? 3 : (press_index-1); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: shutter %d, button %d = %d (single=1, double=2, tripple=3, hold=4)"), shutter_index+1, button_index+1, press_index+1); - XdrvMailbox.index = shutter_index +1; - last_source = SRC_BUTTON; - XdrvMailbox.data_len = 0; - char databuf[1] = ""; - XdrvMailbox.data = databuf; - XdrvMailbox.command = NULL; - if (buttonState == SHT_PRESSED_IMMEDIATE) { - XdrvMailbox.payload = XdrvMailbox.index; - CmndShutterStop(); - } - else { - uint8_t position = (Settings.shutter_button[button_index]>>(6*press_index + 2)) & 0x03f; - if (position) { - if (Shutter.direction[shutter_index]) { - XdrvMailbox.payload = XdrvMailbox.index; - CmndShutterStop(); - } else { - XdrvMailbox.payload = position = (position-1)<<1; - CmndShutterPosition(); - if (Settings.shutter_button[button_index] & ((0x01<<26)<=5) && (press_index<=7) && (!Settings.flag.button_restrict)) { // 5x..7x && no SetOption1 (0) + // simultaneous shutter button press 5x, 6x, 7x detected + char scmnd[20]; + GetTextIndexed(scmnd, sizeof(scmnd), press_index -3, kCommands); + ExecuteCommand(scmnd, SRC_BUTTON); + return; + } + } else if (buttonState == SHT_PRESSED_EXT_HOLD_SIMULTANEOUS) { + // simultaneous shutter button extend hold detected + if (!Settings.flag.button_restrict) { // no SetOption1 (0) + char scmnd[20]; + snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1")); + ExecuteCommand(scmnd, SRC_BUTTON); + return; + } + } else if (buttonState <= SHT_PRESSED_IMMEDIATE) { + if (Settings.shutter_startrelay[shutter_index] && Settings.shutter_startrelay[shutter_index] <9) { + uint8_t pos_press_index = (buttonState == SHT_PRESSED_HOLD) ? 3 : (press_index-1); + if (pos_press_index>3) pos_press_index=3; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: shutter %d, button %d = %d (single=1, double=2, tripple=3, hold=4)"), shutter_index+1, button_index+1, pos_press_index+1); + XdrvMailbox.index = shutter_index +1; + last_source = SRC_BUTTON; + XdrvMailbox.data_len = 0; + char databuf[1] = ""; + XdrvMailbox.data = databuf; + XdrvMailbox.command = NULL; + if (buttonState == SHT_PRESSED_IMMEDIATE) { + XdrvMailbox.payload = XdrvMailbox.index; + CmndShutterStop(); + } + else { + uint8_t position = (Settings.shutter_button[button_index]>>(6*pos_press_index + 2)) & 0x03f; + if (position) { + if (Shutter.direction[shutter_index]) { + XdrvMailbox.payload = XdrvMailbox.index; + CmndShutterStop(); + } else { + XdrvMailbox.payload = position = (position-1)<<1; + CmndShutterPosition(); + if (Settings.shutter_button[button_index] & ((0x01<<26)< 0) && (XdrvMailbox.index <= shutters_present)) { - if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) { - XdrvMailbox.index = XdrvMailbox.payload; - } - uint32_t i = XdrvMailbox.index -1; - if (Shutter.direction[i] != 0) { + if (!(Settings.shutter_options[XdrvMailbox.index-1] & 2)) { + if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) { + XdrvMailbox.index = XdrvMailbox.payload; + } + uint32_t i = XdrvMailbox.index -1; + if (Shutter.direction[i] != 0) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Stop moving %d: dir: %d"), XdrvMailbox.index, Shutter.direction[i]); - // set stop position 10 steps ahead (0.5sec to allow normal stop) - int32_t temp_realpos = Shutter.start_position[i] + ( (Shutter.time[i]+10) * (Shutter.direction[i] > 0 ? 100 : -Shutter.close_velocity[i])); - XdrvMailbox.payload = ShutterRealToPercentPosition(temp_realpos, i); - //XdrvMailbox.payload = Settings.shuttercoeff[2][i] * 5 > temp_realpos ? temp_realpos / Settings.shuttercoeff[2][i] : (temp_realpos-Settings.shuttercoeff[0,i]) / Settings.shuttercoeff[1][i]; - last_source = SRC_WEBGUI; - CmndShutterPosition(); + AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Stop moving %d: dir: %d"), XdrvMailbox.index, Shutter.direction[i]); + // set stop position 10 steps ahead (0.5sec to allow normal stop) + int32_t temp_realpos = Shutter.start_position[i] + ( (Shutter.time[i]+10) * (Shutter.direction[i] > 0 ? 100 : -Shutter.close_velocity[i])); + XdrvMailbox.payload = ShutterRealToPercentPosition(temp_realpos, i); + //XdrvMailbox.payload = Settings.shuttercoeff[2][i] * 5 > temp_realpos ? temp_realpos / Settings.shuttercoeff[2][i] : (temp_realpos-Settings.shuttercoeff[0,i]) / Settings.shuttercoeff[1][i]; + last_source = SRC_WEBGUI; + CmndShutterPosition(); + } else { + if (XdrvMailbox.command) + ResponseCmndDone(); + } } else { if (XdrvMailbox.command) - ResponseCmndDone(); + ResponseCmndIdxChar("Locked"); } } } @@ -660,78 +750,93 @@ void CmndShutterStop(void) void CmndShutterPosition(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - uint32_t index = XdrvMailbox.index-1; - //limit the payload - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Pos. in: payload %s (%d), payload %d, idx %d, src %d"), XdrvMailbox.data , XdrvMailbox.data_len, XdrvMailbox.payload , XdrvMailbox.index, last_source ); + if (!(Settings.shutter_options[XdrvMailbox.index-1] & 2)) { + uint32_t index = XdrvMailbox.index-1; + //limit the payload + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Pos. in: payload %s (%d), payload %d, idx %d, src %d"), XdrvMailbox.data , XdrvMailbox.data_len, XdrvMailbox.payload , XdrvMailbox.index, last_source ); - // value 0 with data_len > 0 can mean Open - if ((XdrvMailbox.data_len > 1) && (XdrvMailbox.payload <= 0)) { - //UpperCase(XdrvMailbox.data, XdrvMailbox.data); - if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_UP) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_OPEN)) { - CmndShutterOpen(); - return; + // value 0 with data_len > 0 can mean Open + if ((XdrvMailbox.data_len > 1) && (XdrvMailbox.payload <= 0)) { + //UpperCase(XdrvMailbox.data, XdrvMailbox.data); + if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_UP) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_OPEN) || ((Shutter.direction[index]==0) && !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLEUP))) { + CmndShutterOpen(); + return; + } + if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_DOWN) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_CLOSE) || ((Shutter.direction[index]==0) && !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLEDOWN))) { + CmndShutterClose(); + return; + } + if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOP) || ((Shutter.direction[index]) && (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLEUP) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLEDOWN)))) { + XdrvMailbox.payload = -99; + CmndShutterStop(); + return; + } } - if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_DOWN) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_CLOSE)) { - CmndShutterClose(); - return; - } - if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOP)) { - XdrvMailbox.payload = -99; - CmndShutterStop(); - return; - } - } - int8_t target_pos_percent = (XdrvMailbox.payload < 0) ? 0 : ((XdrvMailbox.payload > 100) ? 100 : XdrvMailbox.payload); - // webgui still send also on inverted shutter the native position. - target_pos_percent = (Settings.shutter_invert[index] && (SRC_WEBGUI != last_source)) ? 100 - target_pos_percent : target_pos_percent; - if (XdrvMailbox.payload != -99) { - //target_pos_percent = Settings.shutter_invert[index] ? 100 - target_pos_percent : target_pos_percent; - Shutter.target_position[index] = ShutterPercentToRealPosition(target_pos_percent, index); - Shutter.accelerator[index] = Shutter.max_pwm_frequency / ((Shutter.motordelay[index] > 0) ? Shutter.motordelay[index] : 1); - //Shutter.target_position[index] = XdrvMailbox.payload < 5 ? Settings.shuttercoeff[2][index] * XdrvMailbox.payload : Settings.shuttercoeff[1][index] * XdrvMailbox.payload + Settings.shuttercoeff[0,index]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: lastsource %d:, real %d, target %d, payload %d"), last_source, Shutter.real_position[index] ,Shutter.target_position[index],target_pos_percent); - } - if ( (target_pos_percent >= 0) && (target_pos_percent <= 100) && abs(Shutter.target_position[index] - Shutter.real_position[index] ) / Shutter.close_velocity[index] > 2) { - int8_t new_shutterdirection = Shutter.real_position[index] < Shutter.target_position[index] ? 1 : -1; - if (Shutter.direction[index] == -new_shutterdirection) { - // direction need to be changed. on momentary switches first stop the Shutter - if (SHT_PULSE_OPEN__PULSE_CLOSE == Shutter.mode) { - // code for momentary shutters only small switch on to stop Shutter - ExecuteCommandPower(Settings.shutter_startrelay[index] + ((new_shutterdirection == 1) ? 0 : 1), 1, SRC_SHUTTER); - delay(100); - } else { - if (SHT_OFF_OPEN__OFF_CLOSE == Shutter.mode) { - ExecuteCommandPower(Settings.shutter_startrelay[index] + ((new_shutterdirection == 1) ? 1 : 0), 0, SRC_SHUTTER); - ShutterWaitForMotorStop(index); + int8_t target_pos_percent = (XdrvMailbox.payload < 0) ? 0 : ((XdrvMailbox.payload > 100) ? 100 : XdrvMailbox.payload); + // webgui still send also on inverted shutter the native position. + target_pos_percent = ((Settings.shutter_options[index] & 1) && (SRC_WEBGUI != last_source)) ? 100 - target_pos_percent : target_pos_percent; + if (XdrvMailbox.payload != -99) { + //target_pos_percent = (Settings.shutter_options[index] & 1) ? 100 - target_pos_percent : target_pos_percent; + Shutter.target_position[index] = ShutterPercentToRealPosition(target_pos_percent, index); + Shutter.accelerator[index] = Shutter.max_pwm_frequency / ((Shutter.motordelay[index] > 0) ? Shutter.motordelay[index] : 1); + //Shutter.target_position[index] = XdrvMailbox.payload < 5 ? Settings.shuttercoeff[2][index] * XdrvMailbox.payload : Settings.shuttercoeff[1][index] * XdrvMailbox.payload + Settings.shuttercoeff[0,index]; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: lastsource %d:, real %d, target %d, payload %d"), last_source, Shutter.real_position[index] ,Shutter.target_position[index],target_pos_percent); + } + if ( (target_pos_percent >= 0) && (target_pos_percent <= 100) && abs(Shutter.target_position[index] - Shutter.real_position[index] ) / Shutter.close_velocity[index] > 2) { + if (Settings.shutter_options[index] & 4) { + if (0 == target_pos_percent) Shutter.target_position[index] -= 1 * 2000; + if (100 == target_pos_percent) Shutter.target_position[index] += 1 * 2000; + } + int8_t new_shutterdirection = Shutter.real_position[index] < Shutter.target_position[index] ? 1 : -1; + if (Shutter.direction[index] == -new_shutterdirection) { + // direction need to be changed. on momentary switches first stop the Shutter + if (SHT_PULSE_OPEN__PULSE_CLOSE == Shutter.mode) { + // code for momentary shutters only small switch on to stop Shutter + ExecuteCommandPower(Settings.shutter_startrelay[index] + ((new_shutterdirection == 1) ? 0 : 1), 1, SRC_SHUTTER); + delay(100); + } else { + if (SHT_OFF_OPEN__OFF_CLOSE == Shutter.mode) { + ExecuteCommandPower(Settings.shutter_startrelay[index] + ((new_shutterdirection == 1) ? 1 : 0), 0, SRC_SHUTTER); + ShutterWaitForMotorStop(index); + } } } - } - if (Shutter.direction[index] != new_shutterdirection) { - if ((SHT_OFF_ON__OPEN_CLOSE == Shutter.mode) || (SHT_OFF_ON__OPEN_CLOSE_STEPPER == Shutter.mode)) { - //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Delay5 5s, xdrv %d"), XdrvMailbox.payload); - ShutterWaitForMotorStop(index); - ExecuteCommandPower(Settings.shutter_startrelay[index], 0, SRC_SHUTTER); - ShutterStartInit(index, new_shutterdirection, Shutter.target_position[index]); - // Code for shutters with circuit safe configuration, switch the direction Relay - ExecuteCommandPower(Settings.shutter_startrelay[index] +1, new_shutterdirection == 1 ? 0 : 1, SRC_SHUTTER); - // power on - ExecuteCommandPower(Settings.shutter_startrelay[index], 1, SRC_SHUTTER); - } else { - // now start the motor for the right direction, work for momentary and normal shutters. - AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Start in dir %d"), Shutter.direction[index]); - ShutterStartInit(index, new_shutterdirection, Shutter.target_position[index]); - ExecuteCommandPower(Settings.shutter_startrelay[index] + (new_shutterdirection == 1 ? 0 : 1), 1, SRC_SHUTTER); - //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Delay6 5s, xdrv %d"), XdrvMailbox.payload); + if (Shutter.direction[index] != new_shutterdirection) { + if ((SHT_OFF_ON__OPEN_CLOSE == Shutter.mode) || (SHT_OFF_ON__OPEN_CLOSE_STEPPER == Shutter.mode)) { + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Delay5 5s, xdrv %d"), XdrvMailbox.payload); + ShutterWaitForMotorStop(index); + ExecuteCommandPower(Settings.shutter_startrelay[index], 0, SRC_SHUTTER); + ShutterStartInit(index, new_shutterdirection, Shutter.target_position[index]); + if (Shutter.skip_relay_change == 0) { + // Code for shutters with circuit safe configuration, switch the direction Relay + ExecuteCommandPower(Settings.shutter_startrelay[index] +1, new_shutterdirection == 1 ? 0 : 1, SRC_SHUTTER); + // power on + ExecuteCommandPower(Settings.shutter_startrelay[index], 1, SRC_SHUTTER); + } + } else { + // now start the motor for the right direction, work for momentary and normal shutters. + AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Start in dir %d"), Shutter.direction[index]); + ShutterStartInit(index, new_shutterdirection, Shutter.target_position[index]); + if (Shutter.skip_relay_change == 0) { + ExecuteCommandPower(Settings.shutter_startrelay[index] + (new_shutterdirection == 1 ? 0 : 1), 1, SRC_SHUTTER); + } + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Delay6 5s, xdrv %d"), XdrvMailbox.payload); + } + Shutter.switched_relay = 0; } - Shutter.switched_relay = 0; + } else { + target_pos_percent = ShutterRealToPercentPosition(Shutter.real_position[index], index); + ShutterReportPosition(true); } + XdrvMailbox.index = index +1; // Fix random index for ShutterClose + if (XdrvMailbox.command) + ResponseCmndIdxNumber((Settings.shutter_options[index] & 1) ? 100 - target_pos_percent : target_pos_percent); } else { - target_pos_percent = ShutterRealToPercentPosition(Shutter.real_position[index], index); + ShutterReportPosition(true); + if (XdrvMailbox.command) + ResponseCmndIdxChar("Locked"); } - XdrvMailbox.index = index +1; // Fix random index for ShutterClose - if (XdrvMailbox.command) - ResponseCmndIdxNumber(Settings.shutter_invert[index] ? 100 - target_pos_percent : target_pos_percent); } } @@ -808,18 +913,22 @@ void CmndShutterButton(void) // (setting>> 2)&(0x3f) : shutter_position single press 0 disabled, 1..101 == 0..100% // (setting>> 0)&(0x03) : shutter_index if (XdrvMailbox.data_len > 0) { - uint32_t i = 0, button_index = 0; + uint32_t i = 0; + uint32_t button_index = 0; bool done = false; + bool isShortCommand = false; char *str_ptr; - char* version_dup = strdup(XdrvMailbox.data); // Duplicate the version_str as strtok_r will modify it. - // Loop through the version string, splitting on ' ' seperators. - for (char *str = strtok_r(version_dup, " ", &str_ptr); str && i < (1+4+4+1); str = strtok_r(nullptr, " ", &str_ptr), i++) { - int field; - if (str[0] == '-') - field = -1; - else - field = atoi(str); + char data_copy[strlen(XdrvMailbox.data) +1]; + strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); // Duplicate data as strtok_r will modify it. + // Loop through the data string, splitting on ' ' seperators. + for (char *str = strtok_r(data_copy, " ", &str_ptr); str && i < (1+4+4+1); str = strtok_r(nullptr, " ", &str_ptr), i++) { + int field; + if (str[0] == '-') { + field = -1; + } else { + field = atoi(str); + } switch (i) { case 0: if ((field >= -1) && (field<=4)) { @@ -830,19 +939,26 @@ void CmndShutterButton(void) break; case 1: if (!strcmp_P(str, PSTR("up"))) { - setting |= (((100>>1)+1)<<2) | (((50>>1)+1)<<8) | (((75>>1)+1)<<14) | (((100>>1)+1)<<20) | (0x18<<26); - done = true; + setting |= (((100>>1)+1)<<2) | (((50>>1)+1)<<8) | (((75>>1)+1)<<14) | (((100>>1)+1)<<20); + isShortCommand = true; break; } else if (!strcmp_P(str, PSTR("down"))) { - setting |= (((0>>1)+1)<<2) | (((50>>1)+1)<<8) | (((25>>1)+1)<<14) | (((0>>1)+1)<<20) | (0x18<<26); - done = true; + setting |= (((0>>1)+1)<<2) | (((50>>1)+1)<<8) | (((25>>1)+1)<<14) | (((0>>1)+1)<<20); + isShortCommand = true; break; } else if (!strcmp_P(str, PSTR("updown"))) { setting |= (((100>>1)+1)<<2) | (((0>>1)+1)<<8) | (((50>>1)+1)<<14); - done = true; + isShortCommand = true; break; } case 2: + if (isShortCommand) { + if ((field==1) && (setting & (0x3F<<(2+6*3)))) + // if short command up or down then also enable MQTT broadcast + setting |= (0x3<<29); + done = true; + break; + } case 3: case 4: if ((field >= -1) && (field<=100)) @@ -859,7 +975,6 @@ void CmndShutterButton(void) } if (done) break; } - free(version_dup); if (button_index) { if (button_index==-1) { @@ -909,10 +1024,10 @@ void CmndShutterSetHalfway(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) { - Settings.shutter_set50percent[XdrvMailbox.index -1] = Settings.shutter_invert[XdrvMailbox.index -1] ? 100 - XdrvMailbox.payload : XdrvMailbox.payload; + Settings.shutter_set50percent[XdrvMailbox.index -1] = (Settings.shutter_options[XdrvMailbox.index -1] & 1) ? 100 - XdrvMailbox.payload : XdrvMailbox.payload; ShutterInit(); } - ResponseCmndIdxNumber(Settings.shutter_invert[XdrvMailbox.index -1] ? 100 - Settings.shutter_set50percent[XdrvMailbox.index -1] : Settings.shutter_set50percent[XdrvMailbox.index -1]); + ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 1) ? 100 - Settings.shutter_set50percent[XdrvMailbox.index -1] : Settings.shutter_set50percent[XdrvMailbox.index -1]); } } @@ -943,37 +1058,40 @@ void CmndShutterSetClose(void) void CmndShutterInvert(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { - Settings.shutter_invert[XdrvMailbox.index -1] = XdrvMailbox.payload; + if (XdrvMailbox.payload == 0) { + Settings.shutter_options[XdrvMailbox.index -1] &= ~(1); + } else if (XdrvMailbox.payload == 1) { + Settings.shutter_options[XdrvMailbox.index -1] |= (1); } - ResponseCmndIdxNumber(Settings.shutter_invert[XdrvMailbox.index -1]); + ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 1) ? 1 : 0); } } -void CmndShutterCalibration(void) // ???? +void CmndShutterCalibration(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { if (XdrvMailbox.data_len > 0) { - uint32_t i = 0; - char *str_ptr; - char* version_dup = strdup(XdrvMailbox.data); // Duplicate the version_str as strtok_r will modify it. - // Loop through the version string, splitting on '.' seperators. - for (char *str = strtok_r(version_dup, " ", &str_ptr); str && i < 5; str = strtok_r(nullptr, " ", &str_ptr), i++) { - int field = atoi(str); - // The fields in a version string can only range from 1-30000. - // and following value must be higher than previous one - if ((field <= 0) || (field > 30000) || ( (i>0) && (field <= messwerte[i-1]) ) ) { - break; - } - messwerte[i] = field; + uint32_t i = 0; + char *str_ptr; + + char data_copy[strlen(XdrvMailbox.data) +1]; + strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); // Duplicate data as strtok_r will modify it. + // Loop through the data string, splitting on ' ' seperators. + for (char *str = strtok_r(data_copy, " ", &str_ptr); str && i < 5; str = strtok_r(nullptr, " ", &str_ptr), i++) { + int field = atoi(str); + // The fields in a data string can only range from 1-30000. + // and following value must be higher than previous one + if ((field <= 0) || (field > 30000) || ( (i>0) && (field <= messwerte[i-1]) ) ) { + break; } - free(version_dup); - for (i=0 ; i < 5 ; i++) { - Settings.shuttercoeff[i][XdrvMailbox.index -1] = (uint32_t)messwerte[i] * 1000 / messwerte[4]; - AddLog_P2(LOG_LEVEL_INFO, PSTR("Settings.shuttercoeff: %d, i: %d, value: %d, messwert %d"), i,XdrvMailbox.index -1,Settings.shuttercoeff[i][XdrvMailbox.index -1], messwerte[i]); - } - ShutterInit(); - ResponseCmndIdxChar(XdrvMailbox.data); + messwerte[i] = field; + } + for (i = 0; i < 5; i++) { + Settings.shuttercoeff[i][XdrvMailbox.index -1] = SHT_DIV_ROUND((uint32_t)messwerte[i] * 1000, messwerte[4]); + AddLog_P2(LOG_LEVEL_INFO, PSTR("Settings.shuttercoeff: %d, i: %d, value: %d, messwert %d"), i,XdrvMailbox.index -1,Settings.shuttercoeff[i][XdrvMailbox.index -1], messwerte[i]); + } + ShutterInit(); + ResponseCmndIdxChar(XdrvMailbox.data); } else { char setting_chr[30] = "0"; snprintf_P(setting_chr, sizeof(setting_chr), PSTR("%d %d %d %d %d"), Settings.shuttercoeff[0][XdrvMailbox.index -1], Settings.shuttercoeff[1][XdrvMailbox.index -1], Settings.shuttercoeff[2][XdrvMailbox.index -1], Settings.shuttercoeff[3][XdrvMailbox.index -1], Settings.shuttercoeff[4][XdrvMailbox.index -1]); @@ -982,6 +1100,28 @@ void CmndShutterCalibration(void) // ???? } } +void CmndShutterLock(void) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { + if (XdrvMailbox.payload == 0) { + Settings.shutter_options[XdrvMailbox.index -1] &= ~(2); + } else if (XdrvMailbox.payload == 1) { + Settings.shutter_options[XdrvMailbox.index -1] |= (2); + } + ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 2) ? 1 : 0); + } +} + +void CmndShutterEnableEndStopTime(void) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { + if (XdrvMailbox.payload == 0) { + Settings.shutter_options[XdrvMailbox.index -1] &= ~(4); + } else if (XdrvMailbox.payload == 1) { + Settings.shutter_options[XdrvMailbox.index -1] |= (4); + } + ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 4) ? 1 : 0); + } +} + /*********************************************************************************************\ * Interface \*********************************************************************************************/ @@ -1008,7 +1148,7 @@ bool Xdrv27(uint8_t function) break; case FUNC_JSON_APPEND: for (uint8_t i = 0; i < shutters_present; i++) { - uint8_t position = Settings.shutter_invert[i] ? 100 - Settings.shutter_position[i]: Settings.shutter_position[i]; + uint8_t position = (Settings.shutter_options[i] & 1) ? 100 - Settings.shutter_position[i]: Settings.shutter_position[i]; ResponseAppend_P(","); ResponseAppend_P(JSON_SHUTTER_POS, i+1, position, Shutter.direction[i]); #ifdef USE_DOMOTICZ diff --git a/tasmota/xdrv_28_pcf8574.ino b/tasmota/xdrv_28_pcf8574.ino index ecbde786c..26ae9f65a 100644 --- a/tasmota/xdrv_28_pcf8574.ino +++ b/tasmota/xdrv_28_pcf8574.ino @@ -93,6 +93,12 @@ void Pcf8574Init(void) } pcf8574_address++; +#ifdef USE_MCP230xx_ADDR + if (USE_MCP230xx_ADDR == pcf8574_address) { + AddLog_P2(LOG_LEVEL_INFO, PSTR("PCF: Addr: 0x%x reserved for MCP320xx, skipping PCF8574 probe"), pcf8574_address); + pcf8574_address++; + } +#endif if ((PCF8574_ADDR1 +7) == pcf8574_address) { // Support I2C addresses 0x20 to 0x26 and 0x39 to 0x3F pcf8574_address = PCF8574_ADDR2 +1; } diff --git a/tasmota/xdsp_08_ILI9488.ino b/tasmota/xdsp_08_ILI9488.ino index 8b7438c5a..84a493fc6 100644 --- a/tasmota/xdsp_08_ILI9488.ino +++ b/tasmota/xdsp_08_ILI9488.ino @@ -116,6 +116,7 @@ void ILI9488_InitDriver() if (I2cEnabled(XI2C_38) && I2cSetDevice(FT6236_address)) { FT6236begin(FT6236_address); FT6236_found=1; + I2cSetActiveFound(FT6236_address, "FT6236"); } else { FT6236_found=0; } diff --git a/tasmota/xdsp_10_RA8876.ino b/tasmota/xdsp_10_RA8876.ino index 139a654ed..88f3ebad2 100644 --- a/tasmota/xdsp_10_RA8876.ino +++ b/tasmota/xdsp_10_RA8876.ino @@ -101,6 +101,7 @@ void RA8876_InitDriver() if (I2cEnabled(XI2C_39) && I2cSetDevice(FT5316_address)) { FT6236begin(FT5316_address); FT5316_found=1; + I2cSetActiveFound(FT5316_address, "FT5316"); } else { FT5316_found=0; } diff --git a/tasmota/xnrg_02_cse7766.ino b/tasmota/xnrg_02_cse7766.ino index 45001b55e..d7bb93665 100644 --- a/tasmota/xnrg_02_cse7766.ino +++ b/tasmota/xnrg_02_cse7766.ino @@ -20,7 +20,7 @@ #ifdef USE_ENERGY_SENSOR #ifdef USE_CSE7766 /*********************************************************************************************\ - * CSE7766 - Energy (Sonoff S31 and Sonoff Pow R2) + * CSE7759 and CSE7766 - Energy (Sonoff S31 and Sonoff Pow R2) * HLW8032 - Energy (Blitzwolf SHP5) * * Based on datasheet from http://www.chipsea.com/UploadFiles/2017/08/11144342F01B5662.pdf @@ -37,6 +37,12 @@ #define CSE_PREF 1000 #define CSE_UREF 100 +#define CSE_BUFFER_SIZE 25 + +#include + +TasmotaSerial *CseSerial = nullptr; + struct CSE { long voltage_cycle = 0; long current_cycle = 0; @@ -45,6 +51,8 @@ struct CSE { long cf_pulses = 0; long cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED; + int byte_counter = 0; + uint8_t *rx_buffer = nullptr; uint8_t power_invalid = 0; bool received = false; } Cse; @@ -57,7 +65,7 @@ void CseReceived(void) // 55 5A 02 F7 60 00 03 AB 00 40 10 02 60 5D 51 A6 58 03 E9 EF 71 0B 7A 36 - 55 = Ok, 71 = Ok // Hd Id VCal---- Voltage- ICal---- Current- PCal---- Power--- Ad CF--- Ck - uint8_t header = serial_in_buffer[0]; + uint8_t header = Cse.rx_buffer[0]; if ((header & 0xFC) == 0xFC) { AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Abnormal hardware")); return; @@ -67,30 +75,30 @@ void CseReceived(void) if (HLW_UREF_PULSE == Settings.energy_voltage_calibration) { long voltage_coefficient = 191200; // uSec if (CSE_NOT_CALIBRATED != header) { - voltage_coefficient = serial_in_buffer[2] << 16 | serial_in_buffer[3] << 8 | serial_in_buffer[4]; + voltage_coefficient = Cse.rx_buffer[2] << 16 | Cse.rx_buffer[3] << 8 | Cse.rx_buffer[4]; } Settings.energy_voltage_calibration = voltage_coefficient / CSE_UREF; } if (HLW_IREF_PULSE == Settings.energy_current_calibration) { long current_coefficient = 16140; // uSec if (CSE_NOT_CALIBRATED != header) { - current_coefficient = serial_in_buffer[8] << 16 | serial_in_buffer[9] << 8 | serial_in_buffer[10]; + current_coefficient = Cse.rx_buffer[8] << 16 | Cse.rx_buffer[9] << 8 | Cse.rx_buffer[10]; } Settings.energy_current_calibration = current_coefficient; } if (HLW_PREF_PULSE == Settings.energy_power_calibration) { long power_coefficient = 5364000; // uSec if (CSE_NOT_CALIBRATED != header) { - power_coefficient = serial_in_buffer[14] << 16 | serial_in_buffer[15] << 8 | serial_in_buffer[16]; + power_coefficient = Cse.rx_buffer[14] << 16 | Cse.rx_buffer[15] << 8 | Cse.rx_buffer[16]; } Settings.energy_power_calibration = power_coefficient / CSE_PREF; } - uint8_t adjustement = serial_in_buffer[20]; - Cse.voltage_cycle = serial_in_buffer[5] << 16 | serial_in_buffer[6] << 8 | serial_in_buffer[7]; - Cse.current_cycle = serial_in_buffer[11] << 16 | serial_in_buffer[12] << 8 | serial_in_buffer[13]; - Cse.power_cycle = serial_in_buffer[17] << 16 | serial_in_buffer[18] << 8 | serial_in_buffer[19]; - Cse.cf_pulses = serial_in_buffer[21] << 8 | serial_in_buffer[22]; + uint8_t adjustement = Cse.rx_buffer[20]; + Cse.voltage_cycle = Cse.rx_buffer[5] << 16 | Cse.rx_buffer[6] << 8 | Cse.rx_buffer[7]; + Cse.current_cycle = Cse.rx_buffer[11] << 16 | Cse.rx_buffer[12] << 8 | Cse.rx_buffer[13]; + Cse.power_cycle = Cse.rx_buffer[17] << 16 | Cse.rx_buffer[18] << 8 | Cse.rx_buffer[19]; + Cse.cf_pulses = Cse.rx_buffer[21] << 8 | Cse.rx_buffer[22]; if (Energy.power_on) { // Powered on if (adjustement & 0x40) { // Voltage valid @@ -134,41 +142,44 @@ void CseReceived(void) bool CseSerialInput(void) { - if (Cse.received) { - serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; - if (24 == serial_in_byte_counter) { + while (CseSerial->available()) { + yield(); + uint8_t serial_in_byte = CseSerial->read(); - AddLogSerial(LOG_LEVEL_DEBUG_MORE); + if (Cse.received) { + Cse.rx_buffer[Cse.byte_counter++] = serial_in_byte; + if (24 == Cse.byte_counter) { - uint8_t checksum = 0; - for (uint32_t i = 2; i < 23; i++) { checksum += serial_in_buffer[i]; } - if (checksum == serial_in_buffer[23]) { - Energy.data_valid[0] = 0; - CseReceived(); - Cse.received = false; - return true; - } else { - AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: " D_CHECKSUM_FAILURE)); - do { // Sync buffer with data (issue #1907 and #3425) - memmove(serial_in_buffer, serial_in_buffer +1, 24); - serial_in_byte_counter--; - } while ((serial_in_byte_counter > 2) && (0x5A != serial_in_buffer[1])); - if (0x5A != serial_in_buffer[1]) { + AddLogBuffer(LOG_LEVEL_DEBUG_MORE, Cse.rx_buffer, 24); + + uint8_t checksum = 0; + for (uint32_t i = 2; i < 23; i++) { checksum += Cse.rx_buffer[i]; } + if (checksum == Cse.rx_buffer[23]) { + Energy.data_valid[0] = 0; + CseReceived(); Cse.received = false; - serial_in_byte_counter = 0; + return true; + } else { + AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: " D_CHECKSUM_FAILURE)); + do { // Sync buffer with data (issue #1907 and #3425) + memmove(Cse.rx_buffer, Cse.rx_buffer +1, 24); + Cse.byte_counter--; + } while ((Cse.byte_counter > 2) && (0x5A != Cse.rx_buffer[1])); + if (0x5A != Cse.rx_buffer[1]) { + Cse.received = false; + Cse.byte_counter = 0; + } } } - } - } else { - if ((0x5A == serial_in_byte) && (1 == serial_in_byte_counter)) { // 0x5A - Packet header 2 - Cse.received = true; } else { - serial_in_byte_counter = 0; + if ((0x5A == serial_in_byte) && (1 == Cse.byte_counter)) { // 0x5A - Packet header 2 + Cse.received = true; + } else { + Cse.byte_counter = 0; + } + Cse.rx_buffer[Cse.byte_counter++] = serial_in_byte; } - serial_in_buffer[serial_in_byte_counter++] = serial_in_byte; } - serial_in_byte = 0; // Discard - return false; } /********************************************************************************************/ @@ -209,15 +220,33 @@ void CseEverySecond(void) } } -void CseDrvInit(void) +void CseSnsInit(void) { - if ((3 == pin[GPIO_CSE7766_RX]) && (1 == pin[GPIO_CSE7766_TX])) { // As it uses 8E1 currently only hardware serial is supported - SetSerial(4800, TS_SERIAL_8E1); + // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions +// CseSerial = new TasmotaSerial(pin[GPIO_CSE7766_RX], pin[GPIO_CSE7766_TX], 1); + CseSerial = new TasmotaSerial(pin[GPIO_CSE7766_RX], -1, 1); + if (CseSerial->begin(4800, 2)) { // Fake Software Serial 8E1 by using two stop bits + if (CseSerial->hardwareSerial()) { + SetSerial(4800, TS_SERIAL_8E1); + ClaimSerial(); + } if (0 == Settings.param[P_CSE7766_INVALID_POWER]) { Settings.param[P_CSE7766_INVALID_POWER] = CSE_MAX_INVALID_POWER; // SetOption39 1..255 } Cse.power_invalid = Settings.param[P_CSE7766_INVALID_POWER]; - energy_flg = XNRG_02; + } else { + energy_flg = ENERGY_NONE; + } +} + +void CseDrvInit(void) +{ + Cse.rx_buffer = (uint8_t*)(malloc(CSE_BUFFER_SIZE)); + if (Cse.rx_buffer != nullptr) { +// if ((pin[GPIO_CSE7766_RX] < 99) && (pin[GPIO_CSE7766_TX] < 99)) { + if (pin[GPIO_CSE7766_RX] < 99) { + energy_flg = XNRG_02; + } } } @@ -254,8 +283,8 @@ bool Xnrg02(uint8_t function) bool result = false; switch (function) { - case FUNC_SERIAL: - result = CseSerialInput(); + case FUNC_LOOP: + if (CseSerial) { CseSerialInput(); } break; case FUNC_ENERGY_EVERY_SECOND: CseEverySecond(); @@ -263,6 +292,9 @@ bool Xnrg02(uint8_t function) case FUNC_COMMAND: result = CseCommand(); break; + case FUNC_INIT: + CseSnsInit(); + break; case FUNC_PRE_INIT: CseDrvInit(); break; diff --git a/tasmota/xnrg_09_dds2382.ino b/tasmota/xnrg_09_dds2382.ino index b211fa698..aea1f03ea 100644 --- a/tasmota/xnrg_09_dds2382.ino +++ b/tasmota/xnrg_09_dds2382.ino @@ -56,9 +56,14 @@ void Dds2382EverySecond(void) // 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 = ModBus register // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 = Buffer index + // 01 03 24 00 00 1C 7B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 F3 00 00 17 88 09 77 01 A6 03 F8 00 70 03 E1 13 8A 63 ED + // 01 03 24 00 00 1C AD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 F3 00 00 17 BA 09 77 01 F1 04 AF 00 6C 03 E3 13 86 41 A2 // SA FC BC EnergyTotal ExportActiv ImportActiv Volta Curre APowe RPowe PFact Frequ Crc-- = DDS238-2 ZN/S version 1 (#6384) // SA FC BC EnergyTotal ExportActiv ImportActiv Volta Curre APowe RPowe PFact Frequ Crc-- = DDS238-2 ZN/S version 2 (#6531) + // {"TotalStartTime":"2020-01-08T09:43:05","Total":0.060,"Yesterday":0.001,"Today":0.001,"ExportActive":12.670,"Period":0,"Power":1016,"ApparentPower":1020,"ReactivePower":112,"Factor":0.99,"Frequency":50,"Voltage":242,"Current":4.210}} + // {"TotalStartTime":"2020-01-08T00:00:00","Total":0.061,"Yesterday":0.001,"Today":0.001,"ExportActive":12.670,"Period":0.020,"Power":1199.000,"ApparentPower":1204.231,"ReactivePower":108.000,"Factor":1.00,"Frequency":49.98,"Voltage":242.3,"Current":4.970}} + Energy.voltage[0] = (float)((buffer[27] << 8) + buffer[28]) / 10.0; Energy.current[0] = (float)((buffer[29] << 8) + buffer[30]) / 100.0; Energy.active_power[0] = (float)((buffer[31] << 8) + buffer[32]); @@ -69,10 +74,10 @@ void Dds2382EverySecond(void) if (Settings.flag3.dds2382_model) { // SetOption71 - Select different Modbus registers for Active Energy (#6531) offset = 19; } - Energy.export_active = (float)((buffer[offset] << 24) + (buffer[offset +1] << 16) + (buffer[offset +2] << 8) + buffer[offset +3]) / 100.0; // 429496729.0 W - float import_active = (float)((buffer[offset +4] << 24) + (buffer[offset +5] << 16) + (buffer[offset +6] << 8) + buffer[offset +7]) / 100.0; // 429496729.0 W + Energy.export_active = (float)((buffer[offset] << 24) + (buffer[offset +1] << 16) + (buffer[offset +2] << 8) + buffer[offset +3]) / 100.0; // 429496.729 kW + float import_active = (float)((buffer[offset +4] << 24) + (buffer[offset +5] << 16) + (buffer[offset +6] << 8) + buffer[offset +7]) / 100.0; // 429496.729 kW - EnergyUpdateTotal(import_active, false); // 484.708 kWh + EnergyUpdateTotal(import_active, true); // 484.708 kWh } } // end data ready diff --git a/tasmota/xsns_02_analog.ino b/tasmota/xsns_02_analog.ino index f4de98d9a..038da9fa5 100644 --- a/tasmota/xsns_02_analog.ino +++ b/tasmota/xsns_02_analog.ino @@ -71,7 +71,7 @@ struct { void AdcInit(void) { - if ((Settings.adc_param_type != my_adc0) || (Settings.adc_param1 > 1000000) || (Settings.adc_param1 < 100)) { + if ((Settings.adc_param_type != my_adc0) || (Settings.adc_param1 > 1000000)) { if (ADC0_TEMP == my_adc0) { // Default Shelly 2.5 and 1PM parameters Settings.adc_param_type = ADC0_TEMP; @@ -85,11 +85,12 @@ void AdcInit(void) Settings.adc_param2 = ANALOG_LDR_LUX_CALC_SCALAR; Settings.adc_param3 = ANALOG_LDR_LUX_CALC_EXPONENT * 10000; } - else if (ADC0_MOIST == my_adc0) { - Settings.adc_param_type = ADC0_MOIST; + else if (ADC0_RANGE == my_adc0) { + Settings.adc_param_type = ADC0_RANGE; Settings.adc_param1 = 0; Settings.adc_param2 = 1023; Settings.adc_param3 = 0; + Settings.adc_param4 = 100; } else if (ADC0_CT_POWER == my_adc0) { Settings.adc_param_type = ADC0_CT_POWER; @@ -144,17 +145,14 @@ uint16_t AdcGetLux(void) return (uint16_t)ldrLux; } -uint16_t AdcGetMoist(void) +uint16_t AdcGetRange(void) { - // formula for calibration: value, fromLow, fromHigh, toHigh, toLow - // Example: 632, 0, 1023, 100, 0 - // int( ( ( ( - ) / ( - ) ) * ( - ) ) + ) - // double amoist = ((Settings.adc_param2 - (double)adc) / (Settings.adc_param2 - Settings.adc_param1) * 100; - // int((((1023 - ) / ( 1023 - 0 )) * ( 100 - 0 )) + 0 ) + // formula for calibration: value, fromLow, fromHigh, toLow, toHigh + // Example: 514, 632, 236, 0, 100 + // int( (( - ) / ( - ) ) * ( - ) ) + ) int adc = AdcRead(2); - double amoist = ((double)Settings.adc_param2 - (double)adc) / ((double)Settings.adc_param2 - (double)Settings.adc_param1) * 100; - //double amoist = ((1023 - (double)adc) / 1023) * 100; - return (uint16_t)amoist; + double adcrange = ( ((double)Settings.adc_param2 - (double)adc) / ( ((double)Settings.adc_param2 - (double)Settings.adc_param1)) * ((double)Settings.adc_param3 - (double)Settings.adc_param4) + (double)Settings.adc_param4 ); + return (uint16_t)adcrange; } void AdcGetCurrentPower(uint8_t factor) @@ -255,14 +253,14 @@ void AdcShow(bool json) } } - else if (ADC0_MOIST == my_adc0) { - uint16_t adc_moist = AdcGetMoist(); + else if (ADC0_RANGE == my_adc0) { + uint16_t adc_range = AdcGetRange(); if (json) { - ResponseAppend_P(JSON_SNS_MOISTURE, "ANALOG", adc_moist); + ResponseAppend_P(JSON_SNS_RANGE, "ANALOG", adc_range); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_SNS_MOISTURE, "", adc_moist); + WSContentSend_PD(HTTP_SNS_RANGE, "", adc_range); #endif // USE_WEBSERVER } } @@ -342,16 +340,20 @@ void CmndAdcParam(void) if (XdrvMailbox.data_len) { if ((ADC0_TEMP == XdrvMailbox.payload) || (ADC0_LIGHT == XdrvMailbox.payload) || - (ADC0_MOIST == XdrvMailbox.payload) || + (ADC0_RANGE == XdrvMailbox.payload) || (ADC0_CT_POWER == XdrvMailbox.payload)) { if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry char sub_string[XdrvMailbox.data_len +1]; // AdcParam 2, 32000, 10000, 3350 // AdcParam 3, 10000, 12518931, -1.405 + // AdcParam 6, 0, 1023, 0, 100 Settings.adc_param_type = XdrvMailbox.payload; Settings.adc_param1 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); Settings.adc_param2 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 3), nullptr, 10); - if (!ADC0_MOIST == XdrvMailbox.payload) { + if (ADC0_RANGE == XdrvMailbox.payload) { + Settings.adc_param3 = abs(strtol(subStr(sub_string, XdrvMailbox.data, ",", 4), nullptr, 10)); + Settings.adc_param4 = abs(strtol(subStr(sub_string, XdrvMailbox.data, ",", 5), nullptr, 10)); + } else { Settings.adc_param3 = (int)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 4)) * 10000); } if (ADC0_CT_POWER == XdrvMailbox.payload) { @@ -373,7 +375,9 @@ void CmndAdcParam(void) // AdcParam Response_P(PSTR("{\"" D_CMND_ADCPARAM "\":[%d,%d,%d"), Settings.adc_param_type, Settings.adc_param1, Settings.adc_param2); - if (ADC0_MOIST != my_adc0) { + if (ADC0_RANGE == my_adc0) { + ResponseAppend_P(PSTR(",%d,%d"), Settings.adc_param3, Settings.adc_param4); + } else { int value = Settings.adc_param3; uint8_t precision; for (precision = 4; precision > 0; precision--) { @@ -403,7 +407,7 @@ bool Xsns02(uint8_t function) if ((ADC0_INPUT == my_adc0) || (ADC0_TEMP == my_adc0) || (ADC0_LIGHT == my_adc0) || - (ADC0_MOIST == my_adc0) || + (ADC0_RANGE == my_adc0) || (ADC0_CT_POWER == my_adc0)) { switch (function) { #ifdef USE_RULES diff --git a/tasmota/xsns_05_ds18x20.ino b/tasmota/xsns_05_ds18x20.ino index 4168eaa32..ba87e3a5d 100644 --- a/tasmota/xsns_05_ds18x20.ino +++ b/tasmota/xsns_05_ds18x20.ino @@ -50,7 +50,9 @@ struct DS18X20STRUCT { float temperature; } ds18x20_sensor[DS18X20_MAX_SENSORS]; uint8_t ds18x20_sensors = 0; -uint8_t ds18x20_pin = 0; +uint8_t ds18x20_pin = 0; // Shelly GPIO3 input only +uint8_t ds18x20_pin_out = 0; // Shelly GPIO00 output only +bool ds18x20_dual_mode = false; // Single pin mode char ds18x20_types[12]; #ifdef W1_PARASITE_POWER uint8_t ds18x20_sensor_curr = 0; @@ -69,25 +71,38 @@ uint8_t onewire_last_family_discrepancy = 0; bool onewire_last_device_flag = false; unsigned char onewire_rom_id[8] = { 0 }; +/*------------------------------------------------------------------------------------------*/ + uint8_t OneWireReset(void) { uint8_t retries = 125; - //noInterrupts(); - pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); // SetOption74 - Enable internal pullup for single DS18x20 sensor - do { - if (--retries == 0) { - return 0; - } - delayMicroseconds(2); - } while (!digitalRead(ds18x20_pin)); - pinMode(ds18x20_pin, OUTPUT); - digitalWrite(ds18x20_pin, LOW); - delayMicroseconds(480); - pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); // SetOption74 - Enable internal pullup for single DS18x20 sensor + if (!ds18x20_dual_mode) { + pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); // SetOption74 - Enable internal pullup for single DS18x20 sensor + do { + if (--retries == 0) { + return 0; + } + delayMicroseconds(2); + } while (!digitalRead(ds18x20_pin)); + pinMode(ds18x20_pin, OUTPUT); + digitalWrite(ds18x20_pin, LOW); + delayMicroseconds(480); + pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); // SetOption74 - Enable internal pullup for single DS18x20 sensor + } else { + digitalWrite(ds18x20_pin_out, HIGH); + do { + if (--retries == 0) { + return 0; + } + delayMicroseconds(2); + } while (!digitalRead(ds18x20_pin)); + digitalWrite(ds18x20_pin_out, LOW); + delayMicroseconds(480); + digitalWrite(ds18x20_pin_out, HIGH); + } delayMicroseconds(70); uint8_t r = !digitalRead(ds18x20_pin); - //interrupts(); delayMicroseconds(410); return r; } @@ -98,29 +113,39 @@ void OneWireWriteBit(uint8_t v) static const uint8_t delay_high[2] = { 5, 55 }; v &= 1; - //noInterrupts(); - digitalWrite(ds18x20_pin, LOW); - pinMode(ds18x20_pin, OUTPUT); - delayMicroseconds(delay_low[v]); - digitalWrite(ds18x20_pin, HIGH); - //interrupts(); + if (!ds18x20_dual_mode) { + digitalWrite(ds18x20_pin, LOW); + pinMode(ds18x20_pin, OUTPUT); + delayMicroseconds(delay_low[v]); + digitalWrite(ds18x20_pin, HIGH); + } else { + digitalWrite(ds18x20_pin_out, LOW); + delayMicroseconds(delay_low[v]); + digitalWrite(ds18x20_pin_out, HIGH); + } delayMicroseconds(delay_high[v]); } uint8_t OneWireReadBit(void) { - //noInterrupts(); - pinMode(ds18x20_pin, OUTPUT); - digitalWrite(ds18x20_pin, LOW); - delayMicroseconds(3); - pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); // SetOption74 - Enable internal pullup for single DS18x20 sensor + if (!ds18x20_dual_mode) { + pinMode(ds18x20_pin, OUTPUT); + digitalWrite(ds18x20_pin, LOW); + delayMicroseconds(3); + pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); // SetOption74 - Enable internal pullup for single DS18x20 sensor + } else { + digitalWrite(ds18x20_pin_out, LOW); + delayMicroseconds(3); + digitalWrite(ds18x20_pin_out, HIGH); + } delayMicroseconds(10); uint8_t r = digitalRead(ds18x20_pin); - //interrupts(); delayMicroseconds(53); return r; } +/*------------------------------------------------------------------------------------------*/ + void OneWireWrite(uint8_t v) { for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) { @@ -259,6 +284,12 @@ void Ds18x20Init(void) uint64_t ids[DS18X20_MAX_SENSORS]; ds18x20_pin = pin[GPIO_DSB]; + if (pin[GPIO_DSB_OUT] < 99) { + ds18x20_pin_out = pin[GPIO_DSB_OUT]; + ds18x20_dual_mode = true; // Dual pins mode as used by Shelly + pinMode(ds18x20_pin_out, OUTPUT); + pinMode(ds18x20_pin, Settings.flag3.ds18x20_internal_pullup ? INPUT_PULLUP : INPUT); // SetOption74 - Enable internal pullup for single DS18x20 sensor + } OneWireResetSearch(); diff --git a/tasmota/xsns_06_dht.ino b/tasmota/xsns_06_dht.ino index 1c45a550e..c8c3dccd7 100644 --- a/tasmota/xsns_06_dht.ino +++ b/tasmota/xsns_06_dht.ino @@ -34,7 +34,9 @@ uint32_t dht_max_cycles; uint8_t dht_data[5]; uint8_t dht_sensors = 0; +uint8_t dht_pin_out = 0; // Shelly GPIO00 output only bool dht_active = true; // DHT configured +bool dht_dual_mode = false; // Single pin mode struct DHTSTRUCT { uint8_t pin; @@ -49,7 +51,11 @@ struct DHTSTRUCT { void DhtReadPrep(void) { for (uint32_t i = 0; i < dht_sensors; i++) { - digitalWrite(Dht[i].pin, HIGH); + if (!dht_dual_mode) { + digitalWrite(Dht[i].pin, HIGH); + } else { + digitalWrite(dht_pin_out, HIGH); + } } } @@ -77,11 +83,19 @@ bool DhtRead(uint8_t sensor) if (Dht[sensor].lastresult > DHT_MAX_RETRY) { Dht[sensor].lastresult = 0; - digitalWrite(Dht[sensor].pin, HIGH); // Retry read prep + if (!dht_dual_mode) { + digitalWrite(Dht[sensor].pin, HIGH); // Retry read prep + } else { + digitalWrite(dht_pin_out, HIGH); + } delay(250); } - pinMode(Dht[sensor].pin, OUTPUT); - digitalWrite(Dht[sensor].pin, LOW); + if (!dht_dual_mode) { + pinMode(Dht[sensor].pin, OUTPUT); + digitalWrite(Dht[sensor].pin, LOW); + } else { + digitalWrite(dht_pin_out, LOW); + } if (GPIO_SI7021 == Dht[sensor].type) { delayMicroseconds(500); @@ -90,9 +104,14 @@ bool DhtRead(uint8_t sensor) } noInterrupts(); - digitalWrite(Dht[sensor].pin, HIGH); - delayMicroseconds(40); - pinMode(Dht[sensor].pin, INPUT_PULLUP); + if (!dht_dual_mode) { + digitalWrite(Dht[sensor].pin, HIGH); + delayMicroseconds(40); + pinMode(Dht[sensor].pin, INPUT_PULLUP); + } else { + digitalWrite(dht_pin_out, HIGH); + delayMicroseconds(40); + } delayMicroseconds(10); if (-1 == DhtExpectPulse(sensor, LOW)) { AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_TIMEOUT_WAITING_FOR " " D_START_SIGNAL_LOW " " D_PULSE)); @@ -109,6 +128,7 @@ bool DhtRead(uint8_t sensor) } } interrupts(); + if (error) { return false; } for (uint32_t i = 0; i < 40; ++i) { @@ -187,6 +207,13 @@ void DhtInit(void) if (dht_sensors) { dht_max_cycles = microsecondsToClockCycles(1000); // 1 millisecond timeout for reading pulses from DHT sensor. + if (pin[GPIO_DHT11_OUT] < 99) { + dht_pin_out = pin[GPIO_DHT11_OUT]; + dht_dual_mode = true; // Dual pins mode as used by Shelly + dht_sensors = 1; // We only support one sensor in pseudo mode + pinMode(dht_pin_out, OUTPUT); + } + for (uint32_t i = 0; i < dht_sensors; i++) { pinMode(Dht[i].pin, INPUT_PULLUP); Dht[i].lastreadtime = 0; @@ -196,6 +223,7 @@ void DhtInit(void) snprintf_P(Dht[i].stype, sizeof(Dht[i].stype), PSTR("%s%c%02d"), Dht[i].stype, IndexSeparator(), Dht[i].pin); } } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DHT D_SENSORS_FOUND " %d"), dht_sensors); } else { dht_active = false; } diff --git a/tasmota/xsns_53_sml.ino b/tasmota/xsns_53_sml.ino index 1af1f526c..aeb57d0d8 100755 --- a/tasmota/xsns_53_sml.ino +++ b/tasmota/xsns_53_sml.ino @@ -2109,6 +2109,32 @@ init10: } +#ifdef USE_SML_SCRIPT_CMD +uint32_t SML_SetBaud(uint32_t meter, uint32_t br) { + if (meter<1 || meter>meters_used) return 0; + meter--; + if (!meter_ss[meter]) return 0; + if (meter_ss[meter]->begin(br)) { + meter_ss[meter]->flush(); + } + if (meter_ss[meter]->hardwareSerial()) { + if (meter_desc_p[meter].type=='M') { + Serial.begin(br, SERIAL_8E1); + } + } + return 1; +} + +uint32_t SML_Write(uint32_t meter,char *hstr) { + if (meter<1 || meter>meters_used) return 0; + meter--; + if (!meter_ss[meter]) return 0; + SML_Send_Seq(meter,hstr); + return 1; +} +#endif + + void SetDBGLed(uint8_t srcpin, uint8_t ledpin) { pinMode(ledpin, OUTPUT); if (digitalRead(srcpin)) { diff --git a/tasmota/xsns_56_hpma.ino b/tasmota/xsns_56_hpma.ino index c9d50f28f..c66b3c7fd 100644 --- a/tasmota/xsns_56_hpma.ino +++ b/tasmota/xsns_56_hpma.ino @@ -64,7 +64,6 @@ void HpmaSecond(void) // Every second void HpmaInit(void) { hpma_type = 0; - Serial.println("SDS init"); if (pin[GPIO_HPMA_RX] < 99 && pin[GPIO_HPMA_TX] < 99) { HpmaSerial = new TasmotaSerial(pin[GPIO_HPMA_RX], pin[GPIO_HPMA_TX], 1); hpma115S0 = new HPMA115S0(*HpmaSerial); diff --git a/tasmota/xsns_59_ds1624.ino b/tasmota/xsns_59_ds1624.ino index 9fe34b7d8..be0bcf9e5 100644 --- a/tasmota/xsns_59_ds1624.ino +++ b/tasmota/xsns_59_ds1624.ino @@ -38,6 +38,9 @@ #define DS1621_COUNTER_REGISTER 0xA8 //exists on 1621 and 1624(undocumented) #define DS1621_SLOPE_REGISTER 0xA9 //exists on 1624 and 1624(undocumented) +#define DS1621_CFG_1SHOT (1<<0) +#define DS1621_CFG_DONE (1<<7) + enum { DS1624_TYPE_DS1624, DS1624_TYPE_DS1621 @@ -50,6 +53,8 @@ bool ds1624_init = false; struct { float value; uint8_t type; + int errcnt; + int misscnt; bool valid; char name[9]; } ds1624_sns[DS1624_MAX_SENSORS]; @@ -58,6 +63,17 @@ uint32_t DS1624_Idx2Addr(uint32_t idx) { return 0x48 + idx; } +int DS1624_Restart(uint8_t config, uint32_t idx) { + uint32_t addr = DS1624_Idx2Addr(idx); + if ((config & 1) == 1) { + config &= ~(DS1621_CFG_DONE|DS1621_CFG_1SHOT); + I2cWrite8(addr, DS1624_CONF_REGISTER, config); // 1shot off + delay(10); // by spec after writing + AddLog_P2(LOG_LEVEL_ERROR, "%s addr %x is reset, reconfig: %x", ds1624_sns[idx].name, addr, config); + } + I2cValidRead(addr, DS1624_START_REGISTER, 1); +} + void DS1624_HotPlugUp(uint32_t idx) { uint32_t addr = DS1624_Idx2Addr(idx); @@ -75,12 +91,9 @@ void DS1624_HotPlugUp(uint32_t idx) I2cSetActiveFound(addr, ds1624_sns[idx].name); ds1624_sns[idx].valid = true; - if ((config & 1) == 1) { - config &= 0xfe; - I2cWrite8(addr, DS1624_CONF_REGISTER, config); // 1show off - delay(10); // by spec after writing - } - I2cValidRead(addr, DS1624_START_REGISTER, 1); // FIXME 0 must read, but 0 isn't work for tasmota + ds1624_sns[idx].errcnt = 0; + ds1624_sns[idx].misscnt = 0; + DS1624_Restart(config,idx); AddLog_P2(LOG_LEVEL_INFO, "Hot Plug %s addr %x config: %x", ds1624_sns[idx].name, addr, config); } } @@ -98,16 +111,37 @@ bool DS1624GetTemp(float *value, int idx) { uint32_t addr = DS1624_Idx2Addr(idx); + uint8_t config; + if (!I2cValidRead8(&config, addr, DS1624_CONF_REGISTER)) { + ds1624_sns[idx].misscnt++; + AddLog_P2(LOG_LEVEL_INFO, "%s device missing (errors: %i)", ds1624_sns[idx].name, ds1624_sns[idx].misscnt); + return false; + } + ds1624_sns[idx].misscnt=0; + if (config & (DS1621_CFG_1SHOT|DS1621_CFG_DONE)) { + ds1624_sns[idx].errcnt++; + AddLog_P2(LOG_LEVEL_INFO, "%s config error, restart... (errors: %i)", ds1624_sns[idx].name, ds1624_sns[idx].errcnt); + DS1624_Restart(config, idx); + return false; + } + uint16_t t; if (!I2cValidRead16(&t, DS1624_Idx2Addr(idx), DS1624_TEMP_REGISTER)) { return false; } - *value = ((float)(int8_t)(t>>8)) + ((t>>4)&0xf)*0.0625; - if (ds1624_sns[idx].type == DS1624_TYPE_DS1621) { // Higher resolution + if (ds1624_sns[idx].type == DS1624_TYPE_DS1624) { + *value = ((float)(int8_t)(t>>8)) + ((t>>4)&0xf)*0.0625; + } else { //type == DS1624_TYPE_DS1621 + // Datasheet for ds1621 is wrong for high resolution, real is: + *value = ((float)(int8_t)(t>>8)); uint8_t remain; if (!I2cValidRead8(&remain, addr, DS1621_COUNTER_REGISTER)) { return true; } uint8_t perc; if (!I2cValidRead8(&perc, addr, DS1621_SLOPE_REGISTER)) { return true; } - *value += ((float)perc - (float)remain)/((float)perc) - 0.25; + float fix=(float)(perc - remain)/(float)perc; + *value+=fix; } + ds1624_sns[idx].errcnt=0; + config &= ~(DS1621_CFG_DONE); + I2cWrite8(addr, DS1624_CONF_REGISTER, config); return true; } @@ -120,9 +154,11 @@ void DS1624HotPlugScan(void) if (I2cActive(addr) && !ds1624_sns[idx].valid) { continue; // is busy by another driver } - if (!I2cValidRead16(&t, DS1624_Idx2Addr(idx), DS1624_TEMP_REGISTER)) { - DS1624_HotPlugDown(idx); - continue; + if (ds1624_sns[idx].valid) { + if ((ds1624_sns[idx].misscnt>2)||(ds1624_sns[idx].errcnt>2)) { + DS1624_HotPlugDown(idx); + continue; + } } DS1624_HotPlugUp(idx); } diff --git a/tasmota/xsns_60_GPS.ino b/tasmota/xsns_60_GPS.ino index 13cfebdbd..42ef9949b 100644 --- a/tasmota/xsns_60_GPS.ino +++ b/tasmota/xsns_60_GPS.ino @@ -23,6 +23,8 @@ Version Date Action Description -------------------------------------------------------------------------------------------- + 0.9.2.0 20200110 integrate - Added UART-over-TCP/IP-bridge (virtual serial port). Minor tweaks. + --- 0.9.1.0 20191216 integrate - Added pin specifications from Tasmota WEB UI. Minor tweaks. --- 0.9.0.0 20190817 started - further development by Christian Baars - https://github.com/Staars/Sonoff-Tasmota @@ -38,11 +40,11 @@ Driver is tested on a NEO-6m and a Beitian-220. Series 7 should work too. This a - can log postion data with timestamp to flash with a small memory footprint of only 12 Bytes per record - constructs a GPX-file for download of this data - Web-UI -- simplified NTP-server +- simplified NTP-server and UART-over-TCP/IP-bridge (virtual serial port) - command interface ## Usage: -The serial pins are GPX_RX and GPS_TX, no further installation steps needed. To get more debug information compile it with option "DEBUG_TASMOTA_SENSOR". +The serial pins are GPS_RX and GPS_TX, no further installation steps needed. To get more debug information compile it with option "DEBUG_TASMOTA_SENSOR". ## Commands: @@ -89,7 +91,11 @@ The serial pins are GPX_RX and GPS_TX, no further installation steps needed. To + sensor60 13 set latitude and longitude in settings ++ sensor60 14 + open virtual serial port over TCP, usable for u-center ++ sensor60 15 + pause virtual serial port over TCP ## Rules examples for SSD1306 32x128 @@ -119,6 +125,9 @@ const char kUBXTypes[] PROGMEM = "UBX"; #define UBX_LAT_LON_THRESHOLD 1000 // filter out some noise of local drift +#define UBX_SERIAL_BUFFER_SIZE 256 +#define UBX_TCP_PORT 1234 + /********************************************************************************************\ | *globals \*********************************************************************************************/ @@ -252,6 +261,7 @@ struct UBX_t { uint32_t send_UI_only:1; uint32_t runningNTP:1; uint32_t forceUTCupdate:1; + uint32_t runningVPort:1; // TODO: more to come } mode; @@ -280,6 +290,9 @@ TasmotaSerial *UBXSerial; NtpServer timeServer(PortUdp); +WiFiServer vPortServer(UBX_TCP_PORT); +WiFiClient vPortClient; + /*********************************************************************************************\ * helper function \*********************************************************************************************/ @@ -324,7 +337,7 @@ void UBXDetect(void) { UBX.mode.init = 0; if ((pin[GPIO_GPS_RX] < 99) && (pin[GPIO_GPS_TX] < 99)) { - UBXSerial = new TasmotaSerial(pin[GPIO_GPS_RX], pin[GPIO_GPS_TX], 1, 0, 96); // 64 byte buffer is NOT enough + UBXSerial = new TasmotaSerial(pin[GPIO_GPS_RX], pin[GPIO_GPS_TX], 1, 0, UBX_SERIAL_BUFFER_SIZE); // 64 byte buffer is NOT enough if (UBXSerial->begin(9600)) { DEBUG_SENSOR_LOG(PSTR("UBX: started serial")); if (UBXSerial->hardwareSerial()) { @@ -575,6 +588,14 @@ void UBXSelectMode(uint16_t mode) Settings.latitude = UBX.state.last_lat; Settings.longitude = UBX.state.last_lon; break; + case 14: + vPortServer.begin(); + UBX.mode.runningVPort = 1; + break; + case 15: + // vPortServer.stop(); // seems not to work reliably + UBX.mode.runningVPort = 0; + break; default: if (mode>1000 && mode <1066) { // UBXSetRate(mode-1000); // min. 1001 = 0.001 Hz, but will be converted to 1/65535 anyway ~0.015 Hz, max. 2000 = 1.000 Hz @@ -629,7 +650,7 @@ void UBXHandleSTATUS() void UBXHandleTIME() { DEBUG_SENSOR_LOG(PSTR("UBX: UTC-Time: %u-%u-%u %u:%u:%u"), UBX.Message.navTime.year, UBX.Message.navTime.month ,UBX.Message.navTime.day,UBX.Message.navTime.hour,UBX.Message.navTime.min,UBX.Message.navTime.sec); - if (UBX.Message.navTime.valid.UTC) { + if (UBX.Message.navTime.valid.UTC == 1) { DEBUG_SENSOR_LOG(PSTR("UBX: UTC-Time is valid")); if (Rtc.user_time_entry == false || UBX.mode.forceUTCupdate) { AddLog_P(LOG_LEVEL_INFO, PSTR("UBX: UTC-Time is valid, set system time")); @@ -649,6 +670,7 @@ void UBXHandleTIME() void UBXHandleOther(void) { if (UBX.state.non_empty_loops>6) { // we expect only 4-5 non-empty loops in a row, could change with other sensor speed (Hz) + if(UBX.mode.runningVPort) return; UBXinitCFG(); // this should only happen with lots of NMEA-messages, but it is only a guess!! AddLog_P(LOG_LEVEL_ERROR, PSTR("UBX: possible device-reset, will re-init")); UBXSerial->flush(); @@ -658,8 +680,49 @@ void UBXHandleOther(void) /********************************************************************************************/ +void UBXhandleVPort(){ + static uint32_t idx = 0; + static uint8_t buf[UBX_SERIAL_BUFFER_SIZE]; + // static uint32_t tBufMax = 0; + // static uint32_t sBufMax = 0; + + if(!vPortClient.connected()) { + vPortClient = vPortServer.available(); + } + + while(vPortClient.available()) { + buf[idx] = (uint8_t)vPortClient.read(); + if(idxwrite(buf, idx); + // if(idx>tBufMax) { + // tBufMax = idx; + // AddLog_P2(LOG_LEVEL_INFO, PSTR("VPORT: new max. tcp buffer size: %u"),tBufMax); + // } + } + idx = 0; + + while(UBXSerial->available()) { + buf[idx] = (char)UBXSerial->read(); + if(idxsBufMax) { + // sBufMax = idx; + // AddLog_P2(LOG_LEVEL_INFO, PSTR("VPORT: new max. serial buffer size: %u"),sBufMax); + // } + } + idx = 0; +} + void UBXTimeServer() { + if(UBX.mode.runningVPort){ + UBXhandleVPort(); + return; + } if(UBX.mode.runningNTP){ timeServer.processOneRequest(Rtc.utc_time, UBX.state.last_iTOW%1000); } @@ -670,6 +733,10 @@ void UBXLoop(void) static uint16_t counter; //count up every 100 msec static bool new_position; + if(UBX.mode.runningVPort) { + return; + } + uint32_t msgType = UBXprocessGPS(); switch(msgType){ @@ -832,7 +899,7 @@ bool Xsns60(uint8_t function) } break; case FUNC_EVERY_50_MSECOND: - UBXTimeServer(); + UBXTimeServer(); // handles virtual serial port too break; case FUNC_EVERY_100_MSECOND: #ifdef USE_FLOG @@ -865,4 +932,4 @@ bool Xsns60(uint8_t function) return result; } -#endif // USE_GPS +#endif // USE_GPS \ No newline at end of file diff --git a/tasmota/xsns_61_MI_BLE.ino b/tasmota/xsns_61_MI_BLE.ino index 88983e533..c07323684 100644 --- a/tasmota/xsns_61_MI_BLE.ino +++ b/tasmota/xsns_61_MI_BLE.ino @@ -21,6 +21,8 @@ Version yyyymmdd Action Description -------------------------------------------------------------------------------------------- + + 0.9.1.0 20200117 integrate - Added support for the LYWSD02 --- 0.9.0.0 20191127 started - further development by Christian Baars base - code base from cbm80amiga, floe, Dmitry.GR @@ -52,7 +54,7 @@ const char MIBLESlaveFlora[] PROGMEM = "Flora"; const char MIBLESlaveMJ_HT_V1[] PROGMEM = "MJ_HT_V1"; - +const char MIBLESlaveLYWSD02[] PROGMEM = "LYWSD02"; #pragma pack(1) // important!! struct MJ_HT_V1Header_t {// related to the payload @@ -148,6 +150,19 @@ union MJ_HT_V1Packet_t { // related to the whole 32-byte-packet/buffer // We do NOT need the isolated T and H packet }; +union LYWSD02Packet_t { // related to the whole 32-byte-packet/buffer + struct { + uint16_t idWord; + uint8_t padding; + uint8_t serial[6]; + uint8_t padding4; + uint8_t mode; + uint8_t valueTen; + uint8_t effectiveDataLength; + uint16_t data; + } TH; // mode 04 or 06 +}; + struct bleAdvPacket_t { // for nRF24L01 max 32 bytes = 2+6+24 uint8_t pduType; uint8_t payloadSize; @@ -205,6 +220,7 @@ union FIFO_t{ bleAdvPacket_t bleAdv; floraPacket_t floraPacket; MJ_HT_V1Packet_t MJ_HT_V1Packet; + LYWSD02Packet_t LYWSD02Packet; uint8_t raw[32]; }; @@ -227,7 +243,7 @@ struct { } MIBLE; struct mi_sensor_t{ - uint8_t type; //flora = 1; MI-HT_V1=2 + uint8_t type; //flora = 1; MI-HT_V1=2; LYWSD02=3 uint8_t serial[6]; uint8_t showedUp; union { @@ -242,6 +258,10 @@ struct mi_sensor_t{ float hum; uint8_t bat; } MJ_HT_V1; + struct { + float temp; + float hum; + } LYWSD02; }; }; @@ -312,6 +332,9 @@ bool MIBLEreceivePacket(void) case 2: MIBLEwhiten((uint8_t *)&MIBLE.buffer, sizeof(MIBLE.buffer), 0x72); // "MJ_HT_V1" mode 0x72 break; + case 3: + MIBLEwhiten((uint8_t *)&MIBLE.buffer, sizeof(MIBLE.buffer), 0x17); // "LYWSD02" mode 0x17 + break; } // DEBUG_SENSOR_LOG(PSTR("MIBLE: LSFR:%x"),_lsfr); // if (_lsfr>254) _lsfr=0; @@ -403,6 +426,9 @@ void MIBLEchangePacketModeTo(uint8_t _mode) { case 2: // special MJ_HT_V1 packet NRF24radio.openReadingPipe(0,0xdbcc0cd3); // 95 fe 50 20 -> MJ_HT_V1, needs lsfr 0x72 break; + case 3: // special LYWSD02 packet + NRF24radio.openReadingPipe(0,0xef3b0730); // 95 fe 70 20 -> LYWSD02, needs lfsr 0x17 + break; } DEBUG_SENSOR_LOG(PSTR("MIBLE: Change Mode to %u"),_mode); MIBLE.timer = 0; @@ -447,6 +473,10 @@ uint32_t MIBLEgetSensorSlot(uint8_t (&_serial)[6], uint8_t _type){ _newSensor.MJ_HT_V1.hum=-1.0f; _newSensor.MJ_HT_V1.bat=0xff; break; + case 3: + _newSensor.LYWSD02.temp=-1000.0f; + _newSensor.LYWSD02.hum=-1.0f; + break; default: break; } @@ -544,7 +574,34 @@ void MIBLEhandleMJ_HT_V1Packet(void){ DEBUG_SENSOR_LOG(PSTR("MJ_HT_V1 mode:0x0a: U8: %x %%"), MIBLE.buffer.MJ_HT_V1Packet.B.battery); break; } +} +void MIBLEhandleLYWSD02Packet(void){ + if(MIBLE.buffer.LYWSD02Packet.TH.valueTen!=0x10){ + DEBUG_SENSOR_LOG(PSTR("MIBLE: unexpected LYWSD02-packet")); + MIBLE_LOG_BUFFER(MIBLE.buffer.raw); + return; + } + uint32_t _slot = MIBLEgetSensorSlot(MIBLE.buffer.LYWSD02Packet.TH.serial, 3); // H would be possible too + DEBUG_SENSOR_LOG(PSTR("MIBLE: Sensor slot: %u"), _slot); + + static float _tempFloat; + switch(MIBLE.buffer.LYWSD02Packet.TH.mode) { // we can use any struct with a mode, they are all same at this point + case 4: + _tempFloat=(float)(MIBLE.buffer.LYWSD02Packet.TH.data)/10.0f; + if(_tempFloat<60){ + MIBLEsensors.at(_slot).LYWSD02.temp=_tempFloat; + } + DEBUG_SENSOR_LOG(PSTR("LYWSD02: Mode 4: U16: %x Temp"), MIBLE.buffer.LYWSD02Packet.TH.data ); + break; + case 6: + _tempFloat=(float)(MIBLE.buffer.LYWSD02Packet.TH.data)/10.0f; + if(_tempFloat<101){ + MIBLEsensors.at(_slot).LYWSD02.hum=_tempFloat; + } + DEBUG_SENSOR_LOG(PSTR("LYWSD02: Mode 6: U16: %x Hum"), MIBLE.buffer.LYWSD02Packet.TH.data ); + break; + } } void MIBLE_EVERY_100_MSECOND() { // Every 100mseconds, with many sensors 50ms could make sense @@ -555,7 +612,7 @@ void MIBLE_EVERY_100_MSECOND() { // Every 100mseconds, with many sensors 50ms co MIBLEpurgeFakeSensors(); } DEBUG_SENSOR_LOG(PSTR("MIBLE: Change packet mode after 60 seconds, MIBLE.timer: %u"),MIBLE.timer); - if (MIBLE.packetMode == 2){ + if (MIBLE.packetMode == 3){ MIBLEinitBLE(1); // no real ble packets in release mode, otherwise for developing use 0 } else { @@ -592,7 +649,10 @@ void MIBLE_EVERY_100_MSECOND() { // Every 100mseconds, with many sensors 50ms co } if (MIBLE.packetMode == 2){ // "MJ_HT_V1" mode MIBLEhandleMJ_HT_V1Packet(); - } + } + if (MIBLE.packetMode == 3){ // "LYWSD02" mode + MIBLEhandleLYWSD02Packet(); + } MIBLEhopChannel(); NRF24radio.startListening(); @@ -666,6 +726,23 @@ void MIBLEShow(bool json) } ResponseAppend_P(PSTR("}")); break; + case 3: + if(MIBLEsensors.at(i).showedUp < 3){ + DEBUG_SENSOR_LOG(PSTR("MIBLE: sensor not fully registered yet")); + break; + } + sprintf_P(slave,"%s-%02x%02x%02x",MIBLESlaveLYWSD02,MIBLEsensors.at(i).serial[2],MIBLEsensors.at(i).serial[1],MIBLEsensors.at(i).serial[0]); + dtostrfd(MIBLEsensors.at(i).LYWSD02.temp, Settings.flag2.temperature_resolution, temperature); + dtostrfd(MIBLEsensors.at(i).LYWSD02.hum, 1, humidity); + ResponseAppend_P(PSTR(",\"%s\":{"),slave); + if(MIBLEsensors.at(i).LYWSD02.temp!=-1000.0f){ // this is the error code -> no temperature + ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%s"), temperature); + } + if(MIBLEsensors.at(i).LYWSD02.hum!=-1000.0f){ // this is the error code -> no temperature + ResponseAppend_P(PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity); + } + ResponseAppend_P(PSTR("}")); + break; } } #ifdef USE_WEBSERVER @@ -721,11 +798,27 @@ void MIBLEShow(bool json) } if(MIBLEsensors.at(i).MJ_HT_V1.bat!=0xff){ WSContentSend_PD(HTTP_BATTERY, MIBLESlaveMJ_HT_V1, MIBLEsensors.at(i).MJ_HT_V1.bat); + } + break; + case 3: + if(MIBLEsensors.at(i).showedUp < 3){ + DEBUG_SENSOR_LOG(PSTR("MIBLE: sensor not fully registered yet")); + break; + } + dtostrfd(MIBLEsensors.at(i).LYWSD02.temp, Settings.flag2.temperature_resolution, temperature); + dtostrfd(MIBLEsensors.at(i).LYWSD02.hum, 1, humidity); + + WSContentSend_PD(HTTP_MIBLE_SERIAL, MIBLESlaveLYWSD02, MIBLEsensors.at(i).serial[5], MIBLEsensors.at(i).serial[4],MIBLEsensors.at(i).serial[3],MIBLEsensors.at(i).serial[2],MIBLEsensors.at(i).serial[1],MIBLEsensors.at(i).serial[0]); + if(MIBLEsensors.at(i).LYWSD02.temp!=-1000.0f){ + WSContentSend_PD(HTTP_SNS_TEMP, MIBLESlaveLYWSD02, temperature, TempUnit()); + } + if(MIBLEsensors.at(i).LYWSD02.hum!=-1.0f){ + WSContentSend_PD(HTTP_SNS_HUM, MIBLESlaveLYWSD02, humidity); + } break; } } } - } #endif // USE_WEBSERVER } diff --git a/tasmota/xsns_62_MI_HM10.ino b/tasmota/xsns_62_MI_HM10.ino new file mode 100644 index 000000000..17cc094ad --- /dev/null +++ b/tasmota/xsns_62_MI_HM10.ino @@ -0,0 +1,850 @@ +/* + xsns_62_MI_HM10.ino - MI-BLE-sensors via HM-10 support for Tasmota + + Copyright (C) 2020 Christian Baars and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + + + -------------------------------------------------------------------------------------------- + Version yyyymmdd Action Description + -------------------------------------------------------------------------------------------- + + 0.9.1.0 20200209 added - LYWSD02-support, including setting the time + --- + 0.9.0.0 20200130 started - initial development by Christian Baars (support LYWSD03 only) + forked - from arendst/tasmota - https://github.com/arendst/Tasmota + +*/ +#ifdef USE_HM10 + +#define XSNS_62 62 + +#include +#include + +TasmotaSerial *HM10Serial; +#define HM10_BAUDRATE 115200 // default with FW>700 is 115200 + +#define HM10_MAX_TASK_NUMBER 12 +uint8_t HM10_TASK_LIST[HM10_MAX_TASK_NUMBER+1][2]; // first value: kind of task - second value: delay in x * 100ms + +#define HM10_MAX_RX_BUF 512 +char HM10_RX_STRING[HM10_MAX_RX_BUF] = {0}; + +struct { + uint8_t current_task_delay; // number of 100ms-cycles + uint8_t last_command; + uint16_t firmware; + uint32_t period; // set manually in addition to TELE-period, is set to TELE-period after start + uint32_t serialSpeed; + union { + uint32_t time; + uint8_t timebuf[4]; + }; + struct { + uint32_t init:1; + uint32_t pending_task:1; + uint32_t connected:1; + uint32_t subscribed:1; + uint32_t awaitingHT:1; + uint32_t awaitingB:1; + // TODO: more to come + } mode; + struct { + uint8_t sensor; // points to to the number 0...255 + // TODO: more to come + } state; +} HM10; + +#pragma pack(1) +struct { + uint16_t temp; + uint8_t hum; +} LYWSD0x_HT; +#pragma pack(0) + +struct mi_sensor_t{ + uint8_t type; //Flora = 1; MI-HT_V1=2; LYWSD02=3; LYWSD03=4 + uint8_t serial[6]; + uint8_t showedUp; + float temp; //Flora, MJ_HT_V1, LYWSD0x + union { + struct { + float moisture; + float fertility; + uint16_t lux; + }; // Flora + struct { + float hum; + uint8_t bat; + }; // MJ_HT_V1, LYWSD0x + }; +}; + +std::vector MIBLEsensors; + +/*********************************************************************************************\ + * constants +\*********************************************************************************************/ + +#define D_CMND_HM10 "HM10" + +const char S_JSON_HM10_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_HM10 "%s\":%d}"; +const char S_JSON_HM10_COMMAND[] PROGMEM = "{\"" D_CMND_HM10 "%s%s\"}"; +const char kHM10_Commands[] PROGMEM = "Scan|AT|Period|Baud|Time"; + +#define FLORA 1 +#define MJ_HT_V1 2 +#define LYWSD02 3 +#define LYWSD03MMC 4 + +uint8_t kHM10SlaveID[4][3] = { 0xC4,0x7C,0x8D, // Flora + 0x58,0x2D,0x34, // MJ_HT_V1 + 0xE7,0x2E,0x00, // LYWSD02 + 0xA4,0xC1,0x38, // LYWSD03 + }; + +const char kHM10SlaveType1[] PROGMEM = "Flora"; +const char kHM10SlaveType2[] PROGMEM = "MJ_HT_V1"; +const char kHM10SlaveType3[] PROGMEM = "LYWSD02"; +const char kHM10SlaveType4[] PROGMEM = "LYWSD03"; +const char * kHM10SlaveType[] PROGMEM = {kHM10SlaveType1,kHM10SlaveType2,kHM10SlaveType3,kHM10SlaveType4}; + +/*********************************************************************************************\ + * enumerations +\*********************************************************************************************/ + +enum HM10_Commands { // commands useable in console or rules + CMND_HM10_DISC_SCAN, // re-scan for sensors + CMND_HM10_AT, // send AT-command for debugging and special configuration + CMND_HM10_PERIOD, // set period like TELE-period in seconds between read-cycles + CMND_HM10_BAUD, // serial speed of ESP8266 (<-> HM10), does not change baud rate of HM10 + CMND_HM10_TIME // set LYWSD02-Time from ESP8266-time + }; + +/*********************************************************************************************\ + * Task codes defines +\*********************************************************************************************/ + +#define TASK_HM10_NOTASK 0 // nothing to be done +#define TASK_HM10_ROLE1 1 // change role to 1 +#define TASK_HM10_IMME1 2 // change imme to 1 +#define TASK_HM10_RENEW 3 // device factory setting +#define TASK_HM10_RESET 4 // device reset +#define TASK_HM10_DISC 5 // device discovery scan +#define TASK_HM10_CONN 6 // connect to given MAC +#define TASK_HM10_VERSION 7 // query FW version +#define TASK_HM10_NAME 8 // query device name +#define TASK_HM10_FEEDBACK 9 // get device response +#define TASK_HM10_DISCONN 10 // disconnect +#define TASK_HM10_SUB_L3 11 // subscribe to service handle 37 +#define TASK_HM10_READ_HT 12 // read from handle 36 -> Hum & Temp +#define TASK_HM10_FINDALLCHARS 13 // read all available characteristics +#define TASK_HM10_UN_L3 14 // subscribe service handle 37 +#define TASK_HM10_DELAY_SUB 15 // start reading from subscription delayed +#define TASK_HM10_READ_BT_L3 16 // read from handle 3A -> Battery +#define TASK_HM10_SUB_L2 17 // subscribe to service handle 3C +#define TASK_HM10_UN_L2 18 // subscribe service handle 3C +#define TASK_HM10_READ_BT_L2 19 // read from handle 43 -> Battery +#define TASK_HM10_TIME_L2 20 // set time of LYWSD02 to system time + +#define TASK_HM10_DONE 99 // used, if there was a task in the slot or just to wait + +/*********************************************************************************************\ + * Helper functions +\*********************************************************************************************/ + +void HM10_Launchtask(uint8_t task, uint8_t slot, uint8_t delay){ + HM10_TASK_LIST[slot][0] = task; + HM10_TASK_LIST[slot][1] = delay; + HM10_TASK_LIST[slot+1][0] = TASK_HM10_NOTASK; // the tasks must always be launched in ascending order!! + HM10.current_task_delay = HM10_TASK_LIST[0][1]; +} + +void HM10_TaskReplaceInSlot(uint8_t task, uint8_t slot){ + HM10.last_command = HM10_TASK_LIST[slot][0]; // save command + HM10_TASK_LIST[slot][0] = task; +} + +/*********************************************************************************************\ + * chained tasks +\*********************************************************************************************/ + +void HM10_Reset(void) { HM10_Launchtask(TASK_HM10_DISCONN,0,1); // disconnect + HM10_Launchtask(TASK_HM10_ROLE1,1,1); // set role to 1 + HM10_Launchtask(TASK_HM10_IMME1,2,1); // set imme to 1 + HM10_Launchtask(TASK_HM10_RESET,3,1); // reset Device + HM10_Launchtask(TASK_HM10_VERSION,4,10); // read SW Version + HM10_Launchtask(TASK_HM10_DISC,5,50); // discovery + } + +void HM10_Discovery_Scan(void) { + HM10_Launchtask(TASK_HM10_DISCONN,0,1); // disconnect + HM10_Launchtask(TASK_HM10_DISC,1,1); // discovery + } + +void HM10_Read_LYWSD03(void) { + HM10_Launchtask(TASK_HM10_CONN,0,1); // connect + HM10_Launchtask(TASK_HM10_FEEDBACK,1,35); // get OK+CONN + HM10_Launchtask(TASK_HM10_SUB_L3,2,20); // subscribe + HM10_Launchtask(TASK_HM10_UN_L3,3,80); // unsubscribe + HM10_Launchtask(TASK_HM10_READ_BT_L3,4,5); // read Battery + HM10_Launchtask(TASK_HM10_DISCONN,5,5); // disconnect + } + +void HM10_Read_LYWSD02(void) { + HM10_Launchtask(TASK_HM10_CONN,0,1); // connect + HM10_Launchtask(TASK_HM10_FEEDBACK,1,35); // get OK+CONN + HM10_Launchtask(TASK_HM10_SUB_L2,2,20); // subscribe + HM10_Launchtask(TASK_HM10_UN_L2,3,80); // unsubscribe + HM10_Launchtask(TASK_HM10_READ_BT_L2,4,5); // read Battery + HM10_Launchtask(TASK_HM10_DISCONN,5,5); // disconnect + } + +void HM10_Time_LYWSD02(void) { + HM10_Launchtask(TASK_HM10_DISCONN,0,0); // disconnect + HM10_Launchtask(TASK_HM10_CONN,1,5); // connect + HM10_Launchtask(TASK_HM10_FEEDBACK,2,35); // get OK+CONN + HM10_Launchtask(TASK_HM10_TIME_L2,3,20); // subscribe + HM10_Launchtask(TASK_HM10_DISCONN,4,5); // disconnect + } + +/** + * @brief Return the slot number of a known sensor or return create new sensor slot + * + * @param _serial BLE address of the sensor + * @param _type Type number of the sensor, 0xff for Auto-type + * @return uint32_t Known or new slot in the sensors-vector + */ +uint32_t MIBLEgetSensorSlot(uint8_t (&_serial)[6], uint8_t _type){ + if(_type==0xff){ + DEBUG_SENSOR_LOG(PSTR("MIBLE: will test MAC-type")); + for (uint32_t i=0;i<4;i++){ + if(memcmp(_serial,kHM10SlaveID+i,3)==0){ + DEBUG_SENSOR_LOG(PSTR("MIBLE: MAC is type %u"), i); + _type = i+1; + } + else { + DEBUG_SENSOR_LOG(PSTR("MIBLE: MAC-type is unknown")); + } + } + } + if(_type==0xff) return _type; // error + + DEBUG_SENSOR_LOG(PSTR("MIBLE: vector size %u"), MIBLEsensors.size()); + for(uint32_t i=0; ibegin(HM10.serialSpeed)) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s start serial communication fixed to 115200 baud"),D_CMND_HM10); + if (HM10Serial->hardwareSerial()) { + ClaimSerial(); + DEBUG_SENSOR_LOG(PSTR("HM10: claim HW")); + } + HM10_Reset(); + HM10.mode.pending_task = 1; + HM10.mode.init = 1; + HM10.period = Settings.tele_period; + DEBUG_SENSOR_LOG(PSTR("%s_TASK_LIST initialized, now return to main loop"),D_CMND_HM10); + } + return; +} + +/** + * @brief convert Mac-String to byte array + * + * @param string Hex-string, must contain 12 chars (no error checking) + * @param _mac Must be a uint8_t[6], filled with zeros + */ + +void HM10MACStringToBytes(const char* string, uint8_t _mac[]) { + uint32_t index = 0; + while (index < 12) { + char c = string[index]; + uint32_t value = 0; + if(c >= '0' && c <= '9') + value = (c - '0'); + else if (c >= 'A' && c <= 'F') + value = (10 + (c - 'A')); + _mac[(index/2)] += value << (((index + 1) % 2) * 4); + // DEBUG_SENSOR_LOG(PSTR("HM10: Char: %c, Value: %x, Index/2: %u, valueadded: %x, MAC-index: %x"), c, value,(index/2),value << (((index + 1) % 2) * 4), _mac[index/2]); + index++; + } + DEBUG_SENSOR_LOG(PSTR("HM10: MAC-array: %x%x%x%x%x%x"),_mac[0],_mac[1],_mac[2],_mac[3],_mac[4],_mac[5]); +} + + +/*********************************************************************************************\ + * parse the response +\*********************************************************************************************/ + +void HM10ParseResponse(char *buf) { + if (!strncmp(buf,"OK",2)) { + DEBUG_SENSOR_LOG(PSTR("HM10: got OK")); + } + if (!strncmp(buf,"HMSoft",6)) { //8 + const char* _fw = "000"; + memcpy((void *)_fw,(void *)(buf+8),3); + HM10.firmware = atoi(_fw); + DEBUG_SENSOR_LOG(PSTR("HM10: Firmware: %d"), HM10.firmware); + return; + } + char * _pos = strstr(buf, "IS0:"); + if(_pos) { + const char* _mac = "000000000000"; + memcpy((void *)_mac,(void *)(_pos+4),12); + DEBUG_SENSOR_LOG(PSTR("HM10: found Mac: %s"), _mac); + uint8_t _newMacArray[6] = {0}; + HM10MACStringToBytes(_mac, _newMacArray); + DEBUG_SENSOR_LOG(PSTR("HM10: MAC-array: %x%x%x%x%x%x"),_newMacArray[0],_newMacArray[1],_newMacArray[2],_newMacArray[3],_newMacArray[4],_newMacArray[5]); + MIBLEgetSensorSlot(_newMacArray, 0xff); + } + if (strstr(buf, "LOST")){ + HM10.mode.connected = false; + } + else { + DEBUG_SENSOR_LOG(PSTR("HM10: empty response")); + } +} + +void HM10readTempHum(char *_buf){ + DEBUG_SENSOR_LOG(PSTR("HM10: raw data: %x%x%x%x%x%x%x"),_buf[0],_buf[1],_buf[2],_buf[3],_buf[4],_buf[5],_buf[6]); + if(_buf[0] != 0 && _buf[1] != 0){ + memcpy(&LYWSD0x_HT,(void *)_buf,3); + DEBUG_SENSOR_LOG(PSTR("HM10: Temperature * 100: %u, Humidity: %u"),LYWSD0x_HT.temp,LYWSD0x_HT.hum); + uint32_t _slot = HM10.state.sensor; + + DEBUG_SENSOR_LOG(PSTR("MIBLE: Sensor slot: %u"), _slot); + static float _tempFloat; + _tempFloat=(float)(LYWSD0x_HT.temp)/100.0f; + if(_tempFloat<60){ + MIBLEsensors.at(_slot).temp=_tempFloat; + HM10.mode.awaitingHT = false; + HM10.current_task_delay = 0; + } + _tempFloat=(float)LYWSD0x_HT.hum; + if(_tempFloat<100){ + MIBLEsensors.at(_slot).hum = _tempFloat; + DEBUG_SENSOR_LOG(PSTR("LYWSD03: hum updated")); + } + } +} + +bool HM10readBat(char *_buf){ + DEBUG_SENSOR_LOG(PSTR("HM10: raw data: %x%x%x%x%x%x%x"),_buf[0],_buf[1],_buf[2],_buf[3],_buf[4],_buf[5],_buf[6]); + if(_buf[0] != 0){ + DEBUG_SENSOR_LOG(PSTR("HM10: Battery: %u"),_buf[0]); + uint32_t _slot = HM10.state.sensor; + DEBUG_SENSOR_LOG(PSTR("MIBLE: Sensor slot: %u"), _slot); + if(_buf[0]<101){ + MIBLEsensors.at(_slot).bat=_buf[0]; + return true; + } + } + return false; +} + +/*********************************************************************************************\ + * handle the return value from the HM10 +\*********************************************************************************************/ + +bool HM10SerialHandleFeedback(){ // every 50 milliseconds + bool success = false; + uint32_t i = 0; + char ret[HM10_MAX_RX_BUF] = {0}; // reset array with zeros + + + while(HM10Serial->available()) { + // delay(0); + if(iread(); + } + i++; + success = true; + } + if(HM10.mode.awaitingHT) { + if (HM10.mode.connected) HM10readTempHum(ret); + } + else if(HM10.mode.awaitingB) { + if (HM10.mode.connected) { + if (HM10readBat(ret)){ + HM10.mode.awaitingB = false; + HM10.current_task_delay = 0; + } + } + } + else if(success) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s response: %s"),D_CMND_HM10, (char *)ret); + HM10ParseResponse(ret); + } + else { + // DEBUG_SENSOR_LOG(PSTR("%s got no response"),D_CMND_HM10); + } + return success; +} + +/*********************************************************************************************\ + * execute the next Task +\*********************************************************************************************/ + +void HM10_TaskEvery100ms(){ + if (HM10.current_task_delay == 0) { + uint8_t i = 0; + bool runningTaskLoop = true; + while (runningTaskLoop) { // always iterate through the whole task list + switch(HM10_TASK_LIST[i][0]) { // handle the kind of task + case TASK_HM10_ROLE1: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s set role to 1"),D_CMND_HM10); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+ROLE1"); + break; + case TASK_HM10_IMME1: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s set imme to 1"),D_CMND_HM10); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+IMME1"); + break; + case TASK_HM10_DISC: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s start discovery"),D_CMND_HM10); + HM10.current_task_delay = 35; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+DISC?"); + break; + case TASK_HM10_VERSION: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s read version"),D_CMND_HM10); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+VERR?"); + break; + case TASK_HM10_NAME: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s read name"),D_CMND_HM10); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+NAME?"); + break; + case TASK_HM10_CONN: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s connect"),D_CMND_HM10); + HM10.current_task_delay = 2; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + char _con[20]; + sprintf_P(_con,"AT+CON%02x%02x%02x%02x%02x%02x",MIBLEsensors.at(HM10.state.sensor).serial[0],MIBLEsensors.at(HM10.state.sensor).serial[1],MIBLEsensors.at(HM10.state.sensor).serial[2],MIBLEsensors.at(HM10.state.sensor).serial[3],MIBLEsensors.at(HM10.state.sensor).serial[4],MIBLEsensors.at(HM10.state.sensor).serial[5]); + HM10Serial->write(_con); + HM10.mode.awaitingB = false; + HM10.mode.connected = true; + break; + case TASK_HM10_DISCONN: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s disconnect"),D_CMND_HM10); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT"); + break; + case TASK_HM10_RESET: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s Reset Device"),D_CMND_HM10); + HM10Serial->write("AT+RESET"); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + break; + case TASK_HM10_SUB_L3: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s subscribe"),D_CMND_HM10); + HM10.current_task_delay = 25; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_DELAY_SUB,i); + runningTaskLoop = false; + HM10Serial->write("AT+NOTIFY_ON0037"); + break; + case TASK_HM10_UN_L3: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s un-subscribe"),D_CMND_HM10); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10.mode.awaitingHT = false; + HM10Serial->write("AT+NOTIFYOFF0037"); + break; + case TASK_HM10_SUB_L2: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s subscribe"),D_CMND_HM10); + HM10.current_task_delay = 25; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_DELAY_SUB,i); + runningTaskLoop = false; + HM10Serial->write("AT+NOTIFY_ON003C"); + break; + case TASK_HM10_UN_L2: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s un-subscribe"),D_CMND_HM10); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10.mode.awaitingHT = false; + HM10Serial->write("AT+NOTIFYOFF003C"); + break; + case TASK_HM10_TIME_L2: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s set time"),D_CMND_HM10); + HM10.current_task_delay = 5; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10.time = Rtc.utc_time; + HM10Serial->write("AT+SEND_DATAWR002F"); + HM10Serial->write(HM10.timebuf,4); + HM10Serial->write(Rtc.time_timezone / 60); + AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s Time-string: %x%x%x%x%x"),D_CMND_HM10, HM10.timebuf[0],HM10.timebuf[1],HM10.timebuf[2],HM10.timebuf[3],(Rtc.time_timezone /60)); + break; + case TASK_HM10_READ_HT: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s read handle 0036"),D_CMND_HM10); + HM10.current_task_delay = 0; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+READDATA0036?"); + HM10.mode.awaitingHT = true; + break; + case TASK_HM10_READ_BT_L3: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s read handle 003A"),D_CMND_HM10); + HM10.current_task_delay = 2; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+READDATA003A?"); + HM10.mode.awaitingB = true; + break; + case TASK_HM10_READ_BT_L2: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s read handle 0043"),D_CMND_HM10); + HM10.current_task_delay = 2; // set task delay + HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + runningTaskLoop = false; + HM10Serial->write("AT+READDATA0043?"); + HM10.mode.awaitingB = true; + break; + // case TASK_HM10_FINDALLCHARS: + // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s find all chars"),D_CMND_HM10); + // HM10.current_task_delay = 5; // set task delay + // HM10_TaskReplaceInSlot(TASK_HM10_FEEDBACK,i); + // runningTaskLoop = false; + // HM10Serial->write("AT+FINDALLCHARS?"); + // break; + case TASK_HM10_FEEDBACK: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s get response"),D_CMND_HM10); + HM10SerialHandleFeedback(); + HM10.current_task_delay = HM10_TASK_LIST[i+1][1];; // set task delay + HM10_TASK_LIST[i][0] = TASK_HM10_DONE; // no feedback for reset + runningTaskLoop = false; + break; + case TASK_HM10_DELAY_SUB: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%s start reading"),D_CMND_HM10); + HM10SerialHandleFeedback(); + HM10.current_task_delay = HM10_TASK_LIST[i+1][1];; // set task delay + HM10_TASK_LIST[i][0] = TASK_HM10_DONE; // no feedback for reset + HM10.mode.awaitingHT = true; + runningTaskLoop = false; + break; + case TASK_HM10_DONE: // this entry was already handled + // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%sFound done HM10_TASK"),D_CMND_HM10); + // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("%snext slot:%u, i: %u"),D_CMND_HM10, HM10_TASK_LIST[i+1][0],i); + if(HM10_TASK_LIST[i+1][0] == TASK_HM10_NOTASK) { // check the next entry and if there is none + DEBUG_SENSOR_LOG(PSTR("%sno Tasks left"),D_CMND_HM10); + DEBUG_SENSOR_LOG(PSTR("%sHM10_TASK_DONE current slot %u"),D_CMND_HM10, i); + for (uint8_t j = 0; j < HM10_MAX_TASK_NUMBER+1; j++) { // do a clean-up: + DEBUG_SENSOR_LOG(PSTR("%sHM10_TASK cleanup slot %u"),D_CMND_HM10, j); + HM10_TASK_LIST[j][0] = TASK_HM10_NOTASK; // reset all task entries + HM10_TASK_LIST[j][1] = 0; // reset all delays + } + runningTaskLoop = false; // return to main loop + HM10.mode.pending_task = 0; // back to main loop control + break; + } + } + i++; + } + } + else { + HM10.current_task_delay--; // count down every 100 ms + } +} + +/** + * @brief Main loop of the driver, "high level"-loop + * + */ + +void HM10EverySecond(){ + if(HM10.firmware == 0) return; + if(HM10.mode.pending_task == 1) return; + if (MIBLEsensors.size()==0) return; + + static uint32_t _counter = 0; + static uint32_t _nextSensorSlot = 0; + if(_counter==0) { + HM10.state.sensor = _nextSensorSlot; + _nextSensorSlot++; + if(MIBLEsensors.at(HM10.state.sensor).type==LYWSD03MMC) { + HM10.mode.pending_task = 1; + HM10_Read_LYWSD03(); + } + if(MIBLEsensors.at(HM10.state.sensor).type==LYWSD02) { + HM10.mode.pending_task = 1; + HM10_Read_LYWSD02(); + } + if (HM10.state.sensor==MIBLEsensors.size()-1) { + _nextSensorSlot= 0; + _counter++; + } + DEBUG_SENSOR_LOG(PSTR("%s active sensor now: %u"),D_CMND_HM10, HM10.state.sensor); + } + else _counter++; + if (_counter>HM10.period) _counter = 0; +} + +bool HM10Cmd(void) { + char command[CMDSZ]; + bool serviced = true; + uint8_t disp_len = strlen(D_CMND_HM10); + + if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_HM10), disp_len)) { // prefix + uint32_t command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + disp_len, kHM10_Commands); + switch (command_code) { + case CMND_HM10_PERIOD: + if (XdrvMailbox.data_len > 0) { + if (command_code == CMND_HM10_PERIOD) { HM10.period = XdrvMailbox.payload; } + } + else { + if (command_code == CMND_HM10_PERIOD) XdrvMailbox.payload = HM10.period; + } + Response_P(S_JSON_HM10_COMMAND_NVALUE, command, XdrvMailbox.payload); + break; + case CMND_HM10_BAUD: + if (XdrvMailbox.data_len > 0) { + if (command_code == CMND_HM10_BAUD) { + HM10.serialSpeed = XdrvMailbox.payload; + HM10Serial->begin(HM10.serialSpeed); + } + } + else { + if (command_code == CMND_HM10_BAUD) XdrvMailbox.payload = HM10.serialSpeed; + } + Response_P(S_JSON_HM10_COMMAND_NVALUE, command, XdrvMailbox.payload); + break; + case CMND_HM10_TIME: + if (XdrvMailbox.data_len > 0) { + if(MIBLEsensors.size()>XdrvMailbox.payload){ + if(MIBLEsensors.at(XdrvMailbox.payload).type == LYWSD02){ + HM10.state.sensor = XdrvMailbox.payload; + HM10_Time_LYWSD02(); + } + } + } + Response_P(S_JSON_HM10_COMMAND_NVALUE, command, XdrvMailbox.payload); + break; + case CMND_HM10_AT: + HM10Serial->write("AT"); // without an argument this will disconnect + if (strlen(XdrvMailbox.data)!=0) { + HM10Serial->write("+"); + HM10Serial->write(XdrvMailbox.data); // pass everything without checks + Response_P(S_JSON_HM10_COMMAND, ":AT+",XdrvMailbox.data); + } + else Response_P(S_JSON_HM10_COMMAND, ":AT",XdrvMailbox.data); + break; + case CMND_HM10_DISC_SCAN: + if (command_code == CMND_HM10_DISC_SCAN) { HM10_Discovery_Scan(); } + Response_P(S_JSON_HM10_COMMAND, command, ""); + break; + default: + // else for Unknown command + serviced = false; + break; + } + } else { + return false; + } + return serviced; +} + + +/*********************************************************************************************\ + * Presentation +\*********************************************************************************************/ + +const char HTTP_HM10[] PROGMEM = "{s}HM10" " Firmware " "{m}%u{e}"; +const char HTTP_HM10_SERIAL[] PROGMEM = "{s}%s %s{m}%02x:%02x:%02x:%02x:%02x:%02x%{e}"; +const char HTTP_BATTERY[] PROGMEM = "{s}%s" " Battery" "{m}%u%%{e}"; +const char HTTP_HM10_FLORA_DATA[] PROGMEM = "{s}%s" " Fertility" "{m}%sus/cm{e}"; +const char HTTP_HM10_HL[] PROGMEM = "{s}
{m}
{e}"; + +void HM10Show(bool json) +{ + if (json) { + for (uint32_t i = 0; i < MIBLEsensors.size(); i++) { + char slave[33]; + sprintf_P(slave,"%s-%02x%02x%02x",kHM10SlaveType[MIBLEsensors.at(i).type-1],MIBLEsensors.at(i).serial[3],MIBLEsensors.at(i).serial[4],MIBLEsensors.at(i).serial[5]); + char temperature[33]; // all sensors have temperature + dtostrfd(MIBLEsensors.at(i).temp, Settings.flag2.temperature_resolution, temperature); + + ResponseAppend_P(PSTR(",\"%s\":{"),slave); + if(MIBLEsensors.at(i).temp!=-1000.0f){ // this is the error code -> no temperature + ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "\":%s"), temperature); + } + if (MIBLEsensors.at(i).type==FLORA){ + char lux[33]; + char moisture[33]; + char fertility[33]; + dtostrfd((float)MIBLEsensors.at(i).lux, 0, lux); + dtostrfd(MIBLEsensors.at(i).moisture, 0, moisture); + dtostrfd(MIBLEsensors.at(i).fertility, 0, fertility); + if(MIBLEsensors.at(i).lux!=0xffff){ // this is the error code -> no temperature + ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%s"), lux); + } + if(MIBLEsensors.at(i).moisture!=-1000.0f){ // this is the error code -> no moisture + ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":%s"), moisture); + } + if(MIBLEsensors.at(i).fertility!=-1000.0f){ // this is the error code -> no fertility + ResponseAppend_P(PSTR(",\"Fertility\":%s"), fertility); + } + } + if (MIBLEsensors.at(i).type>FLORA){ + char humidity[33]; + dtostrfd(MIBLEsensors.at(i).hum, Settings.flag2.humidity_resolution, humidity); + if(MIBLEsensors.at(i).hum!=-1.0f){ // this is the error code -> no humidity + ResponseAppend_P(PSTR(",\"" D_JSON_HUMIDITY "\":%s"), humidity); + } + if(MIBLEsensors.at(i).bat!=0xff){ // this is the error code -> no battery + ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors.at(i).bat); + } + } + ResponseAppend_P(PSTR("}")); + } +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_HM10, HM10.firmware); + for (uint32_t i = 0; i < MIBLEsensors.size(); i++) { + WSContentSend_PD(HTTP_HM10_HL); + WSContentSend_PD(HTTP_HM10_SERIAL, kHM10SlaveType[MIBLEsensors.at(i).type-1], D_MAC_ADDRESS, MIBLEsensors.at(i).serial[0], MIBLEsensors.at(i).serial[1],MIBLEsensors.at(i).serial[2],MIBLEsensors.at(i).serial[3],MIBLEsensors.at(i).serial[4],MIBLEsensors.at(i).serial[5]); + if(MIBLEsensors.at(i).temp!=-1000.0f){ + char temperature[33]; + dtostrfd(MIBLEsensors.at(i).temp, Settings.flag2.temperature_resolution, temperature); + WSContentSend_PD(HTTP_SNS_TEMP, kHM10SlaveType[MIBLEsensors.at(i).type-1], temperature, TempUnit()); + } + if (MIBLEsensors.at(i).type==FLORA){ + if(MIBLEsensors.at(i).lux!=0xffff){ // this is the error code -> no valid value + WSContentSend_PD(HTTP_SNS_ILLUMINANCE, kHM10SlaveType[MIBLEsensors.at(i).type-1], MIBLEsensors.at(i).lux); + } + if(MIBLEsensors.at(i).moisture!=-1000.0f){ // this is the error code -> no valid value + WSContentSend_PD(HTTP_SNS_MOISTURE, kHM10SlaveType[MIBLEsensors.at(i).type-1], MIBLEsensors.at(i).moisture); + } + if(MIBLEsensors.at(i).fertility!=-1000.0f){ // this is the error code -> no valid value + char fertility[33]; + dtostrfd(MIBLEsensors.at(i).fertility, 0, fertility); + WSContentSend_PD(HTTP_HM10_FLORA_DATA, kHM10SlaveType[MIBLEsensors.at(i).type-1], fertility); + } + } + if (MIBLEsensors.at(i).type>FLORA){ // everything "above" Flora + if(MIBLEsensors.at(i).hum!=-1.0f){ // this is the error code -> no humidity + char humidity[33]; + dtostrfd(MIBLEsensors.at(i).hum, Settings.flag2.humidity_resolution, humidity); + WSContentSend_PD(HTTP_SNS_HUM, kHM10SlaveType[MIBLEsensors.at(i).type-1], humidity); + } + if(MIBLEsensors.at(i).bat!=0xff){ + WSContentSend_PD(HTTP_BATTERY, kHM10SlaveType[MIBLEsensors.at(i).type-1], MIBLEsensors.at(i).bat); + } + } + } +#endif // USE_WEBSERVER + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns62(uint8_t function) +{ + bool result = false; + + if ((pin[GPIO_HM10_RX] < 99) && (pin[GPIO_HM10_TX] < 99)) { + switch (function) { + case FUNC_INIT: + HM10SerialInit(); // init and start communication + break; + case FUNC_EVERY_50_MSECOND: + HM10SerialHandleFeedback(); // check for device feedback very often + break; + case FUNC_EVERY_100_MSECOND: + if (HM10_TASK_LIST[0][0] != TASK_HM10_NOTASK) { + HM10_TaskEvery100ms(); // something has to be done, we'll check in the next step + } + break; + case FUNC_EVERY_SECOND: + HM10EverySecond(); + break; + case FUNC_COMMAND: + result = HM10Cmd(); + break; + case FUNC_JSON_APPEND: + HM10Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + HM10Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} +#endif //USE_HM10 \ No newline at end of file diff --git a/tasmota/xsns_91_prometheus.ino b/tasmota/xsns_91_prometheus.ino index ff18f4e70..ea4c0047a 100644 --- a/tasmota/xsns_91_prometheus.ino +++ b/tasmota/xsns_91_prometheus.ino @@ -56,7 +56,7 @@ void HandleMetrics(void) dtostrfd(Energy.current[0], Settings.flag2.current_resolution, parameter); WSContentSend_P(PSTR("# TYPE current gauge\ncurrent %s\n"), parameter); dtostrfd(Energy.active_power[0], Settings.flag2.wattage_resolution, parameter); - WSContentSend_P(PSTR("# TYPE active_power guage\nactive_power %s\n"), parameter); + WSContentSend_P(PSTR("# TYPE active_power gauge\nactive_power %s\n"), parameter); dtostrfd(Energy.daily, Settings.flag2.energy_resolution, parameter); WSContentSend_P(PSTR("# TYPE energy_daily gauge\nenergy_daily %s\n"), parameter); dtostrfd(Energy.total, Settings.flag2.energy_resolution, parameter); diff --git a/tools/decode-status.py b/tools/decode-status.py index 01319d9e4..2acee4923 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -136,7 +136,10 @@ a_setoption = [[ "Enable shutter support", "Invert PCF8574 ports" ],[ - "","","","", + "Reduced CT range for Alexa", + "Use FriendlyNames instead of ShortAddresses when possible", + "(AWS IoT) publish MQTT state to a device shadow", + "", "","","","", "","","","", "","","","", @@ -189,7 +192,7 @@ a_features = [[ "USE_SONOFF_SC","USE_SONOFF_RF","USE_SONOFF_L1","USE_EXS_DIMMER", "USE_ARDUINO_SLAVE","USE_HIH6","USE_HPMA","USE_TSL2591", "USE_DHT12","USE_DS1624","USE_GPS","USE_HOTPLUG", - "","","","", + "USE_NRF24","USE_MIBLE","USE_HM10","", "","","","" ]] @@ -224,7 +227,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v20190819 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v20200207 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj))