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

libcec

v8.1.7

Published

Node.js binding for libCEC — control CEC-capable HDMI devices (TVs, AV receivers) via Pulse-Eight USB-CEC and SoC-native CEC

Readme

Pulse-Eight logo

libCEC — Node.js binding

A native N-API addon that binds libCEC through its C API (include/cecc.h), the same surface the .NET binding (src/dotnetlib) uses. It lets Node.js applications control CEC-capable HDMI devices — power a TV on/standby, become the active source, send remote keys, read device state — and receive bus events (log, key presses, commands, source changes, alerts).

It works anywhere libCEC and a C++ toolchain do: Linux, macOS, Raspberry Pi and Windows, over the Pulse-Eight USB-CEC adapter or a SoC-native CEC backend.

Requirements

  • libCEC installed with its development files. On Unix these are discovered via pkg-config (pkg-config --exists libcec) — on Debian/Ubuntu that is the libcec8-dev package; or build and make install this repository first.
  • Node.js ≥ 16 and a C++17 toolchain (node-gyp prerequisites: a compiler, make, and Python 3).

Install

npm install libcec

The package carries sources, not a prebuilt binary: installing runs node-gyp rebuild, which compiles src/addon.cc against the libCEC already on the machine. The requirements above have to be met first, or the install fails at that step. Being built on the consumer's machine is also what lets one package serve every platform and every Node ≥ 16.

Build from this repository

cd src/nodejs
npm install        # runs node-gyp rebuild, compiling src/addon.cc against libcec
node example/simple.js

The compiled addon lands at build/Release/cec_native.node.

Windows

Windows has no pkg-config, so tell node-gyp where libCEC's headers and its cec.lib import library are with two environment variables (defaults point at an installed USB-CEC Adapter SDK). From a repo build:

set LIBCEC_INCLUDE_DIR=..\..\include
set LIBCEC_LIB_DIR=..\..\build\Release\x64\lib
npm install

At runtime the addon needs cec.dll on the DLL search path — keep it next to cec_native.node (a .node resolves its dependencies from its own directory). The x64 Windows installer ships a prebuilt addon set up this way under its nodejs folder, so end users don't need a compiler; see docs/README.windows.md. The x86 installer does not — Node.js has had no 32-bit Windows build since v23, so there is no node.lib to link a 32-bit addon against.

Test client

client/cec-client.js is an interactive REPL modelled on the C++ cec-client: the Node counterpart for exercising the library against real hardware and a worked example of every API call. Run it with npm run client (or node client/cec-client.js [port], or the installed cec-client-node bin):

$ npm run client
opening /dev/ttyACM0 ...
connection opened. type 'h' for help, 'q' to quit.
scan
...
tx 1F:82:10:00      # transfer raw bytes
on 0                # power on the TV
pow 0               # query the TV's power status
q

node client/cec-client.js --help lists the command-line options (--list-devices, --info, --type, --monitor, --log-level, …).

Usage

const cec = require('libcec'); // or require('.') from this folder

const adapter = new cec.CecAdapter({
  deviceName: 'CECNode',
  deviceType: cec.CecDeviceType.RecordingDevice,
});

adapter.on('log', (m) => console.log(m.message));
adapter.on('keyPress', (k) => console.log('key', cec.userControlKeyToString(k.keycode)));
adapter.on('command', (c) => console.log('cmd', cec.opcodeToString(c.opcode)));

adapter.open(); // or adapter.open(port) with a path from detectAdapters()

adapter.powerOnDevices(cec.CecLogicalAddress.TV);
for (const addr of adapter.getActiveDevices())
  console.log(cec.logicalAddressToString(addr), adapter.getDeviceOSDName(addr));

adapter.close();

Events

CecAdapter is an EventEmitter. libCEC fires its callbacks from its own worker thread; the addon marshals each one onto the Node event loop via a ThreadSafeFunction, so handlers run on the main thread like any other event.

| event | argument(s) | source callback | |-------|-------------|-----------------| | log | { message, level, time } | logMessage | | keyPress | { keycode, duration } | keyPress | | command | { initiator, destination, opcode, parameters, ack, eom, opcodeSet, transmitTimeout } | commandReceived | | sourceActivated | (logicalAddress, activated) | sourceActivated | | alert | alert (a CecAlert) | alert | | configurationChanged | { deviceName, deviceTypes, physicalAddress, logicalAddresses, cecVersion, adapterType, firmwareVersion, … } | configurationChanged | | menuStateChanged | state (a CecMenuState) | menuStateChanged | | commandHandler | same shape as command | commandHandler (opt-in) |

commandHandler is off by default — pass { enableCommandHandler: true } to the constructor to receive it. It routes every command through libCEC's blocking command-handler path and carries the same data as the cheaper command event, so it's only worth enabling if you specifically need that hook.

Methods

Lifecycle: open(port, timeout=10000), close().

Control: transmit(command), powerOnDevices(address), standbyDevices(address), setActiveSource(deviceType), setInactiveView(), volumeUp(), volumeDown(), muteAudio(), sendKeypress(destination, key, wait=true), sendKeyRelease(destination, wait=true), setOSDString(destination, duration, message).

Queries: getActiveSource(), isActiveSource(address), getDevicePowerStatus(address), getDeviceVendorId(address), getDevicePhysicalAddress(address), getDeviceCecVersion(address), getDeviceOSDName(address), getActiveDevices(), pollDevice(address), rescanDevices(), pingAdapters(), detectAdapters(), getLibInfo().

Enum helpers (module-level): cecVersionToString, powerStatusToString, logicalAddressToString, vendorIdToString, opcodeToString, userControlKeyToString, plus the enum tables (CecLogicalAddress, CecDeviceType, CecPowerStatus, CecUserControlCode, CecOpcode, …).

Notes / limitations

  • commandHandler and menuStateChanged cannot suppress libCEC's default handling from JavaScript. Both are dispatched on libCEC's callback thread and expect a synchronous "handled?" return; the addon always answers "not handled" so the library keeps its default behaviour. Honouring a JS return would mean blocking that thread on the Node event loop and racing libCEC's 1000ms timeout. They are therefore exposed as observe-only events.
  • Call close() when done. It stops libCEC's worker thread before releasing the thread-safe callbacks, so no event can fire against a torn-down adapter.

Licence

GPL-2.0-or-later, or a commercial licence from Pulse-Eight — the same dual licence as libCEC itself.