You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求改进树莓派WiFi存在检测自动灯控程序并整合多检测方式

树莓派自动灯控完整解决方案(整合多检测方式+优化功能)

嘿,我帮你搞定了这个自动灯控的脚本,把你想要的Bash逻辑完全整合到Python里,还解决了响应速度、误判、函数整合和路径的问题,同时加入了所有你提到的功能:支持ARP扫描、IP邻居+Ping、蓝牙检测(适配安卓休眠),还有日间禁止开灯、GPIO状态跟踪优化。直接上可运行代码,然后咱们一步步拆解讲解:

import subprocess
import time
import datetime
import os

# -------------------------- 配置区(请根据你的设备修改) --------------------------
TARGET_DEVICES = {
    "phone": {
        "mac": "AA:BB:CC:DD:EE:FF",  # 你的手机MAC地址(WiFi/蓝牙可相同或不同)
        "ip": "192.168.1.100"        # 你的手机静态IP地址
    }
}
LIGHT_GPIO_PIN = 18  # 控制灯的GPIO引脚(BCM编号)
DAYTIME_START = 7    # 日间开始时间(小时),此时间段内禁止开灯
DAYTIME_END = 19     # 日间结束时间(小时)
DETECTION_METHOD = "ip_neighbor_ping"  # 可选值:arp_scan, ip_neighbor_ping, bluetooth
DETECTION_INTERVAL = 5  # 检测间隔(秒),平衡响应速度和误判
GPIO_STATE = False  # 跟踪当前GPIO状态,避免重复操作

# -------------------------- 工具函数 --------------------------
def is_daytime():
    """判断当前是否处于日间时段,返回True/False"""
    current_hour = datetime.datetime.now().hour
    return DAYTIME_START <= current_hour < DAYTIME_END

def get_command_output(cmd):
    """执行系统命令并返回输出,处理路径问题"""
    # 确保命令使用绝对路径,避免网站调用时环境变量缺失问题
    cmd_parts = cmd.split()
    # 尝试获取命令的绝对路径
    try:
        cmd_path = subprocess.check_output(["which", cmd_parts[0]], text=True).strip()
        cmd_parts[0] = cmd_path
    except subprocess.CalledProcessError:
        print(f"错误:未找到命令 {cmd_parts[0]},请先安装")
        return ""
    
    try:
        result = subprocess.run(cmd_parts, capture_output=True, text=True, timeout=10)
        return result.stdout + result.stderr
    except subprocess.TimeoutExpired:
        print(f"命令 {cmd} 执行超时")
        return ""

# -------------------------- 设备检测函数 --------------------------
def arp_scan_detect(target_mac):
    """使用arp-scan检测设备是否在线"""
    output = get_command_output(f"arp-scan -l --interface wlan0")
    return target_mac.lower() in output.lower()

def ip_neighbor_ping_detect(target_mac, target_ip):
    """整合Bash的ip neighbor + ping逻辑,更可靠"""
    # 先检查ARP缓存(快速判断)
    ip_neighbor_output = get_command_output(f"ip neighbor show {target_ip}")
    if target_mac.lower() in ip_neighbor_output.lower() and "REACHABLE" in ip_neighbor_output:
        return True
    # 缓存不可达时,尝试Ping(只发1个包,超时1秒)
    ping_output = get_command_output(f"ping -c 1 -W 1 {target_ip}")
    if "1 received" in ping_output:
        # Ping成功后再次检查ARP缓存,确保设备确实在线
        ip_neighbor_output = get_command_output(f"ip neighbor show {target_ip}")
        return target_mac.lower() in ip_neighbor_output.lower()
    return False

def bluetooth_detect(target_mac):
    """蓝牙检测,适配安卓休眠(使用l2ping,即使设备休眠也可能响应)"""
    # 先确保蓝牙适配器开启
    get_command_output("bluetoothctl power on")
    # 使用l2ping发送1个包,超时2秒
    output = get_command_output(f"l2ping -c 1 -t 2 {target_mac}")
    return "1 received" in output

# -------------------------- GPIO控制函数 --------------------------
def setup_gpio():
    """初始化GPIO"""
    subprocess.run(["gpio", "mode", str(LIGHT_GPIO_PIN), "out"], check=True)
    global GPIO_STATE
    # 初始状态设为关闭
    set_light_state(False)

def set_light_state(state):
    """设置灯的状态,仅当状态变化时才执行操作"""
    global GPIO_STATE
    if state == GPIO_STATE:
        return  # 状态未变化,跳过操作
    GPIO_STATE = state
    if state:
        subprocess.run(["gpio", "write", str(LIGHT_GPIO_PIN), "1"], check=True)
        print(f"[{datetime.datetime.now()}] 灯已打开")
    else:
        subprocess.run(["gpio", "write", str(LIGHT_GPIO_PIN), "0"], check=True)
        print(f"[{datetime.datetime.now()}] 灯已关闭")

# -------------------------- 主程序逻辑 --------------------------
def main():
    print("启动自动灯控程序...")
    setup_gpio()
    
    try:
        while True:
            # 日间时段直接关闭灯,跳过检测
            if is_daytime():
                set_light_state(False)
                time.sleep(DETECTION_INTERVAL * 2)  # 日间延长检测间隔,减少资源占用
                continue
            
            # 根据选择的检测方式判断设备是否在线
            device_online = False
            target = TARGET_DEVICES["phone"]
            if DETECTION_METHOD == "arp_scan":
                device_online = arp_scan_detect(target["mac"])
            elif DETECTION_METHOD == "ip_neighbor_ping":
                device_online = ip_neighbor_ping_detect(target["mac"], target["ip"])
            elif DETECTION_METHOD == "bluetooth":
                device_online = bluetooth_detect(target["mac"])
            else:
                print("错误:不支持的检测方式")
                time.sleep(DETECTION_INTERVAL)
                continue
            
            # 根据设备在线状态控制灯
            set_light_state(device_online)
            
            time.sleep(DETECTION_INTERVAL)
    except KeyboardInterrupt:
        print("\n程序已终止,关闭灯...")
        set_light_state(False)

if __name__ == "__main__":
    # 切换到脚本所在目录,避免网站调用时工作目录错误的问题
    os.chdir(os.path.dirname(os.path.abspath(__file__)))
    main()

关键功能说明

1. 解决路径问题

脚本启动时会自动切换到自身所在目录,并且用which命令获取系统工具的绝对路径,彻底避免网站调用(比如PHP的exec)时因为工作目录或环境变量缺失导致命令找不到的问题。

2. 多检测方式支持

  • arp_scan:快速扫描局域网,但可能在设备WiFi休眠时误判离线
  • ip_neighbor_ping:整合了你觉得更可靠的Bash逻辑——先查ARP缓存(快),缓存不可达时再Ping确认,完美平衡速度和准确性
  • bluetooth:用l2ping检测,安卓设备即使休眠(只要蓝牙保持连接)也能响应,适合对WiFi休眠敏感的场景

3. 日间禁止开灯

通过is_daytime()函数判断当前时间,日间直接关闭灯,还延长了检测间隔,减少树莓派资源占用。

4. GPIO状态跟踪

用GPIO_STATE变量记录当前灯的状态,只有状态变化时才执行GPIO操作,避免频繁切换导致的硬件损耗和误触发。

5. 误判优化

  • 检测间隔可配置(DETECTION_INTERVAL),默认5秒,你可以根据需求调整——间隔太短容易误判,太长响应慢
  • ip_neighbor_ping方式中,Ping成功后会再次检查ARP缓存,确保设备确实在线,减少误判概率

使用步骤

  1. 安装依赖:

    sudo apt update && sudo apt install arp-scan bluez wiringpi
    
    • arp-scan:ARP扫描功能需要
    • bluez:蓝牙检测功能需要
    • wiringpi:GPIO控制功能需要
  2. 配置参数:
    修改脚本顶部的配置区:

    • 替换TARGET_DEVICES里的MAC和IP为你的手机信息
    • 调整LIGHT_GPIO_PIN为你的实际GPIO引脚
    • 设置合适的DAYTIME_START和DAYTIME_END
    • 选择你想用的DETECTION_METHOD
  3. 测试运行:

    sudo python3 your_script_name.py
    

    (需要sudo权限,因为arp-scan和GPIO控制需要系统权限)

  4. 网站调用注意事项:

    • 如果用网站(比如PHP)调用,确保web用户(www-data)有sudo权限执行脚本,建议通过sudo visudo配置免密权限,避免输入密码
    • 脚本已经处理了路径问题,直接调用绝对路径即可,比如:
      exec("sudo python3 /home/pi/auto_light.py > /dev/null 2>&1 &");
      
    • 避免重复启动,可以用进程检测判断脚本是否在运行

常见问题解决

  • 蓝牙检测失败:确保树莓派蓝牙已开启,手机蓝牙和树莓派配对过(不需要连接,配对即可),并且手机蓝牙设置里允许被检测
  • 误判离线:可以尝试把DETECTION_INTERVAL调大,或者切换到ip_neighbor_ping或bluetooth方式
  • 网站调用循环异常:脚本里的主循环已经做了异常捕获(KeyboardInterrupt),并且用os.chdir切换到脚本目录,避免工作目录导致的问题

内容的提问来源于stack exchange,提问作者Love-to-Make

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:48:33