From ed96e044cf32ddb57a351698d740bbf04913bb50 Mon Sep 17 00:00:00 2001 From: dvdrw Date: Fri, 15 May 2026 15:23:58 +0200 Subject: [PATCH] feat: add factory_Reset, reconfigure_settings endpoints for sensors --- lib/localiser/domain/sensors.ex | 25 ++++++++++++++-- .../web/controllers/sensor_controller.ex | 30 +++++++++++++++++++ lib/localiser/web/router.ex | 2 ++ lib/localiser/web/schemas.ex | 22 ++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) diff --git a/lib/localiser/domain/sensors.ex b/lib/localiser/domain/sensors.ex index faf404b..884daed 100644 --- a/lib/localiser/domain/sensors.ex +++ b/lib/localiser/domain/sensors.ex @@ -54,9 +54,28 @@ defmodule Localiser.Domain.Sensors do |> Repo.update() end + def factory_reset(%Sensor{} = sensor) do + Localiser.MQTT.Connection.publish(cmd_topic(sensor), Jason.encode!(%{action: "factory_reset"})) + {:ok, sensor} + end + + # Pushes new WiFi and/or MQTT broker settings to the sensor. The sensor will + # apply the changes and restart. All keys are optional — omit any you don't + # want to change. Valid keys: "ssid", "password", "mqtt_host", "mqtt_port". + def reconfigure_settings(%Sensor{} = sensor, config) do + payload = Map.merge( + %{"action" => "reconfigure_settings"}, + Map.new(config, fn + {"mqtt_broker", v} -> {"mqtt_host", v} + entry -> entry + end) + ) + Localiser.MQTT.Connection.publish(cmd_topic(sensor), Jason.encode!(payload)) + {:ok, sensor} + end + def delete_sensor(%Sensor{} = sensor) do - topic = "localiser/sensor/#{sensor.sensor_id}/cmd" - Localiser.MQTT.Connection.publish(topic, Jason.encode!(%{command: "factory_reset"})) + factory_reset(sensor) Repo.delete(sensor) end @@ -164,6 +183,8 @@ defmodule Localiser.Domain.Sensors do end end + defp cmd_topic(sensor), do: "localiser/sensor/#{sensor.sensor_id}/cmd" + defp populate_floor_coords(%Sensor{room: nil} = sensor), do: sensor defp populate_floor_coords(%Sensor{room: room} = sensor) do diff --git a/lib/localiser/web/controllers/sensor_controller.ex b/lib/localiser/web/controllers/sensor_controller.ex index 723c65f..9e33e5e 100644 --- a/lib/localiser/web/controllers/sensor_controller.ex +++ b/lib/localiser/web/controllers/sensor_controller.ex @@ -77,6 +77,23 @@ defmodule Localiser.Web.Controllers.SensorController do unauthorized: {"Unauthorized", "application/json", Schemas.Error} ] + operation :factory_reset, + summary: "Send factory reset command to sensor", + parameters: [id: [in: :path, type: :integer, required: true]], + responses: [ + ok: {"Command sent", "application/json", Schemas.CommandSent}, + unauthorized: {"Unauthorized", "application/json", Schemas.Error} + ] + + operation :reconfigure, + summary: "Push new network settings to sensor", + parameters: [id: [in: :path, type: :integer, required: true]], + request_body: {"Reconfigure params", "application/json", Schemas.SensorReconfigureParams, required: true}, + responses: [ + ok: {"Command sent", "application/json", Schemas.CommandSent}, + unauthorized: {"Unauthorized", "application/json", Schemas.Error} + ] + operation :calibration_start, summary: "Begin RSSI calibration", parameters: [id: [in: :path, type: :integer, required: true]], @@ -181,6 +198,19 @@ defmodule Localiser.Web.Controllers.SensorController do end end + def factory_reset(conn, %{"id" => id}) do + sensor = Sensors.get_sensor!(id) + {:ok, _} = Sensors.factory_reset(sensor) + json(conn, %{status: "ok"}) + end + + def reconfigure(conn, %{"id" => id} = params) do + sensor = Sensors.get_sensor!(id) + config = Map.take(params, ["ssid", "password", "mqtt_broker", "mqtt_port"]) + {:ok, _} = Sensors.reconfigure_settings(sensor, config) + json(conn, %{status: "ok"}) + end + def calibration_start(conn, %{"id" => id, "reference_distance" => ref_dist}) do sensor = Sensors.get_sensor!(id) :ok = SensorServer.begin_calibration(sensor.sensor_id, ref_dist) diff --git a/lib/localiser/web/router.ex b/lib/localiser/web/router.ex index e1eb8d2..76758bc 100644 --- a/lib/localiser/web/router.ex +++ b/lib/localiser/web/router.ex @@ -82,6 +82,8 @@ defmodule Localiser.Web.Router do delete "/sensors/:id", SensorController, :delete put "/sensors/:id/place", SensorController, :place delete "/sensors/:id/place", SensorController, :unplace + post "/sensors/:id/factory_reset", SensorController, :factory_reset + post "/sensors/:id/reconfigure", SensorController, :reconfigure post "/sensors/:id/calibration/start", SensorController, :calibration_start post "/sensors/:id/calibration/stop", SensorController, :calibration_stop end diff --git a/lib/localiser/web/schemas.ex b/lib/localiser/web/schemas.ex index 2fbb815..6694660 100644 --- a/lib/localiser/web/schemas.ex +++ b/lib/localiser/web/schemas.ex @@ -124,6 +124,15 @@ defmodule Localiser.Web.Schemas do }) end + defmodule CommandSent do + require OpenApiSpex + OpenApiSpex.schema(%{ + title: "CommandSent", type: :object, + properties: %{status: %Schema{type: :string, enum: ["ok"]}}, + required: [:status] + }) + end + defmodule CalibrationStatus do require OpenApiSpex OpenApiSpex.schema(%{ @@ -246,6 +255,19 @@ defmodule Localiser.Web.Schemas do }) end + defmodule SensorReconfigureParams do + require OpenApiSpex + OpenApiSpex.schema(%{ + title: "SensorReconfigureParams", type: :object, + properties: %{ + ssid: %Schema{type: :string}, + password: %Schema{type: :string, format: :password}, + mqtt_broker: %Schema{type: :string, required: false}, + mqtt_port: %Schema{type: :integer, required: false} + } + }) + end + defmodule SensorUpdateParams do require OpenApiSpex OpenApiSpex.schema(%{