From 711901c5871474b650de0c94195e9639d404df70 Mon Sep 17 00:00:00 2001 From: sillyfrog <816454+sillyfrog@users.noreply.github.com> Date: Sat, 15 Jun 2019 18:32:05 +1000 Subject: [PATCH] Scrape Supported Protocols and generate SupportedProtocols.md (#755) * Tool to build the document. * Add reference to new doc. * Other - Move existing python unit tests to Python3 - Use Python3's pylint - Fix pylint issues found after move. - Convince CI/Travis to install/use convince Python3 stuff. Fixes #743 --- .gitignore | 3 + .travis.yml | 4 +- .vscode/settings.json | 5 + README.md | 4 + SupportedProtocols.md | 127 ++++++++++++++ src/ir_Gree.h | 2 +- src/ir_Haier.h | 2 +- src/ir_Hitachi.h | 2 +- src/ir_Kelvinator.h | 2 +- src/ir_LG.cpp | 2 +- src/ir_LG.h | 8 +- src/ir_Lego.cpp | 2 +- tools/Makefile | 2 +- tools/auto_analyse_raw_data.py | 8 +- tools/auto_analyse_raw_data_test.py | 28 +-- tools/scrape_supported_devices.py | 255 ++++++++++++++++++++++++++++ 16 files changed, 422 insertions(+), 34 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 SupportedProtocols.md create mode 100755 tools/scrape_supported_devices.py 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()