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

@johntalton/i2c-bus-tca9548a

v3.0.2

Published

Provides a `I2CBus` interface for managing the channels for the TCA9548

Readme

I²C Bus interface for TCA9548

Provides a I2CBus interface for managing the channels for the TCA9548

This makes channel management transparent to most device implementation and simplifies program logic.

npm Version GitHub package.json version CI

Description

While the TCA9548 can be managed explicitly, the orchestration code needed can be burdensome 😢.

This library provides an abstraction of the I2CBus while exposing the ChannelManager interface 👍.

This allows device code to be abstractly written against the I2CBus interface, while allowing for custom channel changing methodologies required by the application, without rewriting device code 🥳.

Usage

The following example show the usage in order to manage two (2) HT16K33 that share the same address.

In this case, the TCA9548 exist at address 0x70, while the two HT16K33 chips are both at address 0x71.

The two devices are connected to channel 1 and 3 of the multiplexer.

import { I2CAddressedBus } from '@johntalton/and-other-delights'
import { Tca9548a } from '@johntalton/tca9548a'
import { I2CBusTCA9548A } from '@johntalton/i2c-bus-tca9548a'
import { HT16K33 } from '@johntalton/ht16k33' // example device

// acquire an I2CBus implementation
//  like Excamera I2CDriver
//  or MCP2221 over HID
//  etc.
const bus = /* I2CBus */
const tca = new Tca9548a(new I2CAddressedBus(bus, 0x70))

// create the two managed busses
// for exclusive strategies, two unique busses are created
const managedBus_1 = new I2CBusTCA9548A(bus, tca, { exclusive: 1 })
const managedBus_3 = new I2CBusTCA9548A(bus, tca, { exclusive: 3 })

// given the managed busses, create addressed devices (same address) for each
const device_1 = new HT16K33(new I2CAddressBus(managedBus_1, 0x71))
const device_3 = new HT16K33(new I2CAddressBus(managedBus_3, 0x71))

Example interaction using the above code. Note that the channel is not explicitly set/update in this code, as that is handled by the channel manager:

// enable both devices oscillators
// the ChannelManager will exclusively switch to channel 1 here
await device_1.enableOscillator()
// then to channel 3 (only) here
await device_3.enableOscillator()

You can still set the channel, and the devices will again manage re-setting it for their specific usage.

// external changes to the channels remain valid
// this will not effect either devices_1 or _3s operation
await tca.setChannels([ 4 ])

// turn on the display (disable blinking)
// again, interacting with both will switch channels 1 and 3 sequentially
await device_1.setDisplay(true, 'off')
await device_3.setDisplay(true, 'off')

Setting both channel enabled (1 and 3) is also "valid", and when using the devices it will manage the channel to be specific to the device.

However, using other access when both channels are active that is not guarded by the channel manager results in both devices sharing the same address.

// The following is valid from the perspective of the tca chip,
// however, accessing device directly via 0x71 will have undefined behavior ☠️
// (as noted above, using the managed device_1 or _3 will work)
await tca.setChannels([ 1, 3 ])

Given the static nature of most drivers (in this case the Ht16k33) a single instance of the driver be be directly used on an UN-managed bus and used to access each device with Explicit management of the channel

// It is also possible to create un-managed device.

// Bypassing the Managed Bus is considered an "escape hatch" for scenarios that do not fit well into the ChannelManager api design.

// Note that this works because the HT16K33 driver is stateless, and not effected by the hardware change
const eitherDevice = new HT16K33(new I2CAddressBus(bus, 0x71))
await tca.setChannels([ 1 ])
await eitherDevice.setDisplay(true, 'off') // effect device on channel 1
await tca.setChannels([ 3 ])
await eitherDevice.setDisplay(true, 'off') // effect device on channel 3

Strategies

Default Channel Manager

Enable, exclusively, a channel (or channels) during bus calls.

This example will set the channels explicitly to 3 (and only 3) prior to any further bus calls. And it will restore the existing set channels after bus operations.

{
  exclusive: [ 3 ],
  restore: true
}

The DefaultChannelManager has the following properties:

  • exclusive: Array<number> a list of channels that must be set prior to bus call
  • pedantic: boolean if true, ignore any previous channel value and alway set the exclusive channels, also ignore restoration of previous channels
  • allow: Array<number> list of exception to exclusivity, channels listed here will be allowed to remain set, if set when switching to the exclusive list, only applies if not pedantic.
  • restore: boolean if true, and not pedantic, the channels set prior to setting the exclusive list will be restored in full after bus operation complete

Transaction Bus

While managed busses allow for a cleaner abstraction for device authors and a flexible solution for consumers, it does "hide" the async nature of the interaction (get/set channel prior to device call, and then again after).

Due to this async nature, consumers must take care to grantee that the underlying bus calls are serialized.

There are several solution to this - with the most common being ignore it in most cases 🙈

In cases where serialization of calls is required, a TransactionBus can be used:

import /* ...stuff from above  */
import { TransactionBus } from '@johntalton/and-other-delights'

const rawBus = await SomeUnderlyingI2CBusImplementation()
const transBus = new TransactionBus(rawBus)
const tca = Tca9548a.from(new I2CAddressedBus(transBus, 0x70))
const managedBus_1 = I2CBusTCA9548A.from(transBus, tca, { exclusive: 1 })

// use tca nad managedBus_1 as above (now safely 🦺 )