defmodule PMSA003I do use GenServer require Logger alias PMSA003I.Comm @default_polling_interval_ms 10_000 def start_link(init_arg \\ []) do options = Keyword.take(init_arg, [:name]) GenServer.start_link(__MODULE__, init_arg, options) end def measure(pid) do GenServer.call(pid, :measure) end @impl true @spec init(keyword) :: {:ok, %{device_addr: any, i2c: reference, last_reading: PMSA003I.Measurement.t()}} def init(options \\ []) do # Sample options keyword list : # [transport: {"i2c-1", 0x5B}] # [polling_interval: 5_000] polling_interval = Keyword.get(options, :polling_interval, @default_polling_interval_ms) Logger.info("Starting PMSA00I : Polling interval : #{polling_interval}") :timer.send_interval(polling_interval, :measure) state = %{ init_done: false, options: options, i2c: nil, device_addr: nil, last_reading: nil } {:ok, state} end defp deferred_init(%{init_done: false, options: options} = state) do # Having a deferred init can help main application using this sensor # to start event if the sensor has been removed. {bus_name, device_addr} = Keyword.get(options, :transport, Comm.discover()) Logger.info("Starting (deferred) PMSA00I on bus: #{bus_name}, address: #{device_addr} ") i2c = Comm.open(bus_name) %{ state | init_done: true, i2c: i2c, device_addr: device_addr } end defp deferred_init(state) do state end @impl true def handle_info( :measure, state ) do state = deferred_init(state) %{i2c: i2c, device_addr: device_addr} = state {:noreply, %{ state | last_reading: PMSA003I.Register.read(i2c, device_addr) }} end @impl true def handle_call(:measure, _from, state) do {:reply, {:ok, state.last_reading}, state} end end