Интегрирован wesp в сайт
CI / quality (push) Canceled after 0s

This commit is contained in:
влад
2026-07-17 12:57:18 +03:00
parent 5dfa06ddbe
commit 355c0ef9f1
883 changed files with 194576 additions and 177 deletions
@@ -0,0 +1,107 @@
import threading
import time
from typing import Optional
class GPIOController:
"""Thread-safe singleton controller for GPIO output pin."""
_instance = None
_instance_lock = threading.Lock()
def __init__(self, pin: int, simulation_mode: bool = False):
self.pin = pin
self.simulation_mode = simulation_mode
self._lock = threading.Lock()
self._blink_stop_event = threading.Event()
self._blink_thread: Optional[threading.Thread] = None
self._state = False
self._gpio = None
self._gpio_available = False
if not self.simulation_mode:
try:
import RPi.GPIO as GPIO # type: ignore[import-not-found]
self._gpio = GPIO
self._gpio.setmode(GPIO.BCM)
self._gpio.setup(self.pin, GPIO.OUT)
self._gpio.output(self.pin, GPIO.LOW)
self._gpio_available = True
except Exception:
self._gpio = None
self._gpio_available = False
@classmethod
def get_instance(cls, pin: int = 18, simulation_mode: bool = False):
with cls._instance_lock:
if cls._instance is None:
cls._instance = cls(pin=pin, simulation_mode=simulation_mode)
return cls._instance
@classmethod
def _reset_for_tests(cls):
with cls._instance_lock:
if cls._instance is not None:
cls._instance.cleanup()
cls._instance = None
def _write_locked(self, state: bool) -> None:
self._state = state
if self._gpio_available and self._gpio is not None:
self._gpio.output(self.pin, self._gpio.HIGH if state else self._gpio.LOW)
def on(self) -> None:
with self._lock:
self._write_locked(True)
def off(self) -> None:
with self._lock:
self._write_locked(False)
def is_on(self) -> bool:
with self._lock:
return bool(self._state)
@property
def rpi_gpio_available(self) -> bool:
"""True, если поднят настоящий RPi.GPIO (Raspberry Pi). В симуляции всегда False."""
return bool(self._gpio_available)
def stop_blink(self) -> None:
self._blink_stop_event.set()
if self._blink_thread and self._blink_thread.is_alive():
self._blink_thread.join(timeout=2)
self._blink_thread = None
self._blink_stop_event.clear()
def blink(self, times: int = 3, delay: float = 0.2) -> None:
if times <= 0:
return
self.stop_blink()
def _worker():
for _ in range(times):
if self._blink_stop_event.is_set():
break
self.on()
time.sleep(delay)
if self._blink_stop_event.is_set():
break
self.off()
time.sleep(delay)
self.off()
self._blink_thread = threading.Thread(target=_worker, daemon=True, name="gpio-blink")
self._blink_thread.start()
def cleanup(self) -> None:
self.stop_blink()
self.off()
if self._gpio_available and self._gpio is not None:
try:
self._gpio.cleanup(self.pin)
except Exception:
pass