AnasSarkiz/magnetic-shutter-remote-r8

A USB‑C rechargeable battery-powered ESP32‑C3 wireless controller with Li‑ion charging, protected 3.3‑V buck‑boost regulation, thermal/safety monitoring, status LEDs, buttons, programming UART, crystal clock, and 2.4‑GHz antenna matching network.

Version
0.4.0-prototype
License
unset
Stars
0

scripts/r8_board_geometry.py

"""Read the actual R8 outline and qualified all-layer antenna exclusion."""
from shapely.geometry import Polygon, box


def board_outline(circuit):
    boards = [e for e in circuit if e['type'] == 'pcb_board']
    if len(boards) != 1:
        raise ValueError('Expected one native R8 board')
    board = boards[0]
    outline = Polygon([(p['x'], p['y']) for p in board['outline']])
    if not outline.is_valid or outline.is_empty:
        raise ValueError('Invalid native board outline')
    x, y = board['center']['x'], board['center']['y']
    bounds = (x-board['width']/2, y-board['height']/2,
              x+board['width']/2, y+board['height']/2)
    if any(abs(a-b) > 0.0001 for a, b in zip(outline.bounds, bounds)):
        raise ValueError('Native outline and board dimensions differ')
    return outline


def rf_exclusion(circuit):
    source = [e for e in circuit if e['type'] == 'source_component' and e['name'] == 'U1']
    if len(source) != 1:
        raise ValueError('Expected one fitted radio U1')
    radio = [e for e in circuit if e['type'] == 'pcb_component'
             and e['source_component_id'] == source[0]['source_component_id']]
    if len(radio) != 1:
        raise ValueError('Expected one physical radio U1')
    bands = [e for e in circuit if e['type'] == 'pcb_keepout'
             and e.get('excluded_pcb_component_ids') == [radio[0]['pcb_component_id']]]
    if len(bands) != 1:
        raise ValueError('Expected one explicit radio antenna exclusion')
    band = bands[0]
    if band['shape'] != 'rect' or set(band['layers']) != {'top', 'bottom'}:
        raise ValueError('Antenna exclusion must cover both copper layers')
    x, y = band['center']['x'], band['center']['y']
    exclusion = box(x-band['width']/2, y-band['height']/2,
                    x+band['width']/2, y+band['height']/2)
    bounds = board_outline(circuit).bounds
    if (band['height'] < 8.7-0.0001 or exclusion.bounds[0] > bounds[0]+0.0001
            or exclusion.bounds[2] < bounds[2]-0.0001
            or abs(exclusion.bounds[1]-bounds[1]) > 0.0001):
        raise ValueError('Qualified 8.7mm antenna band must span the board edge')
    return exclusion