Porting
September 26, 2025 ยท View on GitHub
Upgrading Circuits.I2C 1.0 projects to 2.0
Circuits.I2C 2.0 supports alternative I2C hardware and the ability to mock or
emulate devices via backends. The Linux i2c-dev backend is the default and this
matches Circuits.I2C 1.0. Most projects won't need any changes other than to
update the dependency in mix.exs. If upgrading a library, The following
dependency specification is recommended to allow both circuits_i2c versions:
{:circuits_i2c, "~> 2.0 or ~> 1.0"}
The following potentially breaking changes were made:
Circuits.I2C.open/1no longer accepts Erlang strings.- The
stubimplementation has been renamed toi2c_dev_test. If using the stub implementation for testing, you may have to update your tests since there were minor changes.
Upgrading Elixir/ALE projects to Circuits.I2C
The Circuits.I2C package is the next version of Elixir/ALE's I2C support.
If you're currently using Elixir/ALE, you're encouraged to switch. Here are some
benefits:
- Supported by both the maintainer of Elixir/ALE and a couple others. They'd
prefer to support
Circuits.I2Cissues. - Much faster than Elixir/ALE.
- Simplified API
Circuits.I2C uses Erlang's NIF interface. NIFs have the downside of being able
to crash the Erlang VM. Experience with Elixir/ALE has given many of us
confidence that this won't be a problem.
Code modifications
Circuits.I2C is not a GenServer, so if you've added ElixirALE.I2C to a
supervision tree, you'll have to take it out and manually call
Circuits.I2C.open to obtain a reference. A common pattern is to create a
GenServer that is descriptive of what the I2C device does and have it be
responsible for all I2C calls.
The remain modifications should mostly be mechanical:
- Rename references to
ElixirALE.I2CtoCircuits.I2Candelixir_aletocircuits_i2c - Change calls to
ElixirALE.I2C.start_link/2toCircuits.I2C.open/1. You'll need to remove the I2C address from the call to open. While you're at it, review the arguments to open to not include anyGenServeroptions. - Add the I2C device's bus address to all of the
read,write, andwrite_readcalls. We recommend making a short helper function that has the I2C address. - The
readandwrite_readfunctions now return{:ok, result}tuples on success so add code to handle that. Alternately, callread!orwrite_read!and they will raise an exception if there's an error. - Look for calls to
I2C.read_device,I2C.write_deviceandI2C.write_read_deviceand remove the_devicepart. - Consider adding a call to
Circuits.I2C.close/1if there's an obvious place to release the I2C. This is not strictly necessary since the garbage collector will free unreferenced I2C references. - If you manually implemented I2C bus retry logic, consider specifying the
:retriesoption to haveCircuits.I2Cretry for you. - Change calls to
ElixirALE.I2C.device_names/0toCircuits.I2C.bus_names/0.
If you find that you have to make any other changes, please let us know via an issue or PR so that other users can benefit.