Installation

Add location_simulator to your mix.exs dependencies:

def deps do
  [
    {:location_simulator, "~> 1.0}
  ]
end

Then run mix deps.get.

Quick start

Start the simulator with default config — fires GPS events using the built-in LoggerEvent callback:

LocationSimulator.start()

You'll see output like:

[info] Start location worker: 1, timestamp: 1700000000
[info] 1, new GPS: %{lat: 60.0, lon: 87.0, ele: 0, timestamp: ...}
[info] 1 is stopped, time: 0s, success: 1, failed: 0, error: 0

Define a pipeline module that declares your simulation structure:

defmodule MyApp.Simulation do
  use LocationSimulator.Pipeline

  source :synthetic, direction: :north_east, elevation: 100

  plug LocationSimulator.Plug.Callback, callback: MyApp.GpsHandler
end

LocationSimulator.start(MyApp.Simulation, worker: 3, event: 100, interval: 1_000)

With a callback module

defmodule MyApp.GpsHandler do
  @behaviour LocationSimulator.Event

  @impl true
  def start(config, _state), do: {:ok, config}

  @impl true
  def event(config, %{gps: gps}) do
    IO.inspect(gps, label: "GPS")
    {:ok, config}
  end

  @impl true
  def stop(config, state) do
    IO.puts("Done: #{state.success} ok, #{state.failed} failed")
    {:ok, config}
  end
end

Legacy API

If you prefer a flat config map:

LocationSimulator.start(%{
  worker: 3,
  event: 100,
  interval: 1_000,
  direction: :north,
  callback: MyApp.GpsHandler
})

Runtime config reference

KeyType / ValuesDefault
:workerpos_integer()1
:eventpos_integer() | :infinity1
:intervalpos_integer() | :gpx_time100 ms
:random_rangenon_neg_integer()10 ms
:directiondirection atom:random
:elevationinteger()0
:elevation_way:up | :down | :no_up_down:no_up_down
:callbackmodule implementing EventLocationSimulator.LoggerEvent
:group_idany()nil
:gpx_fileglob stringnil
:started_gps{lat, lon, ele}nil