Files
localiserd/lib/localiser/mqtt/router.ex
T
2026-04-16 15:46:00 +02:00

84 lines
2.1 KiB
Elixir

defmodule Localiser.MQTT.Router do
@moduledoc """
Module responsible for routing incoming MQTT messages to the appropriate handlers.
"""
use GenServer
require Logger
alias Localiser.Domain.Sensors
def start_link(opts) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end
def route(topic, payload) do
GenServer.cast(__MODULE__, {:route, topic, payload})
end
# GenServer Callbacks
@impl true
def init(_opts) do
{:ok, %{}}
end
@impl true
def handle_cast({:route, topic, payload}, state) do
case parse_topic(topic) do
{:rssi, sensor_id} ->
handle_rssi(sensor_id, payload)
{:announce, sensor_id} ->
handle_announce(sensor_id)
{:error, :invalid_topic} ->
Logger.debug("[MQTT.Router] Received message with invalid topic: #{topic}")
end
{:noreply, state}
end
# Private helper functions
defp parse_topic(topic) do
# Example topic: "localiser/sensor/device123/rssi"
case String.split(topic, "/") do
["localiser", "sensor", sensor_id, "rssi"] -> {:rssi, sensor_id}
["localiser", "sensor", sensor_id, "announce"] -> {:announce, sensor_id}
_ -> {:error, :invalid_topic}
end
end
defp handle_rssi(sensor_id, payload) do
with {:ok, %{"tag_id" => tag_id, "rssi" => rssi}} <-
Jason.decode(payload) do
reading = %{
sensor_id: sensor_id,
tag_id: tag_id,
rssi: rssi,
timestamp: DateTime.utc_now()
}
Localiser.MQTT.Telemetry.count_reading()
Localiser.RSSI.Buffer.push(reading)
else
{:error, reason} ->
Logger.error("[MQTT.Router] Bad payload from #{sensor_id}: #{inspect(reason)}")
Localiser.MQTT.Telemetry.count_error()
end
end
defp handle_announce(sensor_id) do
case Sensors.upsert_announced(sensor_id) do
{:ok, _sensor} ->
Logger.info("[MQTT.Router] Sensor announced: #{sensor_id}")
{:error, reason} ->
Logger.error("[MQTT.Router] Failed to register announced sensor #{sensor_id}: #{inspect(reason)}")
end
end
end