kevinschweikert

kevinschweikert

Nerves Home Assistant integration

I’ve had the idea to integrate Nerves devices into Home Assistant. The idea would be to communicate with Home Assistant which autodiscovers new devices and creates entities in Home Assistant to get all the wonderful features like a nice UI, historical data, automations, backup, interop with other devices and more for free.

My vision is to make device smart and integrate them easily into Home Assistant.

Some pseudo code could look like this:

defmodule MyNervesProject do
  use HomeAssistantNerves

  entity :sensor, :temperature do
    name "Living Room Temperature"
    unit_of_measurement "°C"
    device_class :temperature
    state_class :measurement
    
    state_fn fn -> 
      {:ok, temp} = YourTempSensor.read()
      temp
    end
    
    update_interval 60_000
  end
  
  entity :switch, :relay do
    name "Garage Light"
    
    state_fn fn -> 
      GPIO.read(pin)
    end
    
    on_command fn state -> 
      GPIO.write(pin, state)
    end
  end
end

This could be a nice use case for Build a Weather Station with Elixir and Nerves (PragProg)

But i’m still not a 100% sure on how to implement the communication layer between Nerves and Homeassistant. I see three options:

  1. MQTT
    Homeassistant offers a automatic device discovery with MQTT. This is very nice, because we wouldn’t have to create a custom integration and using native mechanics. The downside would be, that the user has to configure MQTT and run a broker (which should be already pretty common in a smart home but still)

  2. Native API
    Another option would be to directly hook in to the native APIs from Home Asssistant. This would had the same benefit of not writing a custom integration and also not having to use a MQTT broker but we would have to maintain the calls to the REST API (entity creation) and WebSocket API (realtime updates)

  3. Custom Integration
    This would be the most complex solution but also the most flexible. We could decide ourselves on how to communicate with the device (SSH, gRPC, WebSocket, TCP, HTTP) and implement Nerves only functionality into Home Assistant if there is a need for it. This would involve writing a custom integration in Home Assistant (which i’ve done for other devices, e.g. GitHub - kevinschweikert/ha-mahlkoenig: A homeassistant integration for the Mahlkönig X54 coffee grinder · GitHub) which acts as a translation layer.

  4. Any other ideas?

Before starting this adventure, is there anything you would wish for? Any ideas for improvements? Is there a need/interest in the community?

I’ve looked at other topics but they wanted to write a standalone smart home solution or just connect to the existing information in Home Assistant

Most Liked

kevinschweikert

kevinschweikert

Just a quick update:

The project is called homex and can be found at GitHub - kevinschweikert/homex: A bridge between Elixir and Home Assistant · GitHub .

There is a nerves example project at GitHub - kevinschweikert/Homex-Nerves-Example: An example project using Homex in Nerves · GitHub

I’m currenlty waiting on a new Hex release of the emqtt library which i am using as the MQTT client.

Some sample code:

defmodule HomexDemo.TemperatureSensor do
  @moduledoc """
  A Homex.Entity for the BME680 sensors temperature values
  """

  use Homex.Entity.Sensor,
    name: "bme680 temp",
    device_class: "temperature",
    unit_of_measurement: "°C"

  def handle_timer(entity) do
    {:ok, measurements} = BMP280.measure(BME680)
    entity |> set_value(Float.round(measurements.temperature_c, 2))
  end
end
defmodule HomexDemo.Relay do
  @moduledoc """
  A Homex.Entity for a relay.
  Uses `put_private/3` and `get_private/2` to keep the i2c bus handle in state and reference it
  """

  use Homex.Entity.Switch, name: "quiick_relay"

  def handle_init(entity) do
    {:ok, bus} = Circuits.I2C.open("i2c-1")
    entity |> put_private(:bus, bus) |> set_off()
  end

  def handle_on(entity) do
    bus = entity |> get_private(:bus)
    Circuits.I2C.write!(bus, 0x18, <<0x01>>)
    entity
  end

  def handle_off(entity) do
    bus = entity |> get_private(:bus)
    Circuits.I2C.write!(bus, 0x18, <<0x00>>)
    entity
  end
end

and some pictures

i will write an announcement post when the hex version is published. But in the meantime feel free to play around with it and give feedback!

kevinschweikert

kevinschweikert

After a bit of back and forth with @joshknz we came to the conclusion that the MQTT route would be the best to start from and see from there how the project evolves. Josh also made the point to look at Matter and see if that could be a more generic solution to make Nerves devices compatible with ecosystems like Apple HomeKit and Google Home instead of only Home Assistant. Home Assistant already supports Matter so that way would still be possible.

Inspiration came from GitHub - mtrudel/hap: A HomeKit Accessory Protocol (HAP) Implementation for Elixir · GitHub

We also talked about a more GenServer-ish implementation which could look like this:

defmodule LivingRoomTemo do
  use HomeAssistantNerves.Sensor,
    name: "Living Room Temperature",
    unit_of_measurement: "°C",
    device_class: :temperature,
    update_interval: Duration.new(seconds: 60)
    
  def handle_state(_temp) do
    YourTempSensor.read()
  end
end
  
defmodule Garage do
  use HomeAssistantNerves.Switch,
    name: "Garage Light"
    
  def handle_state(_state) do
    GPIO.read(pin)
  end

  def handle_command(:toggle, _state) do
    GPIO.write(pin, !state)
  end
end

The plan is to create a Repo and go from there and explore ideas. Will post the link here as soon as we have something to show!

kevinschweikert

kevinschweikert

It’s released! homex | Hex

Where Next?

Popular in Discussions Top

matthias_toepp
I’d love to hear what people think about Wisp, the new Gleam web framework started by Gleam’s primary creator Louis Pilfold. Gleam, alon...
New
marciol
Please, let me know if this kind of discussion already took place in another topic . Hi all, how do you consider if is better to build ...
New
mikl
I wanted to capitalize a string, and tried using String.capitalize(). That generally works well, until you try to capitalize a word like...
New
thojanssens1
It would be nice to be able to define a redirect from one route to another from the router.ex file. E.g.: redirect "/", UserController, ...
New
jer
I’ve been using umbrellas for a while, and generally started off (on greenfield projects at least) by isolating subapps based on clearly ...
New
PragTob
Hey everyone, this has been on my mind for some time and I’d love your input on it! TLDR: I feel like maps are superioer for storing and...
New
und0ck3d
Hello everyone! A few days ago I’ve created a topic here about how people were creating CMSs with Elixir and Phoenix. I’ve been studying...
New
AstonJ
Can you believe the first professionally published Elixir book was published just 8 years ago? Since then I think we’ve seen more books f...
New
Fl4m3Ph03n1x
Background A few days ago I was listening to The future of Elixir from Elixir Talks, with Dave Thomas (@pragdave ) and Brian Mitchell. I...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New

We're in Beta

About us Mission Statement