NMEA2000 is a C++ library that hides the protocol and keeps the data handling
NMEA2000 library for Arduino
At a glance
- What is it?
- The NMEA2000 library is an object oriented C++ library for building devices on a NMEA 2000 bus, and its design promise is that the protocol requirements are handled for you, leaving only the interesting data handling for the developer. It has been used in several commercial certified devices, and the fourteen examples in the tree are the fastest way to see what it covers.
- Who is it for?
- Adopt NMEA2000 if you are building a device that sits on a NMEA 2000 bus and you would rather spend your time on the data than on the protocol, since the library takes care of the mandatory requirements and has been used in certified commercial devices. Skip it if you are not on a supported board or you cannot write a CAN driver, because the portability beyond Arduino relies on that.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The promise is that only the data handling is left for you
NMEA2000 library is object oriented C++ library for developing NMEA2000 bus devices, and the sentence that follows is the whole pitch. The library fulfills automatically the NMEA 2000 mandatory requirements, leaving only interesting data handling for the developer.
That is a specific and unusual claim for a protocol library. Most libraries in this space give you the encoding and the framing and leave you to implement the device address handling, the request and response pairing, the periodic update scheduling and the heartbeats, and those requirements are where most first-time implementations go wrong. The claim here is that those obligations are already met.
The credibility claim is attached to it. The library has been used in several commercial certified NMEA2000 devices, which is the strongest evidence available from inside the project itself, since certified devices are ones where the protocol handling was audited by somebody with consequences.
The library was originally developed for Arduino based boards in 2015, and as far as the author knows it has been used and tested with Teensy, ESP, some Arduino, MBED and Rasberry boards. The portability claim for anything else is spelled out as the mechanism: the library can be used also in other systems by writing a compatible CAN driver and necessary classes for other hardware specific functions.
So the abstraction boundary is the CAN driver. Everything above the CAN frames is the library's job, and everything below is yours.
The project is C++, MIT licensed, with the copyright held by Timo Lappalainen of Kave Oy from 2015 to 2026. The last push was on 2026-10-19 and there are no GitHub releases, so the repository is the distribution route.
The device types it covers are the whole boat
The list of device kinds the library supports is the quickest way to understand the scope, and it reads like an inventory of a modern vessel.
Sensor transducers are first, with the examples naming battery, temperature, wind and engine sensors. Then NMEA2000 information displays. Then the NMEA2000 to PC interface, with the Actisense NGT1 named as the example of that device. And then the converters, in both directions, NMEA0183 to NMEA2000 and NMEA2000 to NMEA0183.
The converters deserve a note, because they are the part of a boat's data path that is easiest to forget. A NMEA 2000 bus is not where a legacy instrument or an autopilot head plugs in, and a NMEA 0183 to NMEA 2000 converter is a real product with real demand. The library claims to cover that bridging case as well as the native device case, which means a project can start with an existing NMEA 0183 sensor and still end up on the modern bus.
The Actisense NGT1 reference is a good marker of what the library is really about. That device is a plug-and-play gateway that turns a NMEA 2000 network into a USB feed for a PC, and it is exactly the kind of product where the protocol handling is the entire difficulty and the data handling is trivial. A library that makes building one of those easy has picked the right layer of the stack to own.
For a developer picking a use for it, the practical read is that if you are making a sensor, a display or a bridge for marine equipment, there is probably an example directory close to what you want.
Fourteen example directories, one per device and one per board
The examples directory is the best documentation in the repository, because the examples are organised by exactly the two things that vary between projects.
The first axis is the device. There is a BatteryMonitor, a TemperatureMonitor and a WindMonitor, which are the three sensor transducers named in the description. There is a DataDisplay and a DataDisplay2, which are the information displays. There is a DeviceAnalyzer, which is the tool you would use to see what is on a bus. And there is a MessageSender, which is the generic output device.
The second axis is the transport and the board. There is an ArduinoGateway, an ESP32 directory, and an ActisenseListener and ActisenseListenerSender, which are the NMEA 2000 to PC interface pieces. There is a TeensyActisenseListenerSender, which is the same idea on a different board. And there is a MultiDevice directory, which is the one that matters if you are putting several of your own devices on the same bus, since that is where addressing and arbitration bite.
The two converters have their own directories as well, NMEA2000ToNMEA0183, and there is a MessageSender alongside them.
The pattern across the names is that each example is a complete device rather than a fragment. A TemperatureMonitor example is a whole thing you could put on a boat, which means the library makes a device's addressing, its update cadence and its place in the network something the example handles for you.
That is the difference between a protocol library and a device framework, and it is the reason the examples are organised this way. If you are starting a project, the first move is to find the example closest to your device and read it end to end, rather than to look for an API reference.
The repository carries a build system, a test suite and third-party code
The top-level entries tell you what kind of repository this is, and there is more here than a header file and a folder of examples.
There is a CMakeLists.txt at the root, so the library builds outside the Arduino IDE as well as inside it. There is a library.json and a library.properties, which are the two manifest files the Arduino library manager uses, so the library can be installed through the IDE's library manager rather than by copying files. There is a src/ directory for the implementation, a test/ directory for the tests, and a scripts/ directory.
The third-party/ directory is worth noting, because bundling dependencies is a decision that a library with a hardware abstraction often has to make rather than choose. Here the library is self-contained enough to carry what it needs, which is consistent with the claim that the only hardware-specific part you write is the CAN driver and the supporting classes.
The Documents/ directory holds the documentation sources, which is where the GitHub Pages documentation is generated from, and the README points at two URLs for the reader: the changes page for people who already know the library, and the full documentation index.
That separation between the README and the docs site is a good sign. The README is deliberately short and gives you the shape of the library, the supported device types, the licence and two links, and everything else lives in the generated documentation, where a table of contents can be maintained for a project with this much surface area.
The .travis.yml at the root is a leftover from the era before GitHub Actions, and the .github/ directory is where the current CI lives. The build badges in the README point at the current setup, with one workflow compiling the examples on ESP32-Arduino-v1, one on ESP32-Arduino-v2 and one running the unit tests, so both the board support and the test suite are checked on every push.
It grew out of another project, and that history is documented
The README links two badge workflows that both point at a different repository, phatpaul/NMEA2000, and that is not an accident of a copied badge.
The library was originally developed in 2015 for Arduino based boards, and the current repository carries a fork line from that earlier project with the author's own changes on top. The changes page exists precisely because of that history, and the README addresses it directly: if you are familiar with the library, here is a quick link to the changes.
That is a thoughtful thing for a fork to do. The most common problem with a long-lived fork is that people who know the upstream do not know what changed, and a changes page turns that into a five minute read rather than a diff through the whole history.
The documentation is published on GitHub Pages rather than on a domain of its own, with the index at ttlappalainen.github.io/NMEA2000 and the changes at the sibling path, and the license is MIT with the copyright held by the author and Kave Oy, which is the company behind the work. The copyright span from 2015 to 2026 in the license text matches the origin date in the description.
The repository is not archived and the last push was on 2026-10-19, so the library is being worked on now, which matters for a project where the bus protocol has a certification angle and a change in the mandatory requirements handling is not something you want to discover mid-product.
Where it sits against writing the protocol yourself
The realistic alternative is to implement the NMEA 2000 protocol on your own CAN stack, and for a commercial certified device that is a serious option because the requirements are published and finite.
Writing it yourself means you own the device address claiming, the request and response pairing, the periodic update intervals, the heartbeats and the network management. You also own the consequences of getting any of them wrong, and in a certified product that consequence is a failed audit rather than a bug report. The library's argument is that those obligations are exactly the parts that are not interesting to write and are easy to get subtly wrong.
The case against is the usual one for frameworks. You learn the protocol through the library's API rather than through the specification, so when something does not work you have to decide whether it is a library bug or a misunderstanding of the standard. And when the standard changes, the library's timetable is not yours.
There is also a scope limit that the library states honestly. Portability beyond the tested boards depends on you writing a compatible CAN driver and the necessary classes for other hardware specific functions, so the abstraction does not extend all the way down to the hardware. You need a CAN peripheral and the willingness to bind to it.
For a maker building one sensor at home, the library is overkill and a much simpler approach will do. For a commercial device that has to be certified, or for an integrator building a bridge between a legacy NMEA 0183 instrument and a modern bus, it removes the part of the work where mistakes are expensive, and the existence of examples in commercially certified devices is the reason to believe that claim.
Editorial conclusion
Adopt NMEA2000 if you are building a device that sits on a NMEA 2000 bus and you would rather spend your time on the data than on the protocol, since the library takes care of the mandatory requirements and has been used in certified commercial devices. Skip it if you are not on a supported board or you cannot write a CAN driver, because the portability beyond Arduino relies on that. Verify first which board you are on, since the examples are organised per board and per device type, that the Arduino library manager install works for you or that you build with CMake instead, and read the changes page before upgrading, since the library is versioned separately from the original project it grew out of.
Frequently asked questions
What is the NMEA2000 library and what does it save you from?
It is an object oriented C++ library for developing NMEA2000 bus devices that fulfills the NMEA 2000 mandatory requirements automatically, leaving only the interesting data handling for the developer. The library has been used in several commercial certified NMEA2000 devices, and it covers sensor transducers, information displays, NMEA2000 to PC interfaces such as the Actisense NGT1, and NMEA0183 to NMEA2000 converters.
Which boards does the NMEA2000 library support?
It was originally developed for Arduino based boards in 2015 and as far as the author knows has been used and tested with Teensy, ESP, some Arduino, MBED and Rasberry boards. The library can also be used in other systems by writing a compatible CAN driver and the necessary classes for other hardware specific functions. There are separate example directories for Arduino and ESP32.
How do I install the NMEA2000 library and find an example?
The repository carries a library.json and a library.properties, which are the Arduino library manager manifests, so it can be installed through the Arduino IDE, and a CMakeLists.txt at the root for building it outside the IDE. The Examples/ directory holds one complete example per device and per board, including BatteryMonitor, TemperatureMonitor, WindMonitor, DataDisplay, DataDisplay2, DeviceAnalyzer, MessageSender, MultiDevice, ArduinoGateway, ESP32 and the NMEA2000ToNMEA0183 converter.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ttlappalainen-nmea2000)Was this useful?