defmodule Localiser.Localisation.Sensor.Manager do @moduledoc """ GenServer that subscribes to the "sensors" PubSub topic and manages Sensor.Server lifecycle for a specific floor. - {:sensor_enrolled, sensor, room} → start Sensor.Server if not already running - {:sensor_unenrolled, sensor_id} → terminate the Sensor.Server for this floor """ use GenServer alias Localiser.Localisation.Sensor def start_link(floor) do GenServer.start_link(__MODULE__, floor.id, name: via(floor.id)) end def via(floor_id) do {:via, Registry, {Localiser.Registry, {:sensor_manager, floor_id}}} end @impl true def init(floor_id) do Phoenix.PubSub.subscribe(Localiser.PubSub, "sensors") {:ok, %{floor_id: floor_id}} end # Sensor placed (or moved) onto this floor's layout. @impl true def handle_info({:sensor_enrolled, sensor, %{floor_id: floor_id} = room}, %{floor_id: floor_id} = state) do case Registry.lookup(Localiser.Registry, {:sensor, sensor.sensor_id}) do [] -> Sensor.Supervisor.start_sensor_server(floor_id, sensor, room) _ -> :ok # Sensor.Server is already running and handles position via its own PubSub sub end {:noreply, state} end # Sensor removed from layout — stop the server for this floor if it's running. def handle_info({:sensor_unenrolled, sensor_id}, %{floor_id: floor_id} = state) do case Registry.lookup(Localiser.Registry, {:sensor, sensor_id}) do [{pid, _}] -> DynamicSupervisor.terminate_child(Sensor.Supervisor.via(floor_id), pid) [] -> :ok end {:noreply, state} end # Ignore all other PubSub broadcasts (sensor announced, calibration_complete, etc.) def handle_info(_msg, state), do: {:noreply, state} end