Circuits.GPIO and multiple buttons/sensors?

Hello! I’m currently building a weather station with sensors for wind, rain and temperature in elixir with Circuits.GPIO lib.

So far it has been a blast but I’ve gotten stuck on reading two sensors (eg buttons) and I assume it’s because the functional nature of elixir. My code:

defmodule WeatherStation do
  use GenServer
  require Logger

  @wind_sensor_pin 5
  @rain_sensor_pin 6

  def start_link(_opts) do
    GenServer.start_link(__MODULE__, [], name: __MODULE__)
  end

  def init(_opts) do
    {:ok, _gpio} = Circuits.GPIO.open(@rain_sensor_pin, :input)
    {:ok, gpio} = Circuits.GPIO.open(@wind_sensor_pin, :input)

    Circuits.GPIO.set_interrupts(gpio, :falling)
    {:ok, gpio}
  end

  def handle_info({:circuits_gpio, @rain_sensor_pin, _timestamp, _value}, state) do
    # handle stuff
  end

Obviously above don’t work (button presses is not sent) as I intended so my question is how to organize your code when you have more than one button/sensor in the GPIO lib.

Should I have a genserver for each sensor?

I haven’t used Circuits.GPIO, but the warning from the documentation for set_interrupts suggests that you always need to capture the reference returned from open:

NOTE: You will need to store the Circuits.GPIO reference somewhere (like your GenServer’s state) so that it doesn’t get garbage collected. Event messages stop when it gets collected. If you only get one message and you are expecting more, this is likely the case.

Also, set_interrupts appears to operate on one pin at a time. Taking both into account, your init could be:

def init(_opts) do
  {:ok, rain_pin} = Circuits.GPIO.open(@rain_sensor_pin, :input)
  Circuits.GPIO.set_interrupts(rain_pin, :falling)

  {:ok, wind_pin} = Circuits.GPIO.open(@wind_sensor_pin, :input)
  Circuits.GPIO.set_interrupts(wind_pin, :falling)

  {:ok, {rain_pin, wind_pin}}
end

Welp, that makes perfect sense. Didnt really know how to store the state in my genserver but obviously the state can be anything! Silly me.Thank you!