Add RLUtils class for managing RL/AI dashboard endpoints

- Implemented methods for fetching AI stats, training history, and recent experiences.
- Added functionality to set operation mode (MANUAL, AUTO, AI) with appropriate handling.
- Included helper methods for querying the database and sending JSON responses.
- Integrated model metadata extraction for visualization purposes.
This commit is contained in:
Fabien POLLY
2026-02-18 22:36:10 +01:00
parent b8a13cc698
commit eb20b168a6
684 changed files with 53278 additions and 27977 deletions

View File

@@ -1,15 +1,23 @@
import logging
import time
from . import epdconfig
from logger import Logger
# Display resolution
EPD_WIDTH = 122
EPD_HEIGHT = 250
logger = logging.getLogger(__name__)
logger = Logger(name="epd2in13.py", level=logging.DEBUG)
class EPD:
def __init__(self):
self.is_initialized = False # New flag to track if the display has been initialized #INFINITION
# Defensive timeout/logging for BUSY pin stalls.
self.busy_timeout_s = 30.0
self.busy_poll_ms = 100
self.busy_log_interval_s = 5.0
# Keep this False in production to avoid log spam on normal refresh cycles.
self.log_busy_transitions = False
self.reset_pin = epdconfig.RST_PIN
self.dc_pin = epdconfig.DC_PIN
self.busy_pin = epdconfig.BUSY_PIN
@@ -52,9 +60,24 @@ class EPD:
epdconfig.spi_writebyte([data])
epdconfig.digital_write(self.cs_pin, 1)
def ReadBusy(self):
while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
epdconfig.delay_ms(100)
def ReadBusy(self):
# 0: idle, 1: busy
started = time.monotonic()
last_log = started
while(epdconfig.digital_read(self.busy_pin) == 1):
now = time.monotonic()
waited = now - started
if waited >= self.busy_timeout_s:
raise TimeoutError(
f"EPD busy timeout after {self.busy_timeout_s:.1f}s "
f"(pin={self.busy_pin}, state=1, expected idle=0)"
)
if (now - last_log) >= self.busy_log_interval_s:
logger.warning(
f"ReadBusy waiting {waited:.1f}s (pin={self.busy_pin}, state=1/busy)"
)
last_log = now
epdconfig.delay_ms(self.busy_poll_ms)
def TurnOnDisplay(self):
self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2
@@ -62,9 +85,11 @@ class EPD:
self.send_command(0x20) # MASTER_ACTIVATION
self.send_command(0xFF) # TERMINATE_FRAME_READ_WRITE
logger.debug("e-Paper busy")
if self.log_busy_transitions:
logger.debug("e-Paper busy")
self.ReadBusy()
logger.debug("e-Paper busy release")
if self.log_busy_transitions:
logger.debug("e-Paper busy release")
def init(self, lut):
if not self.is_initialized: # Avoid repeated initialization and accumulation of File descriptors #INFINITION
@@ -195,4 +220,3 @@ class EPD:
epdconfig.module_exit()
### END OF FILE ###

View File

@@ -6,17 +6,23 @@
# - Pas de décalage wrap-around d1 pixel (fini la ligne sombre)
import logging
import time
from . import epdconfig
from logger import Logger
# Résolution physique du panneau (hardware)
EPD_WIDTH = 122
EPD_HEIGHT = 250
logger = logging.getLogger(__name__)
logger = Logger(name="epd2in13_V2.py", level=logging.DEBUG)
class EPD:
def __init__(self):
self.is_initialized = False
# Defensive timeout/logging for BUSY pin stalls.
self.busy_timeout_s = 30.0
self.busy_poll_ms = 50
self.busy_log_interval_s = 5.0
self.reset_pin = epdconfig.RST_PIN
self.dc_pin = epdconfig.DC_PIN
self.busy_pin = epdconfig.BUSY_PIN
@@ -87,8 +93,22 @@ class EPD:
def ReadBusy(self):
# 0: idle, 1: busy
started = time.monotonic()
last_log = started
while epdconfig.digital_read(self.busy_pin) == 1:
epdconfig.delay_ms(50)
now = time.monotonic()
waited = now - started
if waited >= self.busy_timeout_s:
raise TimeoutError(
f"EPD busy timeout after {self.busy_timeout_s:.1f}s "
f"(pin={self.busy_pin}, state=1, expected idle=0)"
)
if (now - last_log) >= self.busy_log_interval_s:
logger.warning(
f"ReadBusy waiting {waited:.1f}s (pin={self.busy_pin}, state=1/busy)"
)
last_log = now
epdconfig.delay_ms(self.busy_poll_ms)
def TurnOnDisplay(self):
self.send_command(0x22)

View File

