ConnorRigby / my_sensors

Elixir Library for https://www.mysensors.org/
MIT License
6 stars 1 forks source link

Ability to use MySensors.Gateway and define a "callback" on new sensor value? #2

Closed stevenproctor closed 6 years ago

stevenproctor commented 6 years ago

There is the ability to write to a sensor via MySensors.Gateway.write_packet, but there is no ability to act on an event wherein the gateway receives an event from a sensor.

I my specific case it would be useful as it would allow me to post back to MQTT for that event, but it could be generic enough that logic could be plugged in against events.

If this is done, and thought through, it could allow someone to even go so crazy as to do push notifications to phones via AWS SNS notifications if so desired. An example from a co-worker was if temperature in my freezer goes above such text me because my food might spoil.

It seems like it could fit below:

  defp do_handle_packet(%Packet{command: @command_SET} = packet, state) do
    case Context.save_sensor_value(packet) do
      {:ok, %SensorValue{}} -> 
          <<notify new sensor value>>
          state
      err -> err
    end
  end

How would you think of doing this? Registering a list of callback functions to be executed as Tasks? Having a gen_event that people can register to?

I would be happy to take a shot at this, but wanted to put the idea out there and see if this was something that might fit in your vision of where you are going with this, and ideas of how you might best have this fit.

ConnorRigby commented 6 years ago

So sorry for the long wait, i haven't looked at this repo in quite a while. I'm not super happy with a regular "callback" registry, just because that isn't "very OTP". But I do have some ideas.

define a behaviour and server mechanism.

This would be similar to gen_server and GenServer

defmodule MyApp.MySensorsHandler do
   use MySensors.Handler

   def start_link(opts) do
      MySensorsHandler.start_link(__MODULE__, opts, [name: __MODULE__])
   end

   def init(_opts) do
      {:ok, initial_state}
   end

   def handle_node(data,state)
   def handle_sensor(data,state)
end

Generic dispatch mechanism

The other case is we could just have a normal pubsub dispatch mechanism. So this lib could expose an api as such:

iex()> MySensors.Registry.subscribe(self())
iex()> flush
{:node, 10, {:sensor, 2, :value, 1}}
{:node, 10, {:sensor, 2, :value, 0}}
:ok
iex()>

Let me know which you think might be better. I'm leaning more toward the second version, but the first version is more OTP like.

ConnorRigby commented 6 years ago

I've implemented a broadcast mechanism. See the moduledoc

MySensors.Broadcast.subscribe()
# bring a node online etc
flush()
{:my_sensors, {:insert_or_update, %Node{}}}