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
This commit is contained in:
sillyfrog
2019-06-15 18:32:05 +10:00
committed by David Conran
parent 84e7fdf56f
commit 711901c587
16 changed files with 422 additions and 34 deletions

3
.gitignore vendored
View File

@@ -8,6 +8,9 @@
# vi/vim # vi/vim
**/*.swp **/*.swp
# vscode
.vscode
## Build environments ## Build environments
# Platformio # Platformio
**/.pio/ **/.pio/

View File

@@ -22,7 +22,7 @@ install:
- arduino --pref "compiler.warning_level=all" --save-prefs - arduino --pref "compiler.warning_level=all" --save-prefs
- sudo apt-get install jq - sudo apt-get install jq
- sudo apt-get purge python-enum34 - sudo apt-get purge python-enum34
- sudo pip install pylint - sudo apt-get install pylint3
script: script:
# Check that everything compiles. # Check that everything compiles.
- arduino --verify --board $BD $PWD/examples/IRrecvDemo/IRrecvDemo.ino - arduino --verify --board $BD $PWD/examples/IRrecvDemo/IRrecvDemo.ino
@@ -51,7 +51,7 @@ script:
# Check for lint issues. # Check for lint issues.
- shopt -s nullglob - 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} - 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 - shopt -u nullglob
# Build and run the unit tests. # Build and run the unit tests.
- (cd test; make run) - (cd test; make run)

5
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"python.linting.pylintEnabled": true,
"python.linting.flake8Enabled": false,
"python.formatting.provider": "yapf"
}

View File

