diff --git a/pnpdevice/relays.py b/pnpdevice/relays.py index 83fb4d8..7aee8a5 100644 --- a/pnpdevice/relays.py +++ b/pnpdevice/relays.py @@ -87,10 +87,10 @@ class Manager: self.configpath = configpath self.has_fakes = has_fakes - # Handles to various chips - self._chips = [] - # Info on various pins - self._pins = [] + # Handles to various chips, mapped by chip number + self._chips = {} + # Info on various pins, mapped by (chip number, line_number) + self._pins = {} # Cached info on the relays self._relays = [] # Connection to single-board computer GPIO @@ -104,7 +104,7 @@ class Manager: def chips(self) -> List[Chip]: if not self._chips: self._load_chips() - return self._chips + return self._chips.values() def connect(self) -> None: self.sbc = rgpio.sbc( @@ -116,16 +116,18 @@ class Manager: self.sbc = None def get_chip_by_number(self, number: int) -> Chip: - for chip in self.chips: - if chip.number == number: - return chip - raise Exception(f"Can't find chip {number}") + try: + return self._chips[number] + except KeyError: + self._load_chip(number) + return self._chips[number] def get_pin_by_number(self, chip: Chip, line_number: int) -> Pin: - for pin in self.pins: - if pin.chip == chip and pin.line_number == line_number: - return pin - raise Exception(f"Can't find pin {chip.name}-{line_number}") + try: + return self._pins[(chip.number, line_number)] + except KeyError: + self._load_pin(chip, line_number) + return self._pins[(chip.number, line_number)] def get_relay_by_pin_id(self, pin_id: str) -> Relay: for relay in self.relays: @@ -133,11 +135,15 @@ class Manager: return relay return None + def load_all_pins(self) -> None: + self._load_chips() + self._load_pins() + @property def pins(self) -> List[Pin]: if not self._pins: self._load_pins() - return self._pins + return self._pins.values() @property def relays(self) -> Iterable[Relay]: @@ -177,50 +183,55 @@ class Manager: def shutdown(self) -> None: _write_config(self.configpath, self.config) + def _load_chip(self, number: int) -> None: + try: + handle = self.sbc.gpiochip_open(number) + except rgpio.error: + return + if handle < 0: + return + okay, number_of_lines, name, label = self.sbc.gpio_get_chip_info(handle) + LOGGER.info("Chip info: %s %s %s %s", okay, number_of_lines, name, label) + if okay != 0: + LOGGER.warn("Chip %s not okay.", name) + return + self._chips[number] = Chip( + handle=handle, + label=label, + name=name, + number=number, + number_of_lines=number_of_lines, + ) + # Talk to the remote pins daemon and get information about the chips def _load_chips(self) -> None: for i in range(MAX_CHIPS): - try: - handle = self.sbc.gpiochip_open(i) - except rgpio.error: - continue - if handle < 0: - continue - okay, number_of_lines, name, label = self.sbc.gpio_get_chip_info(handle) - LOGGER.info("Chip info: %s %s %s %s", okay, number_of_lines, name, label) - if okay != 0: - LOGGER.warn("Chip %s not okay.", name) - continue - self._chips.append(Chip( - handle=handle, - label=label, - name=name, - number=i, - number_of_lines=number_of_lines, - )) + self._load_chip(i) + + def _load_pin(self, chip: Chip, line_number: int) -> None: + okay, offset, flags, name, user = self.sbc.gpio_get_line_info(chip.handle, line_number) + LOGGER.info("Got line info: %s %s %s %s %s", okay, offset, flags, name, user) + assert offset == line_number + if okay != 0: + LOGGER.warn("Line %s is not okay", name) + return + if not name: + LOGGER.warn("Ignoring line %d because it has no name.", line_number) + return + self._pins[(chip.number, line_number)] = Pin( + chip=chip, + flags=flags, + line_number=line_number, + name=name, + user=user, + ) # Talk to the remote pins daemon and get information about the pins def _load_pins(self) -> None: LOGGER.info("Loading pins") for chip in self.chips: for line in range(chip.number_of_lines): - okay, offset, flags, name, user = self.sbc.gpio_get_line_info(chip.handle, line) - LOGGER.info("Got line info: %s %s %s %s %s", okay, offset, flags, name, user) - assert offset == line - if okay != 0: - LOGGER.warn("Line %s is not okay", name) - continue - if not name: - LOGGER.warn("Ignoring line %d because it has no name.", line) - continue - self._pins.append(Pin( - chip=chip, - flags=flags, - line_number=line, - name=name, - user=user, - )) - + self._load_pin(chip, line) def _read_config(configpath: pathlib.Path) -> None: with open(configpath, "rb") as f: diff --git a/pnpdevice/server.py b/pnpdevice/server.py index 22303e6..24b48d6 100644 --- a/pnpdevice/server.py +++ b/pnpdevice/server.py @@ -36,6 +36,7 @@ def index(request: Request): @app.get("/relay/create") def relay_create_get(request: Request): "Get the form to create a new relay." + relays.load_all_pins() pins = relays.pins return templates.TemplateResponse("relay-create.template.html", { "request": request,