<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Python script to change my wifi color LED light bulb state]]></title><description><![CDATA[<p dir="auto">My PC talks to my wifi light bulb directly, not via Tuya's cloud API.</p>
<p dir="auto">I can say, "Alexa, bulb 1 red" or "Alexa bulb 1 off" etc.</p>
<p dir="auto">I can also say, "Use @TRIGGERcmd to turn bulb 1 blue" using the MCP tool with ChatGPT.</p>
<p dir="auto"><strong>Example commands:</strong></p>
<p dir="auto">Turn the bulb on:</p>
<pre><code>python3 c:\tools\tuyabulb.py --id abcdefghijklmnop123456 --key "123456!@ABCcdefh" --ip 192.168.86.25 on
</code></pre>
<p dir="auto">Set the color to red:</p>
<pre><code>python3 c:\tools\tuyabulb.py --id abcdefghijklmnop123456 --key "123456!@ABCcdefh" --ip 192.168.86.25 red
</code></pre>
<p dir="auto">Set the brightness to 60 percent:</p>
<pre><code>python3 c:\tools\tuyabulb.py --id abcdefghijklmnop123456 --key "123456!@ABCcdefh" --ip 192.168.86.25 60
</code></pre>
<p dir="auto">Here's the script:</p>
<pre><code>#!/usr/bin/env python3
import argparse
import ipaddress
import platform
import subprocess
import sys
import tinytuya

# Predefined color presets (RGB values)
COLOR_PRESETS = {
    "red": (255, 0, 0),
    "green": (0, 255, 0),
    "blue": (0, 0, 255),
    "white": (255, 255, 255),
    "yellow": (255, 255, 0),
    "cyan": (0, 255, 255),
    "magenta": (255, 0, 255),
    "orange": (255, 165, 0),
    "purple": (128, 0, 128),
    "pink": (255, 192, 203),
}


def ping_host(ip: str, timeout: int = 1) -&gt; bool:
    """Ping a host to check if it's reachable. Returns True if ping succeeds."""
    param = "-n" if platform.system().lower() == "windows" else "-c"
    timeout_param = "-w" if platform.system().lower() == "windows" else "-W"
    timeout_value = str(timeout * 1000) if platform.system().lower() == "windows" else str(timeout)
    
    command = ["ping", param, "1", timeout_param, timeout_value, ip]
    try:
        result = subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=timeout + 1)
        return result.returncode == 0
    except (subprocess.TimeoutExpired, Exception):
        return False


def make_device(device_id: str, ip: str, local_key: str, version: str | None):
    # BulbDevice works for most Tuya bulbs. If yours isn't a "bulb" type, use Device instead.
    d = tinytuya.BulbDevice(device_id, ip, local_key)
    d.set_socketPersistent(True)   # keep socket open for reliability
    d.set_socketTimeout(5)         # seconds

    # Many Tuya WiFi bulbs are 3.3. Some are 3.1. If you're unsure, try 3.3 first.
    if version:
        d.set_version(float(version))
    else:
        d.set_version(3.3)

    return d


def main():
    p = argparse.ArgumentParser(description="Local control of a Tuya bulb via tinytuya (no cloud).")
    p.add_argument("--id", required=True, help="Tuya device id")
    p.add_argument("--ip", help="Bulb IP address on your LAN")
    p.add_argument("--subnet", help="Subnet to scan (e.g. 192.168.1.0/24)")
    p.add_argument("--start-from", help="IP address to start scanning from (only with --subnet)")
    p.add_argument("--key", required=True, help="Tuya localKey (16+ chars)")
    p.add_argument("--ver", default=None, help="Protocol version (e.g. 3.3 or 3.1). Default: 3.3")
    p.add_argument("cmd", help="Command: off, on, status, color name (red, green, etc.), or brightness 0-100")
    args = p.parse_args()

    # Determine command type
    cmd_lower = args.cmd.lower()
    if cmd_lower in ["off", "on", "status"]:
        cmd_type = cmd_lower
    elif cmd_lower in COLOR_PRESETS:
        cmd_type = "color"
        preset_color = cmd_lower
    elif args.cmd.isdigit():
        brightness_val = int(args.cmd)
        if 0 &lt;= brightness_val &lt;= 100:
            cmd_type = "brightness"
        else:
            p.error("Brightness must be between 0-100")
    else:
        p.error(f"Invalid command: {args.cmd}. Use: off, on, status, color name, or brightness (0-100)")

    # Validate that either --ip or --subnet is provided
    if not args.ip and not args.subnet:
        p.error("Either --ip or --subnet must be specified")
    if args.ip and args.subnet:
        p.error("Cannot specify both --ip and --subnet")
    if args.start_from and not args.subnet:
        p.error("--start-from can only be used with --subnet")

    # Determine which IPs to try
    if args.subnet:
        try:
            network = ipaddress.ip_network(args.subnet, strict=False)
            all_ips = [str(ip) for ip in network.hosts()]
            
            # Filter to start from specified IP if provided
            if args.start_from:
                start_ip = ipaddress.ip_address(args.start_from)
                # Verify start IP is in the subnet
                if start_ip not in network:
                    print(f"ERROR: Start IP {args.start_from} is not in subnet {args.subnet}", file=sys.stderr)
                    return 1
                # Filter to IPs &gt;= start_from
                ips_to_try = [ip for ip in all_ips if ipaddress.ip_address(ip) &gt;= start_ip]
                print(f"Scanning subnet {args.subnet} from {args.start_from} ({len(ips_to_try)} hosts)...", file=sys.stderr)
            else:
                ips_to_try = all_ips
                print(f"Scanning subnet {args.subnet} ({len(ips_to_try)} hosts)...", file=sys.stderr)
        except ValueError as e:
            print(f"ERROR: Invalid subnet or IP format: {e}", file=sys.stderr)
            return 1
    else:
        ips_to_try = [args.ip]

    # Try each IP until one works
    last_error = None
    for ip in ips_to_try:
        if args.subnet:
            print(f"Trying {ip}...", file=sys.stderr)
            # Quick ping check to skip unreachable hosts
            if not ping_host(ip):
                continue
        
        dev = make_device(args.id, ip, args.key, args.ver)

        dev = make_device(args.id, ip, args.key, args.ver)

        try:
            if cmd_type == "off":
                r = dev.turn_off()
            elif cmd_type == "on":
                r = dev.turn_on()
            elif cmd_type == "brightness":
                r = dev.set_brightness_percentage(brightness_val)
            elif cmd_type == "color":
                # Get RGB values from preset
                rgb = COLOR_PRESETS[preset_color]
                # Set the color
                r = dev.set_colour(rgb[0], rgb[1], rgb[2])
            else:
                r = dev.status()

            # Check if the device responded with an errora
            if isinstance(r, dict) and r.get("Error"):
                if args.subnet:
                    # During subnet scan, continue to next IP on error
                    last_error = r.get("Error")
                    continue
                else:
                    # For direct IP, print error and exit
                    print(r)
                    return 2

            # Success! Print result and exit
            if args.subnet:
                print(f"SUCCESS: Device found at {ip}", file=sys.stderr)
            print(r)
            return 0

        except Exception as e:
            last_error = e
            if not args.subnet:
                print(f"ERROR: {e}", file=sys.stderr)
                return 1
            # For subnet scan, continue to next IP
            continue
        finally:
            try:
                dev.set_socketPersistent(False)
            except Exception:
                pass

    # If we get here with subnet scan, none of the IPs worked
    if args.subnet:
        print(f"ERROR: Device not found in subnet {args.subnet}. Last error: {last_error}", file=sys.stderr)
        return 1


if __name__ == "__main__":
    raise SystemExit(main())
</code></pre>
<p dir="auto">This is my commands.json entry:</p>
<pre><code> {
  "trigger": "Tuya Bulb 1",
  "command": "python3 c:\\tools\\tuyabulb.py --id abcdefghijklmnop123456 --key \"123456!@ABCcdefh\" --ip 192.168.86.25",
  "offCommand": "",
  "ground": "foreground",
  "voice": "bulb 1",
  "voiceReply": "",
  "allowParams": "true",
  "mcpToolDescription": "Controls the state of light bulb 1.  Parameters are: on, off, red, green, blue, white, yellow, cyan, magenta, orange, purple, pink, or brightness percentage from 0 to 100"
 }
</code></pre>
]]></description><link>https://www.triggercmd.com/forum/topic/3331/python-script-to-change-my-wifi-color-led-light-bulb-state</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Jul 2026 21:34:50 GMT</lastBuildDate><atom:link href="https://www.triggercmd.com/forum/topic/3331.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 30 Dec 2025 02:19:55 GMT</pubDate><ttl>60</ttl></channel></rss>