npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@coremarine/sbg-ecom-nodered

v1.0.2

Published

Node-RED node for the SBG Systems sbgECom binary protocol (ELLIPSE, EKINOX, APOGEE), emitting the unified CoreMarine CMA format

Readme

@coremarine/sbg-ecom-nodered

npm (scoped) publish npm

Node-RED node for SBG Systems inertial systems — ELLIPSE, EKINOX and APOGEE — speaking sbgECom. It turns the device's output into CMA, the same JSON shape every CoreMarine device parser emits.

Wrapper of @coremarine/sbg-ecom. All 34 output logs of SBG_ECOM_CLASS_LOG_ECOM_0 are decoded. Node >= 22, Node-RED >= 4.

Install

From the Node-RED palette manager, or:

npm install @coremarine/sbg-ecom-nodered

The node appears in the CoreMarine palette category as SBG sbgECom parser.

Configuration

| Field | Meaning | | --- | --- | | Name | Optional node label | | Firmware | Empty for the library default (2.3), or a version this build models | | Memory | On by default — append each input to the buffer instead of replacing it |

You rarely need to pin the firmware. §2.4 of the manual states that SBG only ever adds fields at the end of a log, so 2.3 decodes a newer device correctly and publishes the extra bytes at metadata.trailing rather than failing. A version this build does not model is refused, never substituted.

Leave memory on for a live stream. eCom framing is length-prefixed rather than terminated, so a frame only decodes once its last byte has arrived — with memory off, any frame split across two messages is lost.

⭐ One node, two protocols

An SBG device does not wrap its NMEA output in an eCom frame. The manual is explicit (§2.1.4): the NMEA classes are "only used for identification purpose and does not contain any sbgECom message" — the class ids exist so you can configure which sentence goes out, and the sentence itself is emitted as raw ASCII alongside the binary frames, on the same wire. §2.1.1 Note 4 warns the integrator directly.

So this node has no protocol setting. Wire your serial node straight in and both come out as CMA:

sentences[0].id  // '0:9'   protocol.name 'SBG ECOM'
sentences[1].id  // 'GGA'   protocol.name 'NMEA'
sentences[2].id  // '0:13'  protocol.name 'SBG ECOM'

The example flow has a group demonstrating exactly this — it is the feature most likely to surprise you, so it is the one to open first.

msg API

Send payload to parse. Every other key is optional; a key you do not send is absent from the output too, and on a bad request the corresponding output key holds an error string.

| Key | In | Out | | --- | --- | --- | | payload | a Buffer, a base64 string, an NMEA sentence (any string starting with $), or a byte array | CMA[] | | memory | { command: 'get' } / { command: 'set', payload: boolean } | { memory, bytes } | | firmware | { command: 'get' } / { command: 'set', payload: '2.3' } | { firmware, firmwares, clock? } | | ids | any truthy value | string[] — the 34 eCom log ids plus every NMEA sentence id | | definition | '0:6', 'GGA', or { id, protocol? } | the field table | | fake | '0:6' or { id, protocol?, options? } | a real wire frame, as a Buffer |

Full details, tables and warnings are in the node's help panel inside Node-RED.

Input — what a string means

| string | read as | | --- | --- | | starts with $ | the NMEA sentence, passed through as text | | anything else | base64 eCom bytes, validated strictly |

There is no ambiguity to resolve: base64's alphabet contains no $, and every NMEA sentence starts with one. A Buffer works for both and is the normal case — a serial, TCP or file node hands you one and it goes straight through.

Base64 is accepted because every raw in the output is base64, so it is this package's own vocabulary for bytes: copy a raw out of a debug node, inject it back, and you are re-parsing the exact frame that misbehaved. A byte array works too, for JSON-only paths such as an inject node.

id is '<class>:<message>'

The convention most likely to catch a flow author out. Identity in sbgECom is a pair — §2.1.1 gives MSG and CLASS as two independent header bytes, with no revision concept — so MSG 6 means EKF_EULER in class 0x00 and something else entirely in class 0x02. The id is therefore '0:6', and the log's name is at metadata.name.

Timestamps — the device tells us the time, or nothing does

The first field of almost every log is TIME_STAMP, and it is not a clock: the manual calls it time since power-up. You cannot say when a sample was taken from an uptime counter, so this node never presents one as a time.

It becomes a time through SBG_ECOM_LOG_UTC_TIME, which publishes that counter and the matching UTC. Once such a log arrives with a valid clock status, every later sentence carries an absolute metadata.timestamp.sentence, promoted over timestamp — the device's clock beats the host's.

Until then there is no absolute time, deliberately: a guessed clock is worse than an honest absence. Send firmware: { command: 'get' } to see whether the device has published one — the reply carries clock once it has. That is the answer to "why has my data no timestamp?", and it is why the channel reports it at all.

Nothing is dropped silently

A bad CRC, a wrong end flag, a log this build does not know, or bytes that are not sbgECom at all: each comes back as a sentence saying so, never as an empty array. The signal is the presence of errors on a sentence.

A log the knowledge base does not model is not an error — it arrives with its real id, its bytes at metadata.body and metadata.name: 'unknown'. A log that has grown decodes every field this build knows and publishes the extra bytes at metadata.trailing.

Examples

Import from the Node-RED menu → Import → Examples → @coremarine/sbg-ecom-nodered, or open examples/sbg-ecom-examples.json.

Eight groups, each with a comment node explaining what it shows:

| group | what it demonstrates | | --- | --- | | Decoded logs | real frames from a CoreMarine ELLIPSE; the '0:6' id convention | | The mixed stream | binary frames and a $GPGGA sentence through one node, nothing configured | | Timestamps | fire 1/2, then 2/2 — a UTC_TIME log turning uptime into a real clock | | Failed and garbage | a corrupted CRC still decoding, and junk reported rather than dropped | | Memory | half a frame, then the rest | | Diagnostics | ids, definition, firmware — asking the running node what it expects | | Fake frames | a fabricated frame fed straight back in, round-tripping | | Flow errors | a catch node, so a mistake is visible rather than silent |

Every payload in that flow is a real frame from the committed test corpus, and the flow is covered by tests/examples.unit.test.ts — it is structurally validated and every inject is run through this wrapper's own handlers, so a shipped example cannot rot unnoticed.

Development

pnpm run sbg-ecom:nodered:build       # tsup -> dist/ + copy parser.html and icons
pnpm run sbg-ecom:nodered:test        # node --test (unit + a real node-red integration run)
pnpm run sbg-ecom:nodered:lint        # eslint
pnpm run sbg-ecom:nodered:dev         # a local Node-RED on :1880 with a scratch flow
pnpm run sbg-ecom:nodered:examples    # the same, editing the SHIPPED example flow

Two traps worth knowing before you change anything:

  • The tests run against dist/, not src/. Build the wrapper and the library first, or you are testing a stale copy.
  • tsx strips types without checking them, and :nodered:lint does not typecheck either. Run npx tsc --noEmit -p tsconfig.json inside this package whenever the library changes shape — three real breaks hid behind a green suite that way during the septentrio refactor, and one hid here.