73 lines
2.0 KiB
Elixir
73 lines
2.0 KiB
Elixir
defmodule Localiser.RSSI.Buffer do
|
|
use GenServer
|
|
|
|
alias Localiser.Localisation
|
|
alias Localiser.Localisation.Tag.Filter, as: TagFilter
|
|
alias Localiser.Localisation.Sensor.Server, as: SensorServer
|
|
|
|
@flush_interval_ms 500
|
|
|
|
# reading :: %{sensor_id: String.t(), tag_id: String.t(), rssi: integer()}
|
|
def push(reading) do
|
|
GenServer.cast(__MODULE__, {:push, reading})
|
|
end
|
|
|
|
def start_link(_args) do
|
|
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
|
|
end
|
|
|
|
@impl true
|
|
def init(state) do
|
|
schedule_flush()
|
|
{:ok, state}
|
|
end
|
|
|
|
@impl true
|
|
def handle_cast({:push, %{tag_id: tag_id} = reading}, state) do
|
|
{:noreply, Map.update(state, tag_id, [reading], &[reading | &1])}
|
|
end
|
|
|
|
@impl true
|
|
def handle_info(:flush, state) do
|
|
flush_batches(state)
|
|
schedule_flush()
|
|
{:noreply, %{}}
|
|
end
|
|
|
|
defp flush_batches(batches) do
|
|
Enum.each(batches, fn {tag_id, readings} ->
|
|
case Registry.lookup(Localiser.Registry, {:filter, tag_id}) do
|
|
[{_pid, _}] ->
|
|
measurements = Enum.flat_map(readings, &resolve_measurement/1)
|
|
if measurements != [], do: TagFilter.ingest(tag_id, measurements)
|
|
|
|
[] ->
|
|
:ok
|
|
end
|
|
end)
|
|
end
|
|
|
|
# Resolves a raw RSSI reading to a measurement with sensor location and distance.
|
|
# If the sensor is in calibration mode, feeds the reading to Sensor.Server instead
|
|
# and returns [] so the sample is excluded from Tag.Filter measurements.
|
|
# If the sensor server isn't running, returns [].
|
|
defp resolve_measurement(%{sensor_id: sensor_id, rssi: rssi}) do
|
|
case Registry.lookup(Localiser.Registry, {:sensor, sensor_id}) do
|
|
[{_pid, _}] ->
|
|
if SensorServer.calibrating?(sensor_id) do
|
|
SensorServer.calibration_reading(sensor_id, rssi)
|
|
[]
|
|
else
|
|
[SensorServer.measure(sensor_id, rssi)]
|
|
end
|
|
|
|
[] ->
|
|
[]
|
|
end
|
|
end
|
|
|
|
defp schedule_flush do
|
|
Process.send_after(self(), :flush, @flush_interval_ms)
|
|
end
|
|
end
|