@@ -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`. 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. 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 ## 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. Before reporting an issue or asking for help, please try to follow our [Troubleshooting Guide](https://github.com/markszabo/IRremoteESP8266/wiki/Troubleshooting-Guide) first.

127
SupportedProtocols.md Normal file
View File

@@ -0,0 +1,127 @@
<!--- WARNING: Do NOT edit this file directly.
It is generated by './tools/scrape_supported_devices.py'.
Last generated: Sat Jun 15 13:29:53 2019 --->
# 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<BR>53NGK009/012 Inverter<BR>619EGX0090E0 A/C<BR>619EGX0120E0 A/C<BR>619EGX0180E0 A/C<BR>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<BR>ARC433B69 remote<BR>ARC477A1 remote<BR>FTXZ25NV1B A/C<BR>FTXZ35NV1B A/C<BR>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<BR>AR-RAE1E remote<BR>AR-RAH2E remote<BR>AR-REB1E remote<BR>AST9RSGCW A/C<BR>ASYG30LFCA A/C<BR>ASYG7LMCA A/C | ARDB1<BR>ARJW2<BR>ARRAH2E<BR>ARREB1E | Yes |
| [Fujitsu](https://github.com/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<BR>ARJW2<BR>ARRAH2E<BR>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<BR>HSU07-HEA03 remote<BR>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<BR>RAS-35THA6 remote<BR>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<BR>KSV26HRC A/C<BR>KSV35CRC A/C<BR>KSV35HRC A/C<BR>KSV53HRC A/C<BR>KSV62HRC A/C<BR>KSV70CRC A/C<BR>KSV70HRC A/C<BR>KSV80HRC A/C<BR>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<BR>6711A20083V remote<BR>AKB74395308 remote<BR>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)<BR>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<BR>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<BR>RLA502A700B remote<BR>SRKxxZJ-S A/C<BR>SRKxxZM-S A/C<BR>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)<BR>A75C3704 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>A75C3747 remote<BR>CKP series A/C<BR>CS-ME10CKPG A/C<BR>CS-ME12CKPG A/C<BR>CS-ME14CKPG A/C<BR>CS-YW9MKD A/C<BR>CS-Z9RKR A/C<BR>DKE series A/C<BR>JKE series A/C<BR>NKE series A/C<BR>RKR series A/C<BR>TV | CKP<BR>DKE<BR>JKE<BR>LKE<BR>NKE<BR>RKR | Yes |
| [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<BR>IEC-R03 remote<BR>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<BR>LC-52D62U TV | | Yes |
| [Sherwood](https://github.com/markszabo/IRremoteESP8266/blob/master/src/ir_Sherwood.cpp) | **Sherwood** | RC-138 remote<BR>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<BR>RAS 18SKP-ES<BR>RAS-B13N3KV2<BR>RAS-B13N3KVP-E<BR>WC-L03SE<BR>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<BR>DG11J1-3A remote<BR>DG11J1-91 remote<BR>SPIS409L A/C<BR>SPIS412L A/C<BR>SPIW409L A/C<BR>SPIW412L A/C<BR>SPIW418L A/C | DG11J13A<BR>DG11J191 | Yes |
| [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

View File

@@ -1,7 +1,7 @@
// Copyright 2016 David Conran // Copyright 2016 David Conran
// Gree A/C // Gree A/C
// //
// Supported: // Supports:
// Brand: Ultimate, Model: Heat Pump // Brand: Ultimate, Model: Heat Pump
// Brand: EKOKAI, Model: A/C // Brand: EKOKAI, Model: A/C

View File

@@ -1,7 +1,7 @@
// Copyright 2018 crankyoldgit // Copyright 2018 crankyoldgit
// The specifics of reverse engineering the protocol details by kuzin2006 // The specifics of reverse engineering the protocol details by kuzin2006
// Supported: // Supports:
// Brand: Haier, Model: HSU07-HEA03 remote // Brand: Haier, Model: HSU07-HEA03 remote
// Brand: Haier, Model: YR-W02 remote // Brand: Haier, Model: YR-W02 remote
// Brand: Haier, Model: HSU-09HMC203 A/C // Brand: Haier, Model: HSU-09HMC203 A/C

View File

@@ -2,7 +2,7 @@
// //
// Copyright 2018 David Conran // Copyright 2018 David Conran
// Supported: // Supports:
// Brand: Hitachi, Model: RAS-35THA6 remote // Brand: Hitachi, Model: RAS-35THA6 remote
// Brand: Hitachi, Model: LT0541-HTA remote // Brand: Hitachi, Model: LT0541-HTA remote
// Brand: Hitachi, Model: Series VI A/C (Circa 2007) // Brand: Hitachi, Model: Series VI A/C (Circa 2007)

View File

@@ -2,7 +2,7 @@
// //
// Copyright 2016 David Conran // Copyright 2016 David Conran
// Supported: // Supports:
// Brand: Kelvinator, Model: YALIF Remote // Brand: Kelvinator, Model: YALIF Remote
// Brand: Kelvinator, Model: KSV26CRC A/C // Brand: Kelvinator, Model: KSV26CRC A/C
// Brand: Kelvinator, Model: KSV26HRC A/C // Brand: Kelvinator, Model: KSV26HRC A/C

View File

@@ -2,7 +2,7 @@
// Copyright 2015 cheaplin // Copyright 2015 cheaplin
// Copyright 2017, 2018 David Conran // Copyright 2017, 2018 David Conran
// Supported: // Supports:
// Brand: LG, Model: 6711A20083V remote // Brand: LG, Model: 6711A20083V remote
// Brand: LG, Model: AKB74395308 remote // Brand: LG, Model: AKB74395308 remote

View File

@@ -1,18 +1,12 @@
// Copyright 2017 David Conran // Copyright 2017 David Conran
// Supported: // Supports:
// Brand: LG, Model: 6711A20083V remote // Brand: LG, Model: 6711A20083V remote
// Brand: LG, Model: AKB74395308 remote // Brand: LG, Model: AKB74395308 remote
#ifndef IR_LG_H_ #ifndef IR_LG_H_
#define IR_LG_H_ #define IR_LG_H_
// L GGGG
// L G
// L G GG
// L G G
// LLLLL GGG
#define __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS
#include <stdint.h> #include <stdint.h>

View File

@@ -8,7 +8,7 @@
// LEGO // LEGO
// (LEGO is a Registrated Trademark of the Lego Group.) // (LEGO is a Registrated Trademark of the Lego Group.)
// //
// Supported: // Supports:
// Brand: LEGO Power Functions, Model: IR Receiver // Brand: LEGO Power Functions, Model: IR Receiver
// //
// Ref: // Ref:

View File

@@ -29,7 +29,7 @@ run_tests : all
failed=""; \ failed=""; \
for py_unittest in *_test.py; do \ for py_unittest in *_test.py; do \
echo "RUNNING: $${py_unittest}"; \ echo "RUNNING: $${py_unittest}"; \
python ./$${py_unittest} || failed="$${failed} $${py_unittest}"; \ python3 ./$${py_unittest} || failed="$${failed} $${py_unittest}"; \
done; \ done; \
if [ -n "$${failed}" ]; then \ if [ -n "$${failed}" ]; then \
echo "FAIL: :-( :-( Unit test(s)$${failed} failed! :-( :-("; exit 1; \ echo "FAIL: :-( :-( Unit test(s)$${failed} failed! :-( :-("; exit 1; \

View File

@@ -8,7 +8,7 @@ import argparse
import sys import sys
class RawIRMessage(object): class RawIRMessage():
"""Basic analyse functions & structure for raw IR messages.""" """Basic analyse functions & structure for raw IR messages."""
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
@@ -62,7 +62,7 @@ class RawIRMessage(object):
def _usec_compare(self, seen, expected): def _usec_compare(self, seen, expected):
"""Compare two usec values and see if they match within a """Compare two usec values and see if they match within a
subtractive margin.""" subtractive margin."""
return seen <= expected and seen > expected - self.margin return expected - self.margin < seen <= expected
def _usec_compares(self, usecs, expecteds): def _usec_compares(self, usecs, expecteds):
"""Compare a usec value to a list of values and return True """Compare a usec value to a list of values and return True
@@ -160,7 +160,7 @@ class RawIRMessage(object):
def avg_list(items): def avg_list(items):
"""Return the average of a list of numbers.""" """Return the average of a list of numbers."""
if items: if items:
return sum(items) / len(items) return int(sum(items) / len(items))
return 0 return 0
@@ -293,7 +293,7 @@ def decode_data(message, defines, function_code, output=sys.stdout):
output.write("kHdrSpace+") output.write("kHdrSpace+")
function_code.append(" space(kHdrSpace);") function_code.append(" space(kHdrSpace);")
elif message.is_bit_mark(usec) and count % 2: 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)") output.write("kBitMark(UNEXPECTED)")
state = "BM" state = "BM"
elif message.is_zero_space(usec): elif message.is_zero_space(usec):

View File

@@ -1,6 +1,6 @@
#!/usr/bin/python #!/usr/bin/python3
"""Unit tests for auto_analyse_raw_data.py""" """Unit tests for auto_analyse_raw_data.py"""
import StringIO from io import StringIO
import unittest import unittest
import auto_analyse_raw_data as analyse import auto_analyse_raw_data as analyse
@@ -12,7 +12,7 @@ class TestRawIRMessage(unittest.TestCase):
def test_display_binary(self): def test_display_binary(self):
"""Test the display_binary() method.""" """Test the display_binary() method."""
output = StringIO.StringIO() output = StringIO()
message = analyse.RawIRMessage(100, [8000, 4000, 500, 500, 500], output, message = analyse.RawIRMessage(100, [8000, 4000, 500, 500, 500], output,
False) False)
self.assertEqual(output.getvalue(), '') self.assertEqual(output.getvalue(), '')
@@ -52,8 +52,8 @@ class TestAutoAnalyseRawData(unittest.TestCase):
def test_dump_constants_simple(self): def test_dump_constants_simple(self):
"""Simple tests for the dump_constants() function.""" """Simple tests for the dump_constants() function."""
ignore = StringIO.StringIO() ignore = StringIO()
output = StringIO.StringIO() output = StringIO()
defs = [] defs = []
message = analyse.RawIRMessage(200, [ message = analyse.RawIRMessage(200, [
7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494, 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): def test_dump_constants_aircon(self):
"""More complex tests for the dump_constants() function.""" """More complex tests for the dump_constants() function."""
ignore = StringIO.StringIO() ignore = StringIO()
output = StringIO.StringIO() output = StringIO()
defs = [] defs = []
message = analyse.RawIRMessage(200, [ message = analyse.RawIRMessage(200, [
9008, 4496, 644, 1660, 676, 530, 648, 558, 672, 1636, 646, 1660, 644, 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]) self.assertEqual(analyse.convert_rawdata("0"), [0])
with self.assertRaises(ValueError) as context: with self.assertRaises(ValueError) as context:
analyse.convert_rawdata("") analyse.convert_rawdata("")
self.assertEqual(context.exception.message, self.assertEqual(str(context.exception),
"Raw Data contains a non-numeric value of ''.") "Raw Data contains a non-numeric value of ''.")
# Single parenthesis # Single parenthesis
@@ -132,13 +132,13 @@ class TestAutoAnalyseRawData(unittest.TestCase):
# Bad parentheses # Bad parentheses
with self.assertRaises(ValueError) as context: with self.assertRaises(ValueError) as context:
analyse.convert_rawdata("}10{") analyse.convert_rawdata("}10{")
self.assertEqual(context.exception.message, self.assertEqual(str(context.exception),
"Raw Data not parsible due to parentheses placement.") "Raw Data not parsible due to parentheses placement.")
# Non base-10 values # Non base-10 values
with self.assertRaises(ValueError) as context: with self.assertRaises(ValueError) as context:
analyse.convert_rawdata("10, 20, foo, bar, 30") 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'.") "Raw Data contains a non-numeric value of 'foo'.")
# A messy usual "good" case. # A messy usual "good" case.
@@ -155,7 +155,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
"""Tests for the parse_and_report() function.""" """Tests for the parse_and_report() function."""
# Without code generation. # Without code generation.
output = StringIO.StringIO() output = StringIO()
input_str = """ input_str = """
uint16_t rawbuf[139] = {9008, 4496, 644, 1660, 676, 530, 648, 558, 672, 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, 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') 'Total Nr. of suspected bits: 67\n')
# With code generation. # With code generation.
output = StringIO.StringIO() output = StringIO()
input_str = """ input_str = """
uint16_t rawbuf[37] = {7930, 3952, 494, 1482, 520, 1482, 494, uint16_t rawbuf[37] = {7930, 3952, 494, 1482, 520, 1482, 494,
1508, 494, 520, 494, 1482, 494, 520, 494, 1482, 494, 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 Space Gaps in parse_and_report() function."""
# Tests for unusual Gaps. (Issue #482) # Tests for unusual Gaps. (Issue #482)
output = StringIO.StringIO() output = StringIO()
input_str = """ input_str = """
uint16_t rawbuf[272] = {3485, 3512, 864, 864, 864, 2620, 864, 864, uint16_t rawbuf[272] = {3485, 3512, 864, 864, 864, 2620, 864, 864,
864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 2620, 864, 864,
@@ -466,7 +466,7 @@ class TestAutoAnalyseRawData(unittest.TestCase):
def test_reduce_list(self): def test_reduce_list(self):
"""Tests for the reduce_list method.""" """Tests for the reduce_list method."""
ignore = StringIO.StringIO() ignore = StringIO()
message = analyse.RawIRMessage(200, [ message = analyse.RawIRMessage(200, [
7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494, 7930, 3952, 494, 1482, 520, 1482, 494, 1508, 494, 520, 494, 1482, 494,
520, 494, 1482, 494, 1482, 494, 3978, 494, 520, 494, 520, 494, 520, 494, 520, 494, 1482, 494, 1482, 494, 3978, 494, 520, 494, 520, 494, 520, 494,

255
tools/scrape_supported_devices.py Executable file
View File

@@ -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<brand>.+), *Model: *(?P<model>.+)")
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 = """<!--- WARNING: Do NOT edit this file directly.
It is generated by './tools/scrape_supported_devices.py'.
Last generated: {} --->""".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,
"<BR>".join(codes),
"<BR>".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()