@@ -1,15 +1,23 @@
import logging
import time
from . import epdconfig
from logger import Logger
# Display resolution
EPD_WIDTH = 122
EPD_HEIGHT = 250
logger = logging.getLogger(__name__)
logger = Logger(name="epd2in13_V3.py", level=logging.DEBUG)
class EPD:
def __init__(self):
self.is_initialized = False # New flag to track if the display has been initialized #INFINITION
# Defensive timeout/logging for BUSY pin stalls.
self.busy_timeout_s = 30.0
self.busy_poll_ms = 10
self.busy_log_interval_s = 5.0
# Keep this False in production to avoid log spam on normal refresh cycles.
self.log_busy_transitions = False
self.reset_pin = epdconfig.RST_PIN
self.dc_pin = epdconfig.DC_PIN
self.busy_pin = epdconfig.BUSY_PIN
@@ -107,10 +115,26 @@ class EPD:
parameter:
'''
def ReadBusy(self):
logger.debug("e-Paper busy")
if self.log_busy_transitions:
logger.debug("e-Paper busy")
started = time.monotonic()
last_log = started
while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
epdconfig.delay_ms(10)
logger.debug("e-Paper busy release")
now = time.monotonic()
waited = now - started
if waited >= self.busy_timeout_s:
raise TimeoutError(
f"EPD busy timeout after {self.busy_timeout_s:.1f}s "
f"(pin={self.busy_pin}, state=1, expected idle=0)"
)
if (now - last_log) >= self.busy_log_interval_s:
logger.warning(
f"ReadBusy waiting {waited:.1f}s (pin={self.busy_pin}, state=1/busy)"
)
last_log = now
epdconfig.delay_ms(self.busy_poll_ms)
if self.log_busy_transitions:
logger.debug("e-Paper busy release")
'''
function : Turn On Display
@@ -370,4 +394,3 @@ class EPD:
epdconfig.module_exit()
### END OF FILE ###

View File

@@ -1,15 +1,23 @@
import logging
import time
from . import epdconfig
from logger import Logger
# Display resolution
EPD_WIDTH = 122
EPD_HEIGHT = 250
logger = logging.getLogger(__name__)
logger = Logger(name="epd2in13_V4.py", level=logging.DEBUG)
class EPD:
def __init__(self):
self.is_initialized = False # New flag to track if the display has been initialized #INFINITION
# Defensive timeout/logging for BUSY pin stalls.
self.busy_timeout_s = 30.0
self.busy_poll_ms = 10
self.busy_log_interval_s = 5.0
# Keep this False in production to avoid log spam on normal refresh cycles.
self.log_busy_transitions = False
self.reset_pin = epdconfig.RST_PIN
self.dc_pin = epdconfig.DC_PIN
self.busy_pin = epdconfig.BUSY_PIN
@@ -63,10 +71,26 @@ class EPD:
parameter:
'''
def ReadBusy(self):
logger.debug("e-Paper busy")
if self.log_busy_transitions:
logger.debug("e-Paper busy")
started = time.monotonic()
last_log = started
while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
epdconfig.delay_ms(10)
logger.debug("e-Paper busy release")
now = time.monotonic()
waited = now - started
if waited >= self.busy_timeout_s:
raise TimeoutError(
f"EPD busy timeout after {self.busy_timeout_s:.1f}s "
f"(pin={self.busy_pin}, state=1, expected idle=0)"
)
if (now - last_log) >= self.busy_log_interval_s:
logger.warning(
f"ReadBusy waiting {waited:.1f}s (pin={self.busy_pin}, state=1/busy)"
)
last_log = now
epdconfig.delay_ms(self.busy_poll_ms)
if self.log_busy_transitions:
logger.debug("e-Paper busy release")
'''
function : Turn On Display
@@ -319,4 +343,3 @@ class EPD:
epdconfig.module_exit()
### END OF FILE ###

View File

@@ -28,7 +28,9 @@
#
import logging
import time
from . import epdconfig
from logger import Logger
# Display resolution
EPD_WIDTH = 176
@@ -39,11 +41,18 @@ GRAY2 = 0xC0
GRAY3 = 0x80 #gray
GRAY4 = 0x00 #Blackest
logger = logging.getLogger(__name__)
logger = Logger(name="epd2in7.py", level=logging.DEBUG)
class EPD:
def __init__(self):
self.is_initialized = False # New flag to track if the display has been initialized #INFINITION
# Diagnostic guards for BUSY wait loops:
# this prevents a permanent block when BUSY pin gets stuck.
self.busy_timeout_s = 45.0
self.busy_poll_ms = 200
self.busy_log_interval_s = 5.0
# Keep this False in production to avoid log spam on normal refresh cycles.
self.log_busy_transitions = False
self.reset_pin = epdconfig.RST_PIN
self.dc_pin = epdconfig.DC_PIN
self.busy_pin = epdconfig.BUSY_PIN
@@ -174,11 +183,29 @@ class EPD:
epdconfig.spi_writebyte([data])
epdconfig.digital_write(self.cs_pin, 1)
def ReadBusy(self):
logger.debug("e-Paper busy")
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
epdconfig.delay_ms(200)
logger.debug("e-Paper busy release")
def ReadBusy(self):
# epd2in7 uses inverted BUSY logic on this implementation:
# 0 = busy, 1 = idle.
if self.log_busy_transitions:
logger.debug("e-Paper busy")
started = time.monotonic()
last_log = started
while(epdconfig.digital_read(self.busy_pin) == 0):
now = time.monotonic()
waited = now - started
if waited >= self.busy_timeout_s:
raise TimeoutError(
f"EPD busy timeout after {self.busy_timeout_s:.1f}s "
f"(pin={self.busy_pin}, state=0, expected idle=1)"
)
if (now - last_log) >= self.busy_log_interval_s:
logger.warning(
f"ReadBusy waiting {waited:.1f}s (pin={self.busy_pin}, state=0/busy)"
)
last_log = now
epdconfig.delay_ms(self.busy_poll_ms)
if self.log_busy_transitions:
logger.debug("e-Paper busy release")
def set_lut(self):
self.send_command(0x20) # vcom
@@ -524,4 +551,3 @@ class EPD:
epdconfig.delay_ms(2000)
epdconfig.module_exit()
### END OF FILE ###