{"id":13507388,"url":"https://github.com/entone/firmata","last_synced_at":"2026-02-18T21:02:23.206Z","repository":{"id":3118251,"uuid":"48397233","full_name":"entone/firmata","owner":"entone","description":"Firmata protocol in Elixir","archived":false,"fork":false,"pushed_at":"2020-09-17T14:23:40.000Z","size":521,"stargazers_count":50,"open_issues_count":0,"forks_count":11,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-24T08:56:19.457Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/entone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-12-21T22:22:11.000Z","updated_at":"2025-01-01T20:37:16.000Z","dependencies_parsed_at":"2022-07-18T09:09:11.937Z","dependency_job_id":null,"html_url":"https://github.com/entone/firmata","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entone%2Ffirmata","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entone%2Ffirmata/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entone%2Ffirmata/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/entone%2Ffirmata/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/entone","download_url":"https://codeload.github.com/entone/firmata/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246296325,"owners_count":20754623,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T02:00:32.760Z","updated_at":"2025-10-21T14:44:07.360Z","avatar_url":"https://github.com/entone.png","language":"Elixir","funding_links":[],"categories":["Audio and Sounds"],"sub_categories":[],"readme":"# Firmata\n\nThis package implements the Firmata protocol in Elixir.\n\nFirmata is a MIDI-based protocol for communicating with microcontrollers.\n\n## Feature Completeness\n\n**Implemented**\n\n* Parser\n* Handshake\n  * Retreiving Version\n  * Retreiving Firmware\n  * Retreiving Pin Capabilities\n  * Retreiving Analog Pin Mapping\n* Toggle Analog Channel Reporting\n* Set Pin Mode\n* Digital Write\n* I2C Read/Write\n* String Data\n\n**Planned**\n\n* Digital Read\n\n## Usage Example\n\nA cloneable test application is available here [https://github.com/entone/firmata_test](https://github.com/entone/firmata_test)\n\nThe examples are tested against StandardFirmata.ino v2.5\n\n### FirmataTest.Board\n```elixir\ndefmodule FirmataTest.Board do\n  use GenServer\n  use Firmata.Protocol.Mixin\n  require Logger\n\n  @i2c_channel 98\n  @read_bytes 32\n\n  defmodule State do\n    defstruct firmata: nil, sensors: []\n  end\n\n  def start_link(tty) do\n    GenServer.start_link(__MODULE__, tty, name: __MODULE__)\n  end\n\n  def init(tty) do\n    Logger.debug \"Starting Firmata on port: #{inspect tty}\"\n    {:ok, firmata} = Firmata.Board.start_link(tty, [], :hardware_interface)\n    Logger.info \"Firmata Started: #{inspect firmata}\"\n    #Start the firmata initialization\n    Firmata.Board.sysex_write(firmata, @firmware_query, \u003c\u003c\u003e\u003e)\n    {:ok, %State{firmata: firmata}}\n  end\n\n  def init_board(state) do\n    state |\u003e init_i2c |\u003e init_analog\n  end\n\n  defp init_i2c(state) do\n    #Tell firmata to enable i2c\n    Firmata.Board.sysex_write(state.firmata, @i2c_config, \u003c\u003c\u003e\u003e)\n    Process.send_after(self(), :read_i2c, 0)\n    state\n  end\n\n  defp init_analog(state) do\n    FirmataTest.Analog.start_link(state.firmata, 0, :humidity)\n    state\n  end\n\n  def handle_info(:read_i2c, state) do\n    #Send write command to i2c device on channel 98, writes \"R\" which is the read command for Atlas Scientific stamps\n    Firmata.Board.sysex_write(state.firmata, @i2c_request, \u003c\u003c@i2c_channel, @i2c_mode.write, \"R\"\u003e\u003e)\n    #most Atlas Scientific stamps take about 1000ms to return a value\n    :timer.sleep(1000)\n    #Read 32 bytes from i2c channel we wrote to a second ago.\n    #We will get the response in handle_info(:firmata, {:i2c_response: value})\n    Firmata.Board.sysex_write(state.firmata, @i2c_request, \u003c\u003c@i2c_channel, @i2c_mode.read, @read_bytes\u003e\u003e)\n    # Take a reading every second\n    Process.send_after(self(), :read_i2c, 1000)\n    {:noreply, state}\n  end\n\n  def handle_info({:firmata, {:pin_map, pin_map}}, state) do\n    #We wait until we know all the pin mappings before starting our interfaces\n    Logger.info \"Ready: Pin Map #{inspect pin_map}\"\n    {:noreply, state |\u003e init_board}\n  end\n\n  def handle_info({:elixir_serial, _serial, data}, %{board: board} = state) do\n    send(board, {:serial, data})\n    {:noreply, state}\n  end\n\n  def handle_info({:firmata, {:version, major, minor}}, state) do\n    Logger.info \"Firmware Version: v#{major}.#{minor}\"\n    {:noreply, state}\n  end\n\n  def handle_info({:firmata, {:firmware_name, name}}, state) do\n    Logger.info \"Firmware Name: #{name}\"\n    {:noreply, state}\n  end\n\n  def handle_info({:firmata, {:string_data, value}}, state) do\n    Logger.debug value\n    {:noreply, state}\n  end\n\n  def handle_info({:firmata, {:i2c_response, \u003c\u003cchannel::integer, 0, 0, 0, _rc::integer, value::binary\u003e\u003e} = payload}, state) do\n    Logger.debug \"Payload: #{inspect payload}\"\n    Logger.debug \"Channel: #{channel}\"\n    Logger.debug \"Raw Value: #{inspect value}\"\n    Logger.debug \"Parsed Value: #{inspect value |\u003e parse_ascii}\"\n    {:noreply, state}\n  end\n\n  def handle_info({:firmata, info}, state) do\n    Logger.error \"Unknown Firmata Data: #{inspect info}\"\n    {:noreply, state}\n  end\n\n  defp parse_ascii(data), do: for n \u003c- data, n != \u003c\u003c0\u003e\u003e, into: \"\", do: n\n\nend\n```\n\n### FirmataTest.Analog\n```elixir\ndefmodule FirmataTest.Analog do\n  use GenServer\n  require Logger\n  @report 1\n  @no_report 0\n\n  defmodule State do\n    defstruct firmata: nil, channel: nil, value: 0\n  end\n\n  def start_link(firmata, channel, name \\\\ nil) do\n    GenServer.start_link(__MODULE__, [firmata, channel], name: name)\n  end\n\n  def init([firmata, channel]) do\n    #Set our analog channel/pin to \"report\" which means to report values to this process\n    Firmata.Board.report_analog_channel(firmata, channel, @report)\n    {:ok, %State{firmata: firmata, channel: channel}}\n  end\n\n  def handle_info({:firmata, {:analog_read, channel, value}}, %{channel: s_channel} = state) when channel === s_channel do\n    Logger.debug \"#{__MODULE__} on #{channel}: #{inspect value}\"\n    #Update our state with the latest value\n    {:noreply, %State{state | value: value}}\n  end\n\nend\n```\n\n## Installation\n\nIf [available in Hex](https://hex.pm/docs/publish), the package can be installed as:\n\n  1. Add firmata to your list of dependencies in `mix.exs`:\n\n        def deps do\n          [{:firmata, \"~\u003e 0.0.2\"}]\n        end\n\n  2. Ensure firmata is started before your application:\n\n        def application do\n          [applications: [:firmata]]\n        end\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fentone%2Ffirmata","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fentone%2Ffirmata","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fentone%2Ffirmata/lists"}