{"id":21658168,"url":"https://github.com/rzetterberg/elmobd","last_synced_at":"2026-01-12T00:42:01.464Z","repository":{"id":26144969,"uuid":"105164632","full_name":"rzetterberg/elmobd","owner":"rzetterberg","description":"A Go library for talking to cars over OBD-II","archived":false,"fork":false,"pushed_at":"2024-05-29T16:41:45.000Z","size":230,"stargazers_count":208,"open_issues_count":5,"forks_count":36,"subscribers_count":19,"default_branch":"master","last_synced_at":"2024-06-18T17:16:22.923Z","etag":null,"topics":["automotive","cars","go","golang","obd-ii","obd2"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rzetterberg.png","metadata":{"files":{"readme":"README.org","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2017-09-28T15:19:01.000Z","updated_at":"2024-05-29T13:52:01.000Z","dependencies_parsed_at":"2024-04-26T10:30:41.277Z","dependency_job_id":"b5f95104-6cbe-4332-a502-bb210c18ea53","html_url":"https://github.com/rzetterberg/elmobd","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/rzetterberg%2Felmobd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rzetterberg%2Felmobd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rzetterberg%2Felmobd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rzetterberg%2Felmobd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rzetterberg","download_url":"https://codeload.github.com/rzetterberg/elmobd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226304428,"owners_count":17603590,"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":["automotive","cars","go","golang","obd-ii","obd2"],"created_at":"2024-11-25T09:28:48.763Z","updated_at":"2026-01-12T00:42:01.458Z","avatar_url":"https://github.com/rzetterberg.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# -*- org-confirm-babel-evaluate: nil -*-\n\n* README\n\n[[file:https://img.shields.io/badge/status-active-green.svg]]\n[[https://travis-ci.org/rzetterberg/elmobd][file:https://travis-ci.org/rzetterberg/elmobd.svg?branch=master]]\n[[https://goreportcard.com/report/github.com/rzetterberg/elmobd][file:https://goreportcard.com/badge/github.com/rzetterberg/elmobd?status.svg]]\n[[https://godoc.org/github.com/rzetterberg/elmobd][file:https://godoc.org/github.com/rzetterberg/elmobd?status.svg]]\n\n#+NAME: version_output\n#+begin_src emacs-lisp :results raw :exports results\n(with-temp-buffer\n  (insert-file-contents \"./VERSION\")\n  (format \"- Version :: %s\" (buffer-string))))\n#+end_src\n\n#+RESULTS: version_output\n- Version :: 0.8.0\n\nGo library for communicating with cars [[https://en.wikipedia.org/wiki/On-board_diagnostics][OBD-II]] system using [[https://www.elmelectronics.com/ic/elm327/][ELM327]] based\nUSB-devices.\n\nTo make this library as good as possible - feedback, bug reports and feature\nrequests are very welcome in the GitHub issues of this project.\n\n** How it works\n\nThere are more than 10 different OBD-II signal protocol variations used by the\nvarious cars that exist. To avoid having to handle all the details of these\nprotocols the ELM327 exists. The ELM327 acts a [[https://en.wikipedia.org/wiki/Facade_pattern][facade]] between the computer and\nthe car. You talk to the ELM327 using a simple text based protocol similar to\nthe [[https://en.wikipedia.org/wiki/Hayes_command_set][Hayes command set]] and the ELM327 takes care of the communication details\nof the car.\n\n#+LATEX: \\vspace{0.5cm}\n#+LATEX: \\begin{center}\n#+ATTR_LATEX: :width 8cm\n#+RESULTS: fig:overview\n[[file:docs/assets/overview-diagram.png]]\n#+LATEX: \\end{center}\n\nAs shown in the diagram above this library connects to a serial device of the\noperating system. The library is not concerned with what is connected to that\nserial device, whether it's a bluetooth USB-dongle with a ELM327 at the other\nend or a ELM327 connected directly via an USB-cable.\n\nCommunicating with the ELM327 is similar to communicating with a web server.\nYou make a *request* and wait for a *response*. However, in this context we are\n*calling a command* and waiting for *one or more responses*.\n\nThis library is designed to be used in a way that resembles the way you\nphysically use the device. You have a type called ~Device~ that represents\na ELM327 device connected to the computer. This ~Device~ then has a function\ncalled ~RunCommand~ that sends a command to the actual device and then waits\nfor a response.\n\nThis library aims to be as type safe as possible, which means that you don't\ndeal with raw text commands, instead you have different command /types/.\n\nAll command /types/ need to implement the ~OBDCommand~ /interface/ to be\nable to be run on the device. Since there are A LOT of OBD commands, you can\neasily extend this library, by just implementing the ~OBDCommand~ /interface/\nof your commands.\n\nLet's start by looking at some example of how you use the library.\n\n** Example usage\n\n*Note:* these examples are performed on Linux. If you are using another platform\nthere should be minimal changes, but they are not documented yet. Go ahead\nand put a :+1: on issue #11 if you think this should be prioritized.\n\nFirst of all, you need to plug in your ELM327 device into your computer and\nget the path to the device. You can plugin the device and check dmesg, this is\nwhat I get on my computer:\n\n#+BEGIN_EXAMPLE\n$ dmesg | tail\n[359720.858480] usb 6-2: Manufacturer: FTDI\n[359720.858482] usb 6-2: SerialNumber: A503GJEX\n[359720.897717] usbcore: registered new interface driver usbserial\n[359720.897733] usbcore: registered new interface driver usbserial_generic\n[359720.897748] usbserial: USB Serial support registered for generic\n[359720.901755] usbcore: registered new interface driver ftdi_sio\n[359720.901767] usbserial: USB Serial support registered for FTDI USB Serial Device\n[359720.901839] ftdi_sio 6-2:1.0: FTDI USB Serial Device converter detected\n[359720.901913] usb 6-2: Detected FT232RL\n[359720.904481] usb 6-2: FTDI USB Serial Device converter now attached to ttyUSB0\n#+END_EXAMPLE\n\nNow that I know that the device is available at ~/dev/ttyUSB0~ I can use the\nlibrary to connect to the device and check the ~ELM327~ version of the device:\n\n*example1.go*\n#+NAME: src:example1\n#+BEGIN_SRC go :tangle ./examples/example_1/main.go :mkdirp yes\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"github.com/rzetterberg/elmobd\"\n)\n\nfunc main() {\n\tserialPath := flag.String(\n\t\t\"serial\",\n\t\t\"/dev/ttyUSB0\",\n\t\t\"Path to the serial device to use\",\n\t)\n\n\tflag.Parse()\n\n\tdev, err := elmobd.NewTestDevice(*serialPath, false)\n\n\tif err != nil {\n\t\tfmt.Println(\"Failed to create new device\", err)\n\t\treturn\n\t}\n\n\tversion, err := dev.GetVersion()\n\n\tif err != nil {\n\t\tfmt.Println(\"Failed to get version\", err)\n\t\treturn\n\t}\n\n\tfmt.Println(\"Device has version\", version)\n}\n#+END_SRC\n\n*Note:* These examples uses the function ~NewTestDevice~, which uses a mocked\nELM327 device. To use a real ELM327 device, you instead use ~NewDevice~. The\nreason why a mocked device is used is because the examples should be runnable\nwithout using a real device.\n\n#+BEGIN_EXAMPLE\n$ go run example.go\nDevice has version OBDII by elm329@gmail.com\n#+END_EXAMPLE\n\nThe next step is to run some OBD commands on the device. For this we need to\nplug in the ELM327 into our car and turn on the ignition.\n\nLike mentioned before you use the function ~RunCommand~ that accepts a\n~OBDCommand~ to run. A ~OBDCommand~ has 3 responsibilities:\n\n- Tell the ELM327 what command to run\n- Store the value\n- Convert the value to a common format\n\nSo you start out by creating a new ~OBDCommand~ that does not contain a value.\nYou then take that ~OBDCommand~ and call the ~RunCommand~ function with it.\n~RunCommand~ will then return the ~OBDCommand~ with the value from the car.\n\nLet's try this out by checking the RPM of the engine. There is a ~OBDCommand~\nfor that defined in the library already, called ~EngineRPM~. We start by\ncreating a new ~EngineRPM~ that we call ~RunCommand~ with:\n\n*example2.go*\n#+NAME: src:example2\n#+BEGIN_SRC go :tangle ./examples/example_2/main.go :mkdirp yes\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"github.com/rzetterberg/elmobd\"\n)\n\nfunc main() {\n\tserialPath := flag.String(\n\t\t\"serial\",\n\t\t\"/dev/ttyUSB0\",\n\t\t\"Path to the serial device to use\",\n\t)\n\n\tflag.Parse()\n\n\tdev, err := elmobd.NewTestDevice(*serialPath, false)\n\n\tif err != nil {\n\t\tfmt.Println(\"Failed to create new device\", err)\n\t\treturn\n\t}\n\n\trpm, err := dev.RunOBDCommand(elmobd.NewEngineRPM())\n\n\tif err != nil {\n\t\tfmt.Println(\"Failed to get rpm\", err)\n\t\treturn\n\t}\n\n\tfmt.Printf(\"Engine spins at %s RPMs\\n\", rpm.ValueAsLit())\n}\n#+END_SRC\n\nThere are more than 180 different OBD commands, and cars have different support\nfor these commands. So to avoid sending OBD commands to the car that it does not\nsupport we can check what commands the car support:\n\n*example3.go*\n#+NAME: src:example3\n#+BEGIN_SRC go :tangle ./examples/example_3/main.go :mkdirp yes\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"github.com/rzetterberg/elmobd\"\n)\n\nfunc main() {\n\tserialPath := flag.String(\n\t\t\"serial\",\n\t\t\"/dev/ttyUSB0\",\n\t\t\"Path to the serial device to use\",\n\t)\n\n\tflag.Parse()\n\n\tdev, err := elmobd.NewTestDevice(*serialPath, false)\n\n\tif err != nil {\n\t\tfmt.Println(\"Failed to create new device\", err)\n\t\treturn\n\t}\n\n\tsupported, err := dev.CheckSupportedCommands()\n\n\tif err != nil {\n\t\tfmt.Println(\"Failed to check supported commands\", err)\n\t\treturn\n\t}\n\n\trpm := elmobd.NewEngineRPM()\n\n\tif supported.IsSupported(rpm) {\n\t\tfmt.Println(\"The car supports checking RPM\")\n\t} else {\n\t\tfmt.Println(\"The car does NOT supports checking RPM\")\n\t}\n}\n#+END_SRC\n\nThe ~supported~ here is a ~SupportedCommands~ which is a special type that\nstores the raw lookup table and exposes two helper functions that reads this\ntable:\n\n- ~IsSupported~ :: Check if given command is supported\n- ~FilterSupported~ :: Filters out supported commands from given list\n\nFor simplicity there's a function called ~GetSensorCommands~ which gives you a\nlist of all the commands defined in the library. You can use this list of\ncommands and filter out what commands are supported on by car:\n\n*example4.go*\n#+NAME: src:example4\n#+BEGIN_SRC go :tangle ./examples/example_4/main.go :mkdirp yes\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"github.com/rzetterberg/elmobd\"\n)\n\nfunc main() {\n\tserialPath := flag.String(\n\t\t\"serial\",\n\t\t\"/dev/ttyUSB0\",\n\t\t\"Path to the serial device to use\",\n\t)\n\n\tflag.Parse()\n\n\tdev, err := elmobd.NewTestDevice(*serialPath, false)\n\n\tif err != nil {\n\t\tfmt.Println(\"Failed to create new device\", err)\n\t\treturn\n\t}\n\n\tsupported, err := dev.CheckSupportedCommands()\n\n\tif err != nil {\n\t\tfmt.Println(\"Failed to check supported commands\", err)\n\t\treturn\n\t}\n\n\tallCommands := elmobd.GetSensorCommands()\n\tcarCommands := supported.FilterSupported(allCommands)\n\n\tfmt.Printf(\"%d of %d commands supported:\\n\", len(carCommands), len(allCommands))\n\n\tfor _, cmd := range carCommands {\n\t\tfmt.Printf(\"- %s supported\\n\", cmd.Key())\n\t}\n}\n#+END_SRC\n\nBesides checking sensor values, you can also check whether the [[https://en.wikipedia.org/wiki/Check_engine_light][MIL]] is on and if there are\nany [[https://en.wikipedia.org/wiki/On-board_diagnostics#EOBD_fault_codes][DTCs]]:\n\n*example5.go*\n#+NAME: src:example5\n#+BEGIN_SRC go :tangle ./examples/example_5/main.go :mkdirp yes\npackage main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"github.com/rzetterberg/elmobd\"\n)\n\nfunc main() {\n\tserialPath := flag.String(\n\t\t\"serial\",\n\t\t\"/dev/ttyUSB0\",\n\t\t\"Path to the serial device to use\",\n\t)\n\n\tflag.Parse()\n\n\tdev, err := elmobd.NewTestDevice(*serialPath, false)\n\n\tif err != nil {\n\t\tfmt.Println(\"Failed to create new device\", err)\n\t\treturn\n\t}\n\n\tcmd, err := dev.RunOBDCommand(elmobd.NewMonitorStatus())\n\n\tif err != nil {\n\t\tfmt.Println(\"Failed to get monitor status\", err)\n\t\treturn\n\t}\n\n        status := cmd.(*elmobd.MonitorStatus)\n\n\tfmt.Printf(\"MIL is on: %t, DTCamount: %d\\n\", status.MilActive, status.DtcAmount)\n}\n#+END_SRC\n\nPlease see [[https://godoc.org/github.com/rzetterberg/elmobd][the godocs]] for a more detailed explanation of the library and it's\nstructure.\n\n** Features\n\n- [X] Reading sensor data\n- [ ] Reading trouble codes\n- [ ] Resetting Check Engine Light\n- [ ] Reading freezed sensor data\n\n** Roadmap\n\nThe project uses quarterly milestones to plan upcoming changes. The current\nquarter will focus on implementing new features. To see the details of what\nwill be done see the milestone [[https://github.com/rzetterberg/elmobd/milestone/4][2018 Q3]].\n\nChanges of the library are tracked in the [[file:CHANGELOG.md][CHANGELOG]].\n\n** Compability\n\n*** Platforms\n\nThe library has been built and tested on the following platforms:\n\n| Operating system    | Go version |\n|---------------------+------------|\n| Linux 4.9.25 x86_64 | 1.9        |\n\n*** Cars\n\nThe library has been used successfully on the following cars:\n\n| Car                       | Library version | Tester       |\n|---------------------------+-----------------+--------------|\n| Lexus IS200 Manual 2004   |           0.3.0 | @rzetterberg |\n| Ford Ka 2011              |           0.5.0 | @Enrico204   |\n| Ford Transit Automat 2019 |           0.6.0 | @mikspec     |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frzetterberg%2Felmobd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frzetterberg%2Felmobd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frzetterberg%2Felmobd/lists"}