Add files via upload
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
|||||||
|
ARG BUILD_FROM
|
||||||
|
FROM $BUILD_FROM
|
||||||
|
|
||||||
|
RUN apk add --no-cache python3
|
||||||
|
|
||||||
|
COPY arkteos_proxy.py /arkteos_proxy.py
|
||||||
|
COPY run.sh /run.sh
|
||||||
|
RUN chmod +x /run.sh
|
||||||
|
|
||||||
|
CMD ["/run.sh"]
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# Proxy TCP pour PAC Arkteos REG3
|
||||||
|
# Permet les connexions simultanées de Node-RED et de l'app mobile Arkteos
|
||||||
|
# Usage : arkteos_proxy.py <pac_host> <pac_port> <proxy_port>
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import threading
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# Configuration depuis les arguments (injectés par run.sh depuis les options HA)
|
||||||
|
PAC_HOST = sys.argv[1] if len(sys.argv) > 1 else "192.168.X.X"
|
||||||
|
PAC_PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 9641
|
||||||
|
PROXY_PORT = int(sys.argv[3]) if len(sys.argv) > 3 else 9641
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format='%(asctime)s %(levelname)s %(message)s',
|
||||||
|
stream=sys.stdout
|
||||||
|
)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
stop_event = threading.Event()
|
||||||
|
clients = []
|
||||||
|
clients_lock = threading.Lock()
|
||||||
|
|
||||||
|
def log(msg):
|
||||||
|
logger.info(msg)
|
||||||
|
|
||||||
|
def connect_to_pac():
|
||||||
|
while not stop_event.is_set():
|
||||||
|
try:
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
s.connect((PAC_HOST, PAC_PORT))
|
||||||
|
log(f"Connecté à la PAC {PAC_HOST}:{PAC_PORT}")
|
||||||
|
return s
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Échec connexion PAC : {e}. Nouvelle tentative dans 10s...")
|
||||||
|
time.sleep(10)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def pac_reader(pac_socket):
|
||||||
|
log("Démarrage thread lecture PAC")
|
||||||
|
try:
|
||||||
|
while not stop_event.is_set():
|
||||||
|
try:
|
||||||
|
data = pac_socket.recv(4096)
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Erreur lecture PAC : {e}")
|
||||||
|
break
|
||||||
|
if not data:
|
||||||
|
log("PAC a fermé la connexion")
|
||||||
|
break
|
||||||
|
|
||||||
|
dead_clients = []
|
||||||
|
with clients_lock:
|
||||||
|
for c in clients:
|
||||||
|
try:
|
||||||
|
c.sendall(data)
|
||||||
|
except Exception:
|
||||||
|
dead_clients.append(c)
|
||||||
|
|
||||||
|
if dead_clients:
|
||||||
|
with clients_lock:
|
||||||
|
for c in dead_clients:
|
||||||
|
try:
|
||||||
|
c.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if c in clients:
|
||||||
|
clients.remove(c)
|
||||||
|
log("Client déconnecté nettoyé")
|
||||||
|
finally:
|
||||||
|
log("Arrêt thread lecture PAC")
|
||||||
|
pac_socket.close()
|
||||||
|
|
||||||
|
def pac_keepalive(pac_socket):
|
||||||
|
log("Démarrage thread keepalive PAC")
|
||||||
|
while not stop_event.is_set():
|
||||||
|
time.sleep(300)
|
||||||
|
try:
|
||||||
|
pac_socket.sendall(b'\x00')
|
||||||
|
log("Keepalive envoyé à la PAC")
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Erreur keepalive PAC : {e}")
|
||||||
|
break
|
||||||
|
log("Arrêt thread keepalive PAC")
|
||||||
|
|
||||||
|
def handle_client(client_socket, client_addr, pac_socket):
|
||||||
|
log(f"Nouveau client : {client_addr}")
|
||||||
|
with clients_lock:
|
||||||
|
clients.append(client_socket)
|
||||||
|
try:
|
||||||
|
while not stop_event.is_set():
|
||||||
|
try:
|
||||||
|
data = client_socket.recv(1024)
|
||||||
|
except Exception:
|
||||||
|
break
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
pac_socket.sendall(data)
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Erreur envoi PAC depuis {client_addr} : {e}")
|
||||||
|
break
|
||||||
|
finally:
|
||||||
|
with clients_lock:
|
||||||
|
if client_socket in clients:
|
||||||
|
clients.remove(client_socket)
|
||||||
|
try:
|
||||||
|
client_socket.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
log(f"Client déconnecté : {client_addr}")
|
||||||
|
|
||||||
|
def start_proxy():
|
||||||
|
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
server_socket.bind(('0.0.0.0', PROXY_PORT))
|
||||||
|
server_socket.listen(5)
|
||||||
|
log(f"Proxy en écoute sur 0.0.0.0:{PROXY_PORT}")
|
||||||
|
|
||||||
|
pac_socket = connect_to_pac()
|
||||||
|
if pac_socket is None:
|
||||||
|
log("Impossible de se connecter à la PAC. Arrêt.")
|
||||||
|
return
|
||||||
|
|
||||||
|
reader_thread = threading.Thread(target=pac_reader, args=(pac_socket,), daemon=True)
|
||||||
|
reader_thread.start()
|
||||||
|
|
||||||
|
keepalive_thread = threading.Thread(target=pac_keepalive, args=(pac_socket,), daemon=True)
|
||||||
|
keepalive_thread.start()
|
||||||
|
|
||||||
|
try:
|
||||||
|
while not stop_event.is_set():
|
||||||
|
server_socket.settimeout(1)
|
||||||
|
try:
|
||||||
|
client_socket, addr = server_socket.accept()
|
||||||
|
t = threading.Thread(target=handle_client, args=(client_socket, addr, pac_socket), daemon=True)
|
||||||
|
t.start()
|
||||||
|
except socket.timeout:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Reconnexion si la PAC s'est déconnectée
|
||||||
|
if not reader_thread.is_alive():
|
||||||
|
log("Thread lecture PAC mort, reconnexion...")
|
||||||
|
with clients_lock:
|
||||||
|
for c in clients:
|
||||||
|
try:
|
||||||
|
c.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
clients.clear()
|
||||||
|
pac_socket = connect_to_pac()
|
||||||
|
if pac_socket is None:
|
||||||
|
break
|
||||||
|
reader_thread = threading.Thread(target=pac_reader, args=(pac_socket,), daemon=True)
|
||||||
|
reader_thread.start()
|
||||||
|
keepalive_thread = threading.Thread(target=pac_keepalive, args=(pac_socket,), daemon=True)
|
||||||
|
keepalive_thread.start()
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Erreur serveur proxy : {e}")
|
||||||
|
finally:
|
||||||
|
stop_event.set()
|
||||||
|
server_socket.close()
|
||||||
|
try:
|
||||||
|
pac_socket.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
log("Proxy arrêté.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
start_proxy()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
log("Arrêt demandé")
|
||||||
|
stop_event.set()
|
||||||
|
sys.exit(0)
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
name: Arkteos Proxy
|
||||||
|
version: "1.0.0"
|
||||||
|
slug: arkteos_proxy
|
||||||
|
description: Proxy TCP pour PAC Arkteos REG3 — permet les connexions simultanées de Node-RED et de l'app mobile Arkteos.
|
||||||
|
url: https://github.com/raph666/arkteos-proxy-addon
|
||||||
|
arch:
|
||||||
|
- aarch64
|
||||||
|
- amd64
|
||||||
|
- armhf
|
||||||
|
- armv7
|
||||||
|
- i386
|
||||||
|
init: false
|
||||||
|
options:
|
||||||
|
pac_host: "192.168.X.X"
|
||||||
|
pac_port: 9641
|
||||||
|
proxy_port: 9641
|
||||||
|
schema:
|
||||||
|
pac_host: str
|
||||||
|
pac_port: int
|
||||||
|
proxy_port: int
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
name: Arkteos Proxy
|
||||||
|
url: https://github.com/raph666/arkteos-proxy-addon
|
||||||
|
maintainer: raph666
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/with-contenv bashio
|
||||||
|
|
||||||
|
PAC_HOST=$(bashio::config 'pac_host')
|
||||||
|
PAC_PORT=$(bashio::config 'pac_port')
|
||||||
|
PROXY_PORT=$(bashio::config 'proxy_port')
|
||||||
|
|
||||||
|
bashio::log.info "Démarrage du proxy Arkteos"
|
||||||
|
bashio::log.info "PAC : ${PAC_HOST}:${PAC_PORT}"
|
||||||
|
bashio::log.info "Proxy en écoute sur port : ${PROXY_PORT}"
|
||||||
|
|
||||||
|
exec python3 /arkteos_proxy.py "${PAC_HOST}" "${PAC_PORT}" "${PROXY_PORT}"
|
||||||
Reference in New Issue
Block a user