Files
led-controller/espnow-sender/src/peer_table.py
2026-05-28 00:38:21 +12:00

91 lines
2.5 KiB
Python

"""LRU table of ESP-NOW peer MACs seen on uplink."""
from espnow_wire import BROADCAST_MAC
try:
from settings import Settings
except ImportError:
Settings = None
# ESP32 counts the broadcast peer toward the ~20 peer limit.
_RESERVED_FOR_BROADCAST = 1
class PeerTable:
def __init__(self, max_peers=20):
limit = max(1, int(max_peers) - _RESERVED_FOR_BROADCAST)
self._max = limit
self._order = []
self._names = {}
def _evict_lru(self, esp):
if not self._order:
return
old = self._order.pop(0)
self._names.pop(old, None)
if esp is not None:
try:
esp.del_peer(old)
except OSError:
pass
def touch(self, mac_bytes, name=None, esp=None):
"""Note a peer from uplink (LRU). Pass ``esp`` so evictions free ESP-NOW slots."""
if not mac_bytes or len(mac_bytes) != 6:
return
if mac_bytes == BROADCAST_MAC:
return
if mac_bytes in self._order:
self._order.remove(mac_bytes)
elif len(self._order) >= self._max:
self._evict_lru(esp)
self._order.append(mac_bytes)
if name:
self._names[mac_bytes] = str(name)
if esp is not None:
try:
esp.add_peer(mac_bytes)
except OSError:
pass
def ensure_peer(self, esp, mac_bytes):
"""Register ``mac_bytes`` on ESP-NOW, evicting LRU peers when the table is full."""
if not mac_bytes or len(mac_bytes) != 6:
return False
if mac_bytes == BROADCAST_MAC:
try:
esp.add_peer(mac_bytes)
except OSError:
pass
return True
if mac_bytes in self._order:
self._order.remove(mac_bytes)
self._order.append(mac_bytes)
else:
while len(self._order) >= self._max:
self._evict_lru(esp)
self._order.append(mac_bytes)
# Uplink touch() only updates LRU; always add_peer before unicast send.
try:
esp.add_peer(mac_bytes)
except OSError as err:
print("add_peer failed", err)
return False
return True
def peers(self):
return list(self._order)
def is_broadcast_mac(self, mac_bytes):
return mac_bytes == BROADCAST_MAC
def load_max_peers():
if Settings is None:
return 20
try:
s = Settings()
return int(s.get("max_peers", 20))
except Exception:
return 20