用Python在本地网络中自动发现ESP8266 NodeMCU设备IP地址
动态发现本地网络中的ESP8266设备并批量控制
问题背景
我有运行本地HTTP服务器的ESP8266 NodeMCU设备,已完成初始配置。目标是同步控制大量该设备,当前Python脚本可手动指定IP实现LED控制,但需动态发现本地网络中所有搭载相同固件的ESP8266设备IP,无需静态IP或设备端独特配置。曾尝试用socket模块查找以“ESP-”开头的主机名但无结果,需要适配Mac环境的解决方案。现有脚本如下:
#!/usr/bin/env python import time import sys import socket import requests def myFunction(): #This is what I have right now... ipAddresses = ["192.168.1.43", "192.168.1.44"] # #Instead, I need to search the local network for all the arduinos [ESP8266s] and append their address to the array. # for address in ipAddresses: TurnOnLED(address) def TurnOnLED(address): try: r = requests.post('http://' + address + '/LedON') r.close() except requests.exceptions.ConnectionError: pass #Main def Main(): try: print("Press CTRL-C to stop.") ON = True while ON: myFunction() time.sleep(60) except KeyboardInterrupt: sys.exit(0) if __name__ == "__main__": Main()
适配Mac的解决方案
方法1:ARP扫描验证(无需修改设备固件)
Mac系统可通过arp -a命令获取本地网络ARP缓存表,提取活跃IP后,通过HTTP请求验证是否为目标ESP8266设备(比如请求专属接口或检查响应特征)。
修改后的完整脚本:
#!/usr/bin/env python import time import sys import socket import requests import subprocess import re def discover_esp_devices(): esp_ips = [] # 执行arp命令获取本地网络设备列表 result = subprocess.run(['arp', '-a'], capture_output=True, text=True) # 正则提取所有IP地址 ip_pattern = re.compile(r'(\d+\.\d+\.\d+\.\d+)') ips = ip_pattern.findall(result.stdout) # 遍历IP,验证是否为ESP8266设备 for ip in ips: try: # 可改为请求专属验证接口(如/device-info),判断响应特征提升准确性 requests.get(f'http://{ip}/LedON', timeout=1) esp_ips.append(ip) except (requests.exceptions.ConnectionError, requests.exceptions.Timeout): continue return esp_ips def myFunction(): # 动态发现ESP设备IP ipAddresses = discover_esp_devices() print(f"Found {len(ipAddresses)} ESP devices: {ipAddresses}") for address in ipAddresses: TurnOnLED(address) def TurnOnLED(address): try: r = requests.post(f'http://{address}/LedON') r.close() except requests.exceptions.ConnectionError: pass #Main def Main(): try: print("Press CTRL-C to stop.") ON = True while ON: myFunction() time.sleep(60) except KeyboardInterrupt: sys.exit(0) if __name__ == "__main__": Main()
方法2:UDP广播发现(效率更高,需极小修改设备固件)
在ESP8266固件中添加UDP广播响应逻辑:设备启动后监听指定UDP端口,收到广播指令时回复自身IP。Python端发送广播包并收集响应,可快速获取所有设备IP。
ESP8266固件新增核心代码:
#include <ESP8266WiFi.h> #include <WiFiUdp.h> WiFiUDP udp; const int udpPort = 10000; void setup() { // 原有WiFi初始化代码... udp.begin(udpPort); } void loop() { int packetSize = udp.parsePacket(); if (packetSize) { char packetBuffer[255]; int len = udp.read(packetBuffer, 255); if (len > 0) packetBuffer[len] = 0; // 识别发现指令并回复IP if (strcmp(packetBuffer, "DISCOVER_ESP") == 0) { udp.beginPacket(udp.remoteIP(), udp.remotePort()); udp.print(WiFi.localIP().toString()); udp.endPacket(); } } // 原有loop代码... }
对应Python发现函数:
def discover_esp_devices_via_udp(): esp_ips = [] broadcast_ip = '192.168.1.255' # 根据你的子网修改 udp_port = 10000 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.settimeout(2) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) # 发送广播发现指令 sock.sendto(b"DISCOVER_ESP", (broadcast_ip, udp_port)) # 收集设备响应 while True: try: data, addr = sock.recvfrom(1024) esp_ips.append(addr[0]) except socket.timeout: break sock.close() return list(set(esp_ips)) # 去重
注意事项
- ARP扫描依赖设备在ARP缓存中存在,刚上线的设备可能无法立即发现,可配合定时扫描
- UDP广播需确保ESP8266与Mac在同一子网,广播地址需根据实际网络调整
- 建议在ESP8266固件中添加专属响应标识,避免误识别其他HTTP设备
内容的提问来源于stack exchange,提问作者JeremiahDuane
相关产品推荐
相关产品推荐

