From 1893ab9cda399eb8ed7ad50560613f024099fdee Mon Sep 17 00:00:00 2001 From: Jason Cox Date: Sat, 25 May 2024 22:35:38 -0700 Subject: [PATCH 1/4] Add pipx support #500 --- RELEASE.md | 5 ++ pyproject.toml | 2 + setup.py | 1 + tinytuya/__main__.py | 160 ++++++++++++++++++++++--------------------- tinytuya/core.py | 2 +- 5 files changed, 90 insertions(+), 80 deletions(-) create mode 100644 pyproject.toml diff --git a/RELEASE.md b/RELEASE.md index 4fbac6b5..28b909cf 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,5 +1,10 @@ # RELEASE NOTES +## v1.13.3 - PIPX Support + +* Add support for `pipx install tinytuya` as raised by @felipecrs in https://github.com/jasonacox/tinytuya/issues/500 allowing for easier CLI use. +* Possible breaking change: Running `tinytuya` by itself will now produce a "Usage" page instead of running a scan. Use `tinytuya scan` or `python -m tinytuya scan`. + ## v1.13.2 - Contrib Updates * Add example for XmCosy+ RGBW patio string lights by @bikerglen in https://github.com/jasonacox/tinytuya/pull/445 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..cf0e05aa --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[build-system] +requires = ["setuptools", "colorama", "requests", "cryptography"] diff --git a/setup.py b/setup.py index f8e69bde..ff33e6f8 100644 --- a/setup.py +++ b/setup.py @@ -40,6 +40,7 @@ url='https://github.com/jasonacox/tinytuya', packages=setuptools.find_packages(exclude=("sandbox",)), install_requires=INSTALL_REQUIRES, + entry_points={"console_scripts": ["tinytuya=tinytuya.__main__:main"]}, classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", diff --git a/tinytuya/__main__.py b/tinytuya/__main__.py index e39d0b0d..89ba2589 100644 --- a/tinytuya/__main__.py +++ b/tinytuya/__main__.py @@ -19,92 +19,94 @@ from . import wizard from . import scanner -retries = None -state = 0 -color = True -force = False -force_list = [] -last_force = False -broadcast_listen = True -assume_yes = False +def main(): + retries = None + state = 10 + color = True + force = False + force_list = [] + last_force = False + broadcast_listen = True + assume_yes = False -for i in sys.argv: - if i==sys.argv[0]: - continue - this_force = False - if i.lower() == "wizard": - state = 1 - elif i.lower() == "scan": - state = 0 - elif i.lower() == "-nocolor": - color = False - elif i.lower() == "-force" or i.lower() == "-f": - force = True - this_force = True - elif i.lower() == "-no-broadcasts": - broadcast_listen = False - elif i.lower() == "snapshot": - state = 2 - elif i.lower() == "devices": - state = 3 - elif i.lower() == "json": - state = 4 - elif i.lower() == "-yes" or i.lower() == "-y": - assume_yes = True - elif i.lower() == "-debug" or i.lower() == "-d": - tinytuya.set_debug(True) - elif last_force and len(i) > 6: - this_force = True - force_list.append( i ) - else: - try: - retries = int(i) - except: - state = 10 + for i in sys.argv: + if i==sys.argv[0]: + continue + this_force = False + if i.lower() == "wizard": + state = 1 + elif i.lower() == "scan": + state = 0 + elif i.lower() == "-nocolor": + color = False + elif i.lower() == "-force" or i.lower() == "-f": + force = True + this_force = True + elif i.lower() == "-no-broadcasts": + broadcast_listen = False + elif i.lower() == "snapshot": + state = 2 + elif i.lower() == "devices": + state = 3 + elif i.lower() == "json": + state = 4 + elif i.lower() == "-yes" or i.lower() == "-y": + assume_yes = True + elif i.lower() == "-debug" or i.lower() == "-d": + tinytuya.set_debug(True) + elif last_force and len(i) > 6: + this_force = True + force_list.append( i ) + else: + try: + retries = int(i) + except: + state = 10 - last_force = this_force + last_force = this_force -if force and len(force_list) > 0: - force = force_list + if force and len(force_list) > 0: + force = force_list -# State 0 = Run Network Scan -if state == 0: - scanner.scan(scantime=retries, color=color, forcescan=force, discover=broadcast_listen, assume_yes=assume_yes) + # State 0 = Run Network Scan + if state == 0: + scanner.scan(scantime=retries, color=color, forcescan=force, discover=broadcast_listen, assume_yes=assume_yes) -# State 1 = Run Setup Wizard -if state == 1: - wizard.wizard(color=color, retries=retries, forcescan=force, quicklist=assume_yes) + # State 1 = Run Setup Wizard + if state == 1: + wizard.wizard(color=color, retries=retries, forcescan=force, quicklist=assume_yes) -# State 2 = Snapshot Display and Scan -if state == 2: - scanner.snapshot(color=color) + # State 2 = Snapshot Display and Scan + if state == 2: + scanner.snapshot(color=color) -# State 3 = Scan All Devices -if state == 3: - scanner.alldevices(color=color, scantime=retries) + # State 3 = Scan All Devices + if state == 3: + scanner.alldevices(color=color, scantime=retries) -# State 4 = Scan All Devices -if state == 4: - scanner.snapshotjson() + # State 4 = Scan All Devices + if state == 4: + scanner.snapshotjson() -# State 10 = Show Usage -if state == 10: - print("TinyTuya [%s]\n" % (tinytuya.version)) - print("Usage:\n") - print(" python -m tinytuya [] [-debug] [-nocolor] [-force [192.168.0.0/24 192.168.1.0/24 ...]] [-h]") - print("") - print(" wizard Launch Setup Wizard to get Tuya Local KEYs.") - print(" scan Scan local network for Tuya devices.") - print(" devices Scan all devices listed in devices.json file.") - print(" snapshot Scan devices listed in snapshot.json file.") - print(" json Scan devices listed in snapshot.json file [JSON].") - print(" Maximum time to find Tuya devices [Default=%s]" % tinytuya.SCANTIME) - print(" -nocolor Disable color text output.") - print(" -force Force network scan of device IP addresses based on format:") - print(" [net1/mask1 net2/mask2 ...] Auto-detects if none provided.") - print(" -no-broadcasts Ignore broadcast packets when force scanning.") - print(" -debug Activate debug mode.") - print(" -h Show usage.") - print("") + # State 10 = Show Usage + if state == 10: + print("TinyTuya [%s]\n" % (tinytuya.version)) + print("Usage:\n") + print(" python -m tinytuya [] [-debug] [-nocolor] [-force [192.168.0.0/24 192.168.1.0/24 ...]] [-h]") + print("") + print(" wizard Launch Setup Wizard to get Tuya Local KEYs.") + print(" scan Scan local network for Tuya devices.") + print(" devices Scan all devices listed in devices.json file.") + print(" snapshot Scan devices listed in snapshot.json file.") + print(" json Scan devices listed in snapshot.json file [JSON].") + print(" Maximum time to find Tuya devices [Default=%s]" % tinytuya.SCANTIME) + print(" -nocolor Disable color text output.") + print(" -force Force network scan of device IP addresses based on format:") + print(" [net1/mask1 net2/mask2 ...] Auto-detects if none provided.") + print(" -no-broadcasts Ignore broadcast packets when force scanning.") + print(" -debug Activate debug mode.") + print(" -h Show usage.") + print("") -# End +if __name__ == "__main__": + main() diff --git a/tinytuya/core.py b/tinytuya/core.py index 2a4dd6bd..dad15cc0 100644 --- a/tinytuya/core.py +++ b/tinytuya/core.py @@ -123,7 +123,7 @@ # Colorama terminal color capability for all platforms init() -version_tuple = (1, 13, 2) +version_tuple = (1, 13, 3) version = __version__ = "%d.%d.%d" % version_tuple __author__ = "jasonacox" From 930810adbae05c8ebd8d2076a07c7133b96ec078 Mon Sep 17 00:00:00 2001 From: Jason Cox Date: Sat, 25 May 2024 22:46:17 -0700 Subject: [PATCH 2/4] Update Actions --- .github/workflows/contrib.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/contrib.yml b/.github/workflows/contrib.yml index afe95808..57a3aee9 100644 --- a/.github/workflows/contrib.yml +++ b/.github/workflows/contrib.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - python-version: ["3.6", "3.7", "3.8"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] steps: - uses: "actions/checkout@v2" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8f0ccd6c..a14873f5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - python-version: ["3.5", "3.6", "3.7", "3.8", "3.9", "3.10"] + python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] steps: - uses: "actions/checkout@v3" From 286d6b3f9832066d59152186eb44c6c81a5c693c Mon Sep 17 00:00:00 2001 From: Jason Cox Date: Sat, 25 May 2024 23:00:37 -0700 Subject: [PATCH 3/4] Address pylint --- tinytuya/scanner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tinytuya/scanner.py b/tinytuya/scanner.py index 1102ab3b..de845ffa 100644 --- a/tinytuya/scanner.py +++ b/tinytuya/scanner.py @@ -1079,6 +1079,7 @@ def tuyaLookup(deviceid): ) #debug_ips = ['172.20.10.144', '172.20.10.91', '172.20.10.51', '172.20.10.136'] + scan_ips = None debug_ips = [] networks = [] scanned_devices = {} From 617a26ba2de429912442234c03d44c033c3b7c91 Mon Sep 17 00:00:00 2001 From: Jason Cox Date: Sat, 25 May 2024 23:15:02 -0700 Subject: [PATCH 4/4] Fix pylint warnings --- tinytuya/BulbDevice.py | 2 ++ tinytuya/core.py | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tinytuya/BulbDevice.py b/tinytuya/BulbDevice.py index fd435d4b..768333d5 100644 --- a/tinytuya/BulbDevice.py +++ b/tinytuya/BulbDevice.py @@ -178,6 +178,7 @@ def _hexvalue_to_rgb(hexvalue, bulb="A"): Args: hexvalue(string): The hex representation generated by BulbDevice._rgb_to_hexvalue() """ + r, g, b = 0, 0, 0 if bulb == "A": r = int(hexvalue[0:2], 16) g = int(hexvalue[2:4], 16) @@ -203,6 +204,7 @@ def _hexvalue_to_hsv(hexvalue, bulb="A"): Args: hexvalue(string): The hex representation generated by BulbDevice._rgb_to_hexvalue() """ + h, s, v = 0, 0, 0 if bulb == "A": h = int(hexvalue[7:10], 16) / 360.0 s = int(hexvalue[10:12], 16) / 255.0 diff --git a/tinytuya/core.py b/tinytuya/core.py index dad15cc0..23e340b6 100644 --- a/tinytuya/core.py +++ b/tinytuya/core.py @@ -89,7 +89,7 @@ pass for clib in ('pyca/cryptography', 'PyCryptodomex', 'PyCrypto', 'pyaes'): - Crypto = AES = CRYPTOLIB = None + Crypto = Crypto_modes = AES = CRYPTOLIB = None try: if clib == 'pyca/cryptography': # https://cryptography.io/en/latest/ from cryptography import __version__ as Crypto_version @@ -496,6 +496,7 @@ def pack_message(msg, hmac_key=None): def unpack_message(data, hmac_key=None, header=None, no_retcode=False): """Unpack bytes into a TuyaMessage.""" + crc_good = False if header is None: header = parse_header(data)