diff --git a/.gitignore b/.gitignore
index 1b1e81bb..4441365b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,9 @@
# vi/vim
**/*.swp
+# vscode
+.vscode
+
## Build environments
# Platformio
**/.pio/
diff --git a/.travis.yml b/.travis.yml
index 8b102e2d..3ade79b7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -22,7 +22,7 @@ install:
- arduino --pref "compiler.warning_level=all" --save-prefs
- sudo apt-get install jq
- sudo apt-get purge python-enum34
- - sudo pip install pylint
+ - sudo apt-get install pylint3
script:
# Check that everything compiles.
- arduino --verify --board $BD $PWD/examples/IRrecvDemo/IRrecvDemo.ino
@@ -51,7 +51,7 @@ script:
# Check for lint issues.
- shopt -s nullglob
- python cpplint.py --extensions=c,cc,cpp,ino --headers=h,hpp {src,test,tools}/*.{h,c,cc,cpp,hpp,ino} examples/*/*.{h,c,cc,cpp,hpp,ino}
- - pylint {src,test,tools}/*.py
+ - pylint3 -d F0001 {src,test,tools}/*.py
- shopt -u nullglob
# Build and run the unit tests.
- (cd test; make run)
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..1460defe
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "python.linting.pylintEnabled": true,
+ "python.linting.flake8Enabled": false,
+ "python.formatting.provider": "yapf"
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 3944a6e8..025e7248 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,10 @@ something you likely should not have. You should be able to quickly determine
the new name from the old. e.g. `CONSTANT_NAME` to `kConstantName`.
Use common sense or examining the library's code if this does affect code.
+## Supported protocols
+You can find the details of which protocols & devices are supported
+[here](https://github.com/markszabo/IRremoteESP8266/blob/master/SupportedProtocols.md).
+
## Troubleshooting
Before reporting an issue or asking for help, please try to follow our [Troubleshooting Guide](https://github.com/markszabo/IRremoteESP8266/wiki/Troubleshooting-Guide) first.
diff --git a/SupportedProtocols.md b/SupportedProtocols.md
new file mode 100644
index 00000000..563e901e
--- /dev/null
+++ b/SupportedProtocols.md
@@ -0,0 +1,127 @@
+
+# IR Protocols supported by this library
+
+| Protocol | Brand | Model | A/C Model | Detailed A/C Support |
+| --- | --- | --- | --- | --- |
+| [Aiwa](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Aiwa.cpp) | **Aiwa** | RC-T501 RCU | | - |
+| [Argo](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Argo.cpp) | **[Argo](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Argo.h)** | Ulisse 13 DCI Mobile Split A/C | | Yes |
+| [Carrier](https://github.com/markszabo/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/markszabo/IRremoteESP8266/blob/master/src/ir_Coolix.cpp) | **[Unknown](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Coolix.h)** | | | Yes |
+| [Daikin](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Daikin.cpp) | **[Daikin](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Daikin.h)** | ARC433** remote
ARC433B69 remote
ARC477A1 remote
FTXZ25NV1B A/C
FTXZ35NV1B A/C
FTXZ50NV1B A/C | | Yes |
+| [Denon](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Denon.cpp) | **Unknown** | | | - |
+| [Dish](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Dish.cpp) | **DISH NETWORK** | echostar 301 | | - |
+| [Electra](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Electra.cpp) | **Unknown** | | | - |
+| [Fujitsu](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AR-DB1 remote
AR-RAE1E remote
AR-RAH2E remote
AR-REB1E remote
AST9RSGCW A/C
ASYG30LFCA A/C
ASYG7LMCA A/C | ARDB1
ARJW2
ARRAH2E
ARREB1E | Yes |
+| [Fujitsu](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Fujitsu.cpp) | **[Fujitsu General](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Fujitsu.h)** | AR-JW2 remote | ARDB1
ARJW2
ARRAH2E
ARREB1E | Yes |
+| [GICable](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_GICable.cpp) | **Unknown** | | | - |
+| [GlobalCache](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_GlobalCache.cpp) | **Unknown** | | | - |
+| [Goodweather](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Goodweather.cpp) | **[Goodweather](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Goodweather.h)** | ZH/JT-03 remote | | Yes |
+| [Gree](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[EKOKAI](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Gree.h)** | A/C | | Yes |
+| [Gree](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Gree.cpp) | **[Ultimate](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Gree.h)** | Heat Pump | | Yes |
+| [Haier](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Haier.cpp) | **[Haier](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Haier.h)** | HSU-09HMC203 A/C
HSU07-HEA03 remote
YR-W02 remote | | Yes |
+| [Hitachi](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Hitachi.cpp) | **[Hitachi](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Hitachi.h)** | LT0541-HTA remote
RAS-35THA6 remote
Series VI A/C (Circa 2007) | | Yes |
+| [Inax](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Inax.cpp) | **Lixil** | Inax DT-BA283 Toilet | | - |
+| [JVC](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_JVC.cpp) | **Unknown** | | | - |
+| [Kelvinator](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Kelvinator.cpp) | **[Kelvinator](https://github.com/markszabo/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/markszabo/IRremoteESP8266/blob/master/src/ir_LG.cpp) | **[LG](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_LG.h)** | 6711A20083V remote
6711A20083V remote
AKB74395308 remote
AKB74395308 remote | | Yes |
+| [Lasertag](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Lasertag.cpp) | **Unknown** | | | - |
+| [Lego](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Lego.cpp) | **LEGO Power Functions** | IR Receiver | | - |
+| [Lutron](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Lutron.cpp) | **Unknown** | | | - |
+| [MWM](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_MWM.cpp) | **Unknown** | | | - |
+| [Magiquest](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Magiquest.cpp) | **[Unknown](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Magiquest.h)** | | | Yes |
+| [Midea](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Midea.cpp) | **[Pioneer System](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Midea.h)** | RUBO18GMFILCAD A/C (18K BTU)
RYBO12GMFILCAD A/C (12K BTU) | | Yes |
+| [Mitsubishi](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Mitsubishi.cpp) | **[Mitsubishi](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Mitsubishi.h)** | HC3000 Projector
TV | | Yes |
+| [MitsubishiHeavy](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_MitsubishiHeavy.cpp) | **[Mitsubishi Heavy Industries](https://github.com/markszabo/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/markszabo/IRremoteESP8266/blob/master/src/ir_NEC.cpp) | **[Unknown](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_NEC.h)** | | | Yes |
+| [Nikai](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Nikai.cpp) | **Unknown** | | | - |
+| [Panasonic](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Panasonic.cpp) | **[Panasonic](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Panasonic.h)** | A75C2311 remote (CKP)
A75C3704 remote
A75C3747 remote
A75C3747 remote
A75C3747 remote
A75C3747 remote
CKP series A/C
CS-ME10CKPG A/C
CS-ME12CKPG A/C
CS-ME14CKPG A/C
CS-YW9MKD A/C
CS-Z9RKR A/C
DKE series A/C
JKE series A/C
NKE series A/C
RKR series A/C
TV | CKP
DKE
JKE
LKE
NKE
RKR | Yes |
+| [Pioneer](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Pioneer.cpp) | **Unknown** | | | - |
+| [Pronto](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Pronto.cpp) | **Unknown** | | | - |
+| [RC5_RC6](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_RC5_RC6.cpp) | **Unknown** | | | - |
+| [RCMM](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_RCMM.cpp) | **Microsoft** | XBOX 360 | | - |
+| [Samsung](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Samsung.cpp) | **[Samsung](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Samsung.h)** | AR12KSFPEWQNET A/C
IEC-R03 remote
UA55H6300 TV | | Yes |
+| [Sanyo](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Sanyo.cpp) | **Unknown** | | | - |
+| [Sharp](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Sharp.cpp) | **[Sharp](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Sharp.h)** | AY-ZP40KR A/C
LC-52D62U TV | | Yes |
+| [Sherwood](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Sherwood.cpp) | **Sherwood** | RC-138 remote
RD6505(B) Receiver | | - |
+| [Sony](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Sony.cpp) | **Unknown** | | | - |
+| [Tcl](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Tcl.cpp) | **[Unknown](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Tcl.h)** | | | Yes |
+| [Teco](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Teco.cpp) | **[Unknown](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Teco.h)** | | | Yes |
+| [Toshiba](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Toshiba.cpp) | **[Toshiba](https://github.com/markszabo/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/markszabo/IRremoteESP8266/blob/master/src/ir_Trotec.cpp) | **[Unknown](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Trotec.h)** | | | Yes |
+| [Vestel](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Vestel.cpp) | **[Vestel](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Vestel.h)** | BIOX CXP-9 A/C (9K BTU) | | Yes |
+| [Whirlpool](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Whirlpool.cpp) | **[Whirlpool](https://github.com/markszabo/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/markszabo/IRremoteESP8266/blob/master/src/ir_Whynter.cpp) | **Whynter** | ARC-110WD A/C | | - |
+
+
+## Send only protocols:
+
+- GLOBALCACHE
+- PRONTO
+- RAW
+- SHERWOOD
+
+
+## Send & decodable protocols:
+
+- AIWA_RC_T501
+- ARGO
+- CARRIER_AC
+- COOLIX
+- DAIKIN
+- DAIKIN2
+- DAIKIN216
+- DENON
+- DISH
+- ELECTRA_AC
+- FUJITSU_AC
+- GICABLE
+- GOODWEATHER
+- GREE
+- HAIER_AC
+- HAIER_AC_YRW02
+- HITACHI_AC
+- HITACHI_AC1
+- HITACHI_AC2
+- INAX
+- JVC
+- KELVINATOR
+- LASERTAG
+- LEGOPF
+- LG
+- LG2
+- LUTRON
+- MAGIQUEST
+- MIDEA
+- MITSUBISHI
+- MITSUBISHI2
+- MITSUBISHI_AC
+- MITSUBISHI_HEAVY_152
+- MITSUBISHI_HEAVY_88
+- MWM
+- NEC
+- NEC_LIKE
+- NIKAI
+- PANASONIC
+- PANASONIC_AC
+- PIONEER
+- RC5
+- RC5X
+- RC6
+- RCMM
+- SAMSUNG
+- SAMSUNG36
+- SAMSUNG_AC
+- SANYO
+- SANYO_LC7461
+- SHARP
+- SHARP_AC
+- SONY
+- TCL112AC
+- TECO
+- TOSHIBA_AC
+- TROTEC
+- VESTEL_AC
+- WHIRLPOOL_AC
+- WHYNTER
diff --git a/src/ir_Gree.h b/src/ir_Gree.h
index f508b737..409d2511 100644
--- a/src/ir_Gree.h
+++ b/src/ir_Gree.h
@@ -1,7 +1,7 @@
// Copyright 2016 David Conran
// Gree A/C
//
-// Supported:
+// Supports:
// Brand: Ultimate, Model: Heat Pump
// Brand: EKOKAI, Model: A/C
diff --git a/src/ir_Haier.h b/src/ir_Haier.h
index e9386531..bd9ef8f2 100644
--- a/src/ir_Haier.h
+++ b/src/ir_Haier.h
@@ -1,7 +1,7 @@
// Copyright 2018 crankyoldgit
// The specifics of reverse engineering the protocol details by kuzin2006
-// Supported:
+// Supports:
// Brand: Haier, Model: HSU07-HEA03 remote
// Brand: Haier, Model: YR-W02 remote
// Brand: Haier, Model: HSU-09HMC203 A/C
diff --git a/src/ir_Hitachi.h b/src/ir_Hitachi.h
index f48d368a..308632ef 100644
--- a/src/ir_Hitachi.h
+++ b/src/ir_Hitachi.h
@@ -2,7 +2,7 @@
//
// Copyright 2018 David Conran
-// Supported:
+// Supports:
// Brand: Hitachi, Model: RAS-35THA6 remote
// Brand: Hitachi, Model: LT0541-HTA remote
// Brand: Hitachi, Model: Series VI A/C (Circa 2007)
diff --git a/src/ir_Kelvinator.h b/src/ir_Kelvinator.h
index dcee295f..b35f9517 100644
--- a/src/ir_Kelvinator.h
+++ b/src/ir_Kelvinator.h
@@ -2,7 +2,7 @@
//
// Copyright 2016 David Conran
-// Supported:
+// Supports:
// Brand: Kelvinator, Model: YALIF Remote
// Brand: Kelvinator, Model: KSV26CRC A/C
// Brand: Kelvinator, Model: KSV26HRC A/C
diff --git a/src/ir_LG.cpp b/src/ir_LG.cpp
index 59a924c5..ded6fefa 100644
--- a/src/ir_LG.cpp
+++ b/src/ir_LG.cpp
@@ -2,7 +2,7 @@
// Copyright 2015 cheaplin
// Copyright 2017, 2018 David Conran
-// Supported:
+// Supports:
// Brand: LG, Model: 6711A20083V remote
// Brand: LG, Model: AKB74395308 remote
diff --git a/src/ir_LG.h b/src/ir_LG.h
index 42eca119..01f81e2c 100644
--- a/src/ir_LG.h
+++ b/src/ir_LG.h
@@ -1,18 +1,12 @@
// Copyright 2017 David Conran
-// Supported:
+// Supports:
// Brand: LG, Model: 6711A20083V remote
// Brand: LG, Model: AKB74395308 remote
#ifndef IR_LG_H_
#define IR_LG_H_
-// L GGGG
-// L G
-// L G GG
-// L G G
-// LLLLL GGG
-
#define __STDC_LIMIT_MACROS
#include
diff --git a/src/ir_Lego.cpp b/src/ir_Lego.cpp
index f23d1c53..726b6cd4 100644
--- a/src/ir_Lego.cpp
+++ b/src/ir_Lego.cpp
@@ -8,7 +8,7 @@
// LEGO
// (LEGO is a Registrated Trademark of the Lego Group.)
//
-// Supported:
+// Supports:
// Brand: LEGO Power Functions, Model: IR Receiver
//
// Ref:
diff --git a/tools/Makefile b/tools/Makefile
index fe199a2a..129279ec 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -29,7 +29,7 @@ run_tests : all
failed=""; \
for py_unittest in *_test.py; do \
echo "RUNNING: $${py_unittest}"; \
- python ./$${py_unittest} || failed="$${failed} $${py_unittest}"; \
+ python3 ./$${py_unittest} || failed="$${failed} $${py_unittest}"; \
done; \
if [ -n "$${failed}" ]; then \
echo "FAIL: :-( :-( Unit test(s)$${failed} failed! :-( :-("; exit 1; \
diff --git a/tools/auto_analyse_raw_data.py b/tools/auto_analyse_raw_data.py
index b23cdb46..8a2e4579 100755
--- a/tools/auto_analyse_raw_data.py
+++ b/tools/auto_analyse_raw_data.py
@@ -8,7 +8,7 @@ import argparse
import sys
-class RawIRMessage(object):
+class RawIRMessage():
"""Basic analyse functions & structure for raw IR messages."""
# pylint: disable=too-many-instance-attributes
@@ -62,7 +62,7 @@ class RawIRMessage(object):
def _usec_compare(self, seen, expected):
"""Compare two usec values and see if they match within a
subtractive margin."""
- return seen <= expected and seen > expected - self.margin
+ return expected - self.margin < seen <= expected
def _usec_compares(self, usecs, expecteds):
"""Compare a usec value to a list of values and return True
@@ -160,7 +160,7 @@ class RawIRMessage(object):
def avg_list(items):
"""Return the average of a list of numbers."""
if items:
- return sum(items) / len(items)
+ return int(sum(items) / len(items))
return 0
@@ -293,7 +293,7 @@ def decode_data(message, defines, function_code, output=sys.stdout):
output.write("kHdrSpace+")
function_code.append(" space(kHdrSpace);")
elif message.is_bit_mark(usec) and count % 2:
- if state != "HS" and state != "BS":
+ if state not in ("HS", "BS"):
output.write("kBitMark(UNEXPECTED)")
state = "BM"
elif message.is_zero_space(usec):
diff --git a/tools/auto_analyse_raw_data_test.py b/tools/auto_analyse_raw_data_test.py
index 681ff552..5d5504ff 100755
--- a/tools/auto_analyse_raw_data_test.py
+++ b/tools/auto_analyse_raw_data_test.py
@@ -1,6 +1,6 @@
-#!/usr/bin/python
+#!/usr/bin/python3
"""Unit tests for auto_analyse_raw_data.py"""
-import StringIO
+from io import StringIO
import unittest
import auto_analyse_raw_data as analyse
@@ -12,7 +12,7 @@ class TestRawIRMessage(unittest.TestCase):
def test_display_binary(self):
"""Test the display_binary() method."""
- output = StringIO.StringIO()
+ output = StringIO()
message = analyse.RawIRMessage(100, [8000, 4000, 500, 500, 500], output,
False)
self.assertEqual(output.getvalue(), '')
@@ -52,8 +52,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
def test_dump_constants_simple(self):
"""Simple tests for the dump_constants() function."""
- ignore = StringIO.StringIO()
- output = StringIO.StringIO()
+ ignore = StringIO()
+ output = StringIO()
defs = []
message = analyse.RawIRMessage(200, [
7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494,
@@ -75,8 +75,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
def test_dump_constants_aircon(self):
"""More complex tests for the dump_constants() function."""
- ignore = StringIO.StringIO()
- output = StringIO.StringIO()
+ ignore = StringIO()
+ output = StringIO()
defs = []
message = analyse.RawIRMessage(200, [
9008, 4496, 644, 1660, 676, 530, 648, 558, 672, 1636, 646, 1660, 644,
@@ -111,7 +111,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
self.assertEqual(analyse.convert_rawdata("0"), [0])
with self.assertRaises(ValueError) as context:
analyse.convert_rawdata("")
- self.assertEqual(context.exception.message,
+ self.assertEqual(str(context.exception),
"Raw Data contains a non-numeric value of ''.")
# Single parenthesis
@@ -132,13 +132,13 @@ class TestAutoAnalyseRawData(unittest.TestCase):
# Bad parentheses
with self.assertRaises(ValueError) as context:
analyse.convert_rawdata("}10{")
- self.assertEqual(context.exception.message,
+ self.assertEqual(str(context.exception),
"Raw Data not parsible due to parentheses placement.")
# Non base-10 values
with self.assertRaises(ValueError) as context:
analyse.convert_rawdata("10, 20, foo, bar, 30")
- self.assertEqual(context.exception.message,
+ self.assertEqual(str(context.exception),
"Raw Data contains a non-numeric value of 'foo'.")
# A messy usual "good" case.
@@ -155,7 +155,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
"""Tests for the parse_and_report() function."""
# Without code generation.
- output = StringIO.StringIO()
+ output = StringIO()
input_str = """
uint16_t rawbuf[139] = {9008, 4496, 644, 1660, 676, 530, 648, 558, 672,
1636, 646, 1660, 644, 556, 650, 584, 626, 560, 644, 580, 628, 1680,
@@ -210,7 +210,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
'Total Nr. of suspected bits: 67\n')
# With code generation.
- output = StringIO.StringIO()
+ output = StringIO()
input_str = """
uint16_t rawbuf[37] = {7930, 3952, 494, 1482, 520, 1482, 494,
1508, 494, 520, 494, 1482, 494, 520, 494, 1482, 494, 1482, 494,
@@ -294,7 +294,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
"""Tests for unusual Space Gaps in parse_and_report() function."""
# Tests for unusual Gaps. (Issue #482)
- output = StringIO.StringIO()
+ output = StringIO()
input_str = """
uint16_t rawbuf[272] = {3485, 3512, 864, 864, 864, 2620, 864, 864,
864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864,
@@ -466,7 +466,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
def test_reduce_list(self):
"""Tests for the reduce_list method."""
- ignore = StringIO.StringIO()
+ ignore = StringIO()
message = analyse.RawIRMessage(200, [
7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494,
520, 494, 1482, 494, 1482, 494, 3978, 494, 520, 494, 520, 494, 520, 494,
diff --git a/tools/scrape_supported_devices.py b/tools/scrape_supported_devices.py
new file mode 100755
index 00000000..89534904
--- /dev/null
+++ b/tools/scrape_supported_devices.py
@@ -0,0 +1,255 @@
+#!/usr/bin/env python3
+"""Generate SupportedProtocols.md by scraping source code files"""
+import pathlib
+import argparse
+import sys
+import re
+import time
+
+CODE_URL = "https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_"
+
+BRAND_MODEL = re.compile(r"Brand: *(?P.+), *Model: *(?P.+)")
+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")
+
+ALL_FN = re.compile(r"ir_(.+).(h|cpp)")
+
+EXCLUDED_PROTOCOLS = ["UNKNOWN", "UNUSED", "kLastDecodeType"]
+
+MARKDOWN_HEADER = """""".format(time.asctime())
+
+
+def getallprotocols():
+ """Return all protocls configured in IRremoteESP8266.h
+ """
+ irremote = ARGS.directory / "IRremoteESP8266.h"
+ enums = getenums(irremote)
+ if not enums:
+ errorexit("Error getting ENUMS from IRremoteESP8266.h")
+ return enums
+
+
+def getdecodedprotocols():
+ """All protocols that include decoding support"""
+ ret = set()
+ for path in ARGS.directory.iterdir():
+ if path.suffix != ".cpp":
+ continue
+ matches = DECODED_PROTOCOLS.finditer(path.open().read())
+ for match in matches:
+ protocol = match.group(1)
+ if protocol not in EXCLUDED_PROTOCOLS:
+ ret.add(protocol)
+ return ret
+
+
+def getallacs():
+ """All supported A/C codes"""
+ ret = {}
+ for path in ARGS.directory.iterdir():
+ match = AC_FN.match(path.name)
+ if not match:
+ continue
+ acprotocol = match.group(1)
+ rawmodels = getenums(path)
+ models = set()
+ for model in rawmodels:
+ model = model.upper()
+ model = model.replace("K{}".format(acprotocol.upper()), "")
+ if model and model not in EXCLUDED_PROTOCOLS:
+ models.add(model)
+ ret[acprotocol] = models
+ return ret
+
+
+def getalldevices():
+ """All devices and associated branding and model information (if available)
+ """
+ allcodes = {}
+ fnnomatch = set()
+ fnmatch = set()
+ for path in ARGS.directory.iterdir():
+ match = ALL_FN.match(path.name)
+ if not match:
+ continue
+ supports = extractsupports(path)
+ if supports:
+ fnmatch.add(path.stem)
+ else:
+ fnnomatch.add(path.stem)
+ protocol = match.group(1)
+ for brand, model in supports:
+ protocolbrand = (protocol, brand)
+ allcodes[protocolbrand] = allcodes.get(protocolbrand, list()) + [model]
+ nosupports = fnnomatch - fnmatch
+ for fnprotocol in nosupports:
+ allcodes[(fnprotocol[3:], "Unknown")] = []
+ return allcodes, nosupports
+
+
+def getenums(path):
+ """Returns the keys for the first enum type in path
+ """
+ enums = ENUMS.search(path.open().read())
+ ret = set()
+ if not enums:
+ return ret
+ for enum in ENUM_ENTRY.finditer(enums.group(1)):
+ enum = enum.group(1)
+ if enum in EXCLUDED_PROTOCOLS:
+ continue
+ ret.add(enum)
+ return ret
+
+
+ARGS = None
+
+
+def initargs():
+ """Init the command line arguments"""
+ global ARGS # pylint: disable=global-statement
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-s",
+ "--stdout",
+ help="output to stdout rather than SupportedProtocols.md",
+ action="store_true",
+ )
+ parser.add_argument("-v",
+ "--verbose",
+ help="increase output verbosity",
+ action="store_true")
+ parser.add_argument(
+ "-a",
+ "--alert",
+ help="alert if a file does not have a supports section",
+ action="store_true",
+ )
+ parser.add_argument(
+ "directory",
+ nargs="?",
+ help="directory of the source git checkout",
+ default=None,
+ )
+ ARGS = parser.parse_args()
+ if ARGS.directory is None:
+ src = pathlib.Path("../src")
+ if not src.is_dir():
+ src = pathlib.Path("./src")
+ else:
+ src = pathlib.Path(ARGS.directory) / "src"
+ if not src.is_dir():
+ errorexit("Directory not valid: {}".format(str(src)))
+ ARGS.directory = src
+ return ARGS
+
+
+def errorexit(msg):
+ """Print an error and exit on critical error"""
+ sys.stderr.write("{}\n".format(msg))
+ sys.exit(1)
+
+
+def extractsupports(path):
+ """Extract all of the Supports: sections and associated brands and models
+ """
+ supports = []
+ insupports = False
+ for line in path.open():
+ if not line.startswith("//"):
+ continue
+ line = line[2:].strip()
+ if line == "Supports:":
+ insupports = True
+ continue
+ if insupports:
+ match = BRAND_MODEL.match(line)
+ if match:
+ supports.append((match.group("brand"), match.group("model")))
+ else:
+ insupports = False
+ continue
+ return supports
+
+
+def makeurl(txt, path):
+ """Make a Markup URL from given filename"""
+ return "[{}]({})".format(txt, CODE_URL + path)
+
+
+def outputprotocols(fout, protocols):
+ """For a given protocol set, sort and output the markdown"""
+ protocols = list(protocols)
+ protocols.sort()
+ for protocol in protocols:
+ fout.write("- {}\n".format(protocol))
+
+
+def main():
+ """Standard boiler plate"""
+ initargs()
+ if ARGS.verbose:
+ print("Looking for files in: {}".format(str(ARGS.directory.resolve())))
+ if ARGS.stdout:
+ fout = sys.stdout
+ else:
+ foutpath = ARGS.directory / "../SupportedProtocols.md"
+ foutpath = foutpath.resolve()
+ if ARGS.verbose:
+ print("Output path: {}".format(str(foutpath)))
+ fout = foutpath.open("w")
+ decodedprotocols = getdecodedprotocols()
+ sendonly = getallprotocols() - decodedprotocols
+ allacs = getallacs()
+
+ allcodes, nosupports = getalldevices()
+ allbrands = list(allcodes.keys())
+ allbrands.sort()
+
+ fout.write(MARKDOWN_HEADER)
+ fout.write("\n# IR Protocols supported by this library\n\n")
+ fout.write(
+ "| Protocol | Brand | Model | A/C Model | Detailed A/C Support |\n")
+ fout.write("| --- | --- | --- | --- | --- |\n")
+
+ for protocolbrand in allbrands:
+ protocol, brand = protocolbrand
+ codes = allcodes[protocolbrand]
+ codes.sort()
+ if protocol in allacs:
+ acmodels = list(allacs[protocol])
+ acmodels.sort()
+ acsupport = "Yes"
+ brand = makeurl(brand, protocol + ".h")
+ else:
+ acmodels = []
+ acsupport = "-"
+
+ fout.write("| {} | **{}** | {} | {} | {} |\n".format(
+ makeurl(protocol, protocol + ".cpp"),
+ brand,
+ "
".join(codes),
+ "
".join(acmodels),
+ acsupport,
+ ))
+
+ fout.write("\n\n## Send only protocols:\n\n")
+ outputprotocols(fout, sendonly)
+
+ fout.write("\n\n## Send & decodable protocols:\n\n")
+ outputprotocols(fout, decodedprotocols)
+
+ if ARGS.alert:
+ nosupports = list(nosupports)
+ nosupports.sort()
+ print("The following files had no supports section:")
+ for path in nosupports:
+ print("\t{}".format(path))
+
+
+if __name__ == "__main__":
+ main()