This commit is contained in:
2026-08-17 22:09:15 +05:00
parent 522bb8dfa5
commit 046284e9d8
7 changed files with 294 additions and 9 deletions
+162
View File
@@ -0,0 +1,162 @@
import network
import socket
import time
import json
from dotenv import load_env
# ==== НАСТРОЙКИ ====
TRANSMIT_PIN = 19
# ====================
def connect_wifi(ssid, password, timeout_s=15):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print(f"Подключение к WiFi '{ssid}'...")
wlan.connect(ssid, password)
start = time.time()
while not wlan.isconnected():
if time.time() - start > timeout_s:
print("Не удалось подключиться к WiFi (таймаут)")
return None
time.sleep(0.5)
ip = wlan.ifconfig()[0]
print(f"WiFi подключен. IP адрес: {ip}")
return ip
def load_codes(filename="codes.json"):
try:
with open(filename, "r") as f:
return json.load(f)
except OSError:
return {}
def send_ir_code(name, pin_num=TRANSMIT_PIN):
from transmit import send_code
send_code(name, pin_num=pin_num)
def url_decode(s):
"""Простейший url-decode для параметров запроса (без внешних зависимостей)."""
s = s.replace("+", " ")
result = ""
i = 0
while i < len(s):
if s[i] == "%" and i + 2 < len(s):
try:
result += chr(int(s[i + 1:i + 3], 16))
i += 3
continue
except ValueError:
pass
result += s[i]
i += 1
return result
def parse_query(path):
"""Возвращает (route, {param: value}) из строки вида /send?code=power"""
if "?" not in path:
return path, {}
route, qs = path.split("?", 1)
params = {}
for pair in qs.split("&"):
if "=" in pair:
k, v = pair.split("=", 1)
params[url_decode(k)] = url_decode(v)
return route, params
def handle_request(path):
route, params = parse_query(path)
if route == "/send":
name = params.get("code")
if not name:
return 400, {"error": "укажите ?code=имя_кода"}
codes = load_codes()
if name not in codes:
return 404, {"error": f"код '{name}' не найден", "available": list(codes.keys())}
try:
send_ir_code(name)
return 200, {"status": "ok", "sent": name}
except Exception as e:
return 500, {"error": str(e)}
elif route == "/list":
codes = load_codes()
return 200, {"codes": list(codes.keys())}
elif route == "/":
return 200, {"status": "ESP32 IR сервер запущен", "endpoints": ["/list", "/send?code=ИМЯ"]}
else:
return 404, {"error": "неизвестный маршрут"}
def run_server(ip):
addr = socket.getaddrinfo("0.0.0.0", 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(1)
print(f"Сервер запущен: http://{ip}/")
print(f"Примеры: http://{ip}/list | http://{ip}/send?code=power")
while True:
try:
conn, client_addr = s.accept()
request = conn.recv(1024).decode("utf-8", "ignore")
# Парсим первую строку запроса: "GET /send?code=power HTTP/1.1"
first_line = request.split("\r\n", 1)[0]
parts = first_line.split(" ")
path = parts[1] if len(parts) > 1 else "/"
status, body = handle_request(path)
body_json = json.dumps(body)
status_text = {200: "OK", 400: "Bad Request", 404: "Not Found",
500: "Internal Server Error"}.get(status, "OK")
response = (
f"HTTP/1.1 {status} {status_text}\r\n"
"Content-Type: application/json\r\n"
"Access-Control-Allow-Origin: *\r\n"
f"Content-Length: {len(body_json)}\r\n"
"Connection: close\r\n"
"\r\n"
f"{body_json}"
)
conn.send(response.encode())
conn.close()
except Exception as e:
print(f"Ошибка обработки запроса: {e}")
try:
conn.close()
except Exception:
pass
def main():
env = load_env()
ssid = env.get("WIFI_SSID")
password = env.get("WIFI_PASSWORD")
if not ssid or not password:
print("Ошибка: заполните WIFI_SSID и WIFI_PASSWORD в .env")
return
ip = connect_wifi(ssid, password)
if ip:
run_server(ip)
else:
print("Сервер не запущен: нет WiFi")
if __name__ == "__main__":
main()