defmodule SCD30 do use GenServer require Logger alias SCD30.Comm @default_polling_interval_ms 10_000 @default_measuring_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 def init(options \\ []) do # Sample options keyword list : # [transport: {"i2c-1", 0x5B}] # [polling_interval: 10_000] # [measuring_interval: 10_000] polling_interval = Keyword.get(options, :polling_interval, @default_polling_interval_ms) measuring_interval = Keyword.get(options, :measuring_interval, @default_measuring_interval_ms) {bus_name, device_addr} = Keyword.get(options, :transport, Comm.discover()) Logger.info( "Starting PMSA00I on bus: #{bus_name}, address: #{device_addr} : " <> "Polling interval : #{polling_interval}" ) i2c = Comm.open(bus_name) SCD30.Cmds.MEASUREMENT_INTERVAL.set(i2c, device_addr, div(measuring_interval, 1000)) SCD30.Cmds.CONTINUOUS_MEASUREMENT.start(i2c, device_addr) :timer.send_interval(polling_interval, :measure) state = %{ i2c: i2c, device_addr: device_addr, last_reading: %SCD30.Measurement{} } {:ok, state} end @impl true def handle_info( :measure, %{i2c: i2c, device_addr: device_addr} = state ) do updated_with_reading = case SCD30.Cmds.DATA_READY.read(i2c, device_addr) do true -> %{ state | last_reading: SCD30.Cmds.READ_MEASUREMENT.read(i2c, device_addr) } _ -> state end {:noreply, updated_with_reading} end @impl true def handle_call(:measure, _from, state) do {:reply, {:ok, state.last_reading}, state} end end