New:Socket for Asana Is Now Available.Learn more
Get Started

bluetti-mqtt-node

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

bluetti-mqtt-node

TypeScript Bluetti BLE to MQTT bridge with MQTT TLS, structured logging, a native Windows BLE helper, simulated devices for hardware-free testing, and a data-driven device registry

latest
Source
npmnpm
Version
1.1.0
Version published
Maintainers
1
Created
Source

bluetti-mqtt-node

Windows-first TypeScript port of the Python bluetti_mqtt library.

This project connects to Bluetti power stations over Bluetooth Low Energy, polls device state through the Bluetti MODBUS-over-BLE protocol, and publishes that state to MQTT.

The repository is designed around Windows as the primary runtime. BLE access is handled by a small .NET helper using native Windows Bluetooth APIs, while the protocol logic, parsing, polling, and MQTT bridge live in TypeScript.

CI License: MIT Node >=22 Platform: Windows npm version

Features

  • Windows-native BLE transport
  • TypeScript implementation of Bluetti MODBUS command framing and CRC handling
  • Typed field parsing for supported Bluetti devices
  • MQTT state publishing
  • MQTT command-topic ingestion for writable fields
  • Optional MQTT TLS support for CA trust, mutual TLS, server name override, and self-signed broker workflows
  • c8 coverage reporting and a single npm run validate CI contract
  • Live polling, logging, and probe CLIs

Scope

Included:

  • Windows runtime
  • MQTT broker bridge over plain MQTT or TLS-secured MQTT
  • BLE polling and command dispatch

Explicitly out of scope:

  • Home Assistant discovery/config publishing
  • Linux-first or macOS-first BLE support

Supported Device Models

The TypeScript registry currently supports the same models ported from the Python library:

  • AC200M
  • AC300
  • AC500
  • AC60
  • EB3A
  • EP500
  • EP500P
  • EP600

Architecture

The project is split into a few clear layers:

  • src/core
    • MODBUS commands, CRC, shared types, event bus
  • src/devices
    • device models and typed field parsing
  • src/bluetooth
    • Windows-helper transport abstraction, session state machine, helper client, mock transport
  • src/app
    • polling orchestration and runtime wiring
  • src/broker
    • MQTT publishing and command-topic handling
  • src/cli
    • user-facing command entrypoints
  • helper/BluettiMqtt.BluetoothHelper
    • Windows-native BLE helper implemented in .NET / WinRT

Why a Windows Helper Exists

Node-native BLE libraries on Windows are workable in some environments, but they tend to be more fragile than the native Windows Bluetooth stack and often require native addon toolchains. This project uses a small .NET helper process instead, and the old experimental noble path has been removed from the supported runtime surface.

That gives us:

  • native Windows BLE APIs for scan/connect/GATT operations
  • a simpler Node runtime surface
  • a cleaner separation between transport concerns and protocol logic
  • fewer issues with node-gyp and Windows BLE adapter quirks

The helper communicates with Node over line-delimited JSON on stdio.

Quick Start

For local development with a reachable broker and a known Bluetti BLE address:

npm ci
npm run build
npm run helper:build
npm run bluetti-mqtt -- --broker mqtt://127.0.0.1:1883 --once 24:4C:AB:2C:24:8E

For a packaged/runtime-style setup, publish the helper first so the CLI can resolve artifacts/helper/win-x64/BluettiMqtt.BluetoothHelper.exe without falling back to dotnet run:

npm run helper:publish
npm run bluetti-mqtt -- --broker mqtt://127.0.0.1:1883 --interval 5 24:4C:AB:2C:24:8E

Mock Mode (No Hardware Required)

Every CLI accepts a --mock flag that swaps native Bluetooth for a simulated Bluetti device fleet. The simulator answers the real MODBUS-over-BLE dialect (CRC-validated reads, write echoes, chunked notifications, exception frames), so the entire pipeline — discovery, polling, parsing, setters, and the MQTT bridge — runs identically to real hardware. This works on any platform, including Linux and macOS, and needs no Bluetti device, Bluetooth adapter, or .NET helper:

npm ci
npm run build

# List the simulated fleet (an AC500 at 00:11:22:33:44:55 by default)
node dist/cli/bluetti-discovery.js --mock

# One full polling cycle against the simulated AC500
node dist/cli/poll.js --mock 00:11:22:33:44:55

# Full MQTT bridge against a local broker; addresses default to the mock fleet
node dist/cli/bluetti-mqtt.js --mock --broker mqtt://127.0.0.1:1883 --interval 5

bluetti-mqtt also accepts --mock-device <model> (repeatable) to simulate other models from the registry, and "mock": true in the JSON config file. Library consumers can build their own fleets with SimulatedBluettiDevice and createSimulatedRuntime, including fault injection (queueException, dropNextResponse) for testing busy/timeout handling.

Native (non-mock) Bluetooth currently requires Windows; a Linux/macOS backend based on @stoprocent/noble is planned, and createPlatformRuntime is the seam it will plug into.

Requirements

Runtime requirements:

  • Windows for native Bluetooth (mock mode runs on Linux/macOS/Windows)
  • Node.js 22 or newer
  • npm
  • .NET SDK 6.0+ if you are building the Windows helper from source
  • Bluetooth adapter supported by Windows BLE APIs (not needed in mock mode)
  • MQTT broker reachable from the machine running this project

Development requirements:

  • Docker optional, but useful for spinning up a local MQTT broker for testing

Installation

Install Node dependencies:

npm ci

Build the TypeScript project:

npm run build

Build the Windows helper:

dotnet build helper\BluettiMqtt.BluetoothHelper\BluettiMqtt.BluetoothHelper.csproj

Publish a self-contained Windows helper for distribution:

npm run helper:publish

Publish a smaller framework-dependent helper instead:

npm run helper:publish:portable

Run the full local validation suite:

npm run validate

npm run validate is the same command used by CI. It runs TypeScript typechecking, Biome linting, the test suite, c8 coverage, and the Windows helper build.

Installed CLI Names

If this package is installed as a CLI package, the declared executable names are:

  • bluetti-mqtt-node
  • bluetti-mqtt-node-discovery
  • bluetti-mqtt-node-logger
  • bluetti-mqtt-node-poll
  • bluetti-mqtt-node-probe

The repo-local npm run ... scripts remain the easiest way to use the commands during development.

Helper Resolution

The Node runtime resolves the Windows helper in this order:

  • BLUETTI_HELPER_PATH if you set it
  • published helper artifact at artifacts/helper/win-x64/BluettiMqtt.BluetoothHelper.exe
  • source fallback through dotnet run --project helper/BluettiMqtt.BluetoothHelper/BluettiMqtt.BluetoothHelper.csproj

That means:

  • contributors can work directly from source without changing anything
  • release builds can ship a published helper executable
  • end users can override the helper path explicitly when needed

Example override:

$env:BLUETTI_HELPER_PATH = "C:\tools\BluettiMqtt.BluetoothHelper.exe"

If you publish the framework-dependent helper, point BLUETTI_HELPER_PATH at artifacts/helper/win-x64-fdd/BluettiMqtt.BluetoothHelper.exe.

CLI Usage

Discover Nearby Devices

npm run bluetti-discovery

This scans nearby BLE devices through the Windows helper and prints discovered devices as JSON.

Use --help with any CLI to print its usage text.

Probe a Device

npm run probe -- <BLUETOOTH_MAC>

This:

  • connects to the device
  • reads the device name characteristic
  • executes ReadHoldingRegisters(10, 40)
  • parses and prints the result

Poll the Device's Standard Polling Set

npm run poll -- <BLUETOOTH_MAC>

This runs the device's pollingCommands set and prints:

  • per-command responses
  • parsed output for each command
  • a merged view of the parsed state

Log the Device's Logging Command Set

npm run bluetti-logger -- <BLUETOOTH_MAC>

This runs the broader loggingCommands set for the device and prints the parsed output.

Run the MQTT Bridge Once

npm run bluetti-mqtt -- --broker mqtt://127.0.0.1:1883 --once <BLUETOOTH_MAC>

This performs one poll/publish cycle, publishes MQTT state topics, and exits.

Run the MQTT Bridge Continuously

npm run bluetti-mqtt -- --broker mqtt://127.0.0.1:1883 --interval 5 <BLUETOOTH_MAC>

Supported flags:

  • --broker <mqtt-url>
  • --config <path>
  • --username <username>
  • --password <password>
  • --mqtt-ca <path>
  • --mqtt-cert <path>
  • --mqtt-key <path>
  • --mqtt-servername <name>
  • --mqtt-insecure
  • --interval <seconds>
  • --log-level <level>
  • --once

Example:

npm run bluetti-mqtt -- --broker mqtt://127.0.0.1:1883 --interval 5 24:4C:AB:2C:24:8E

Config-file example:

npm run bluetti-mqtt -- --config .\config.example.json

The config file is JSON and supports:

  • broker
  • username
  • password
  • tls.caPath
  • tls.certPath
  • tls.keyPath
  • tls.servername
  • tls.rejectUnauthorized
  • interval
  • once
  • logLevel
  • addresses

CLI flags override config-file values when both are provided.

MQTT TLS

Use an mqtts:// broker URL with TLS options when the broker requires a custom trust chain, client certificate authentication, or a specific TLS server name.

CA-only example:

npm run bluetti-mqtt -- `
  --broker mqtts://broker.local:8883 `
  --mqtt-ca .\certs\ca.pem `
  --interval 5 `
  24:4C:AB:2C:24:8E

Mutual TLS example:

npm run bluetti-mqtt -- `
  --broker mqtts://broker.local:8883 `
  --mqtt-ca .\certs\ca.pem `
  --mqtt-cert .\certs\client.pem `
  --mqtt-key .\certs\client-key.pem `
  24:4C:AB:2C:24:8E

For local labs with self-signed certificates, --mqtt-insecure sets rejectUnauthorized to false. Prefer a CA file for normal use.

Config-file TLS fields live under tls:

{
  "broker": "mqtts://broker.local:8883",
  "tls": {
    "caPath": "./certs/ca.pem",
    "certPath": "./certs/client.pem",
    "keyPath": "./certs/client-key.pem",
    "servername": "broker.local",
    "rejectUnauthorized": true
  },
  "addresses": ["24:4C:AB:2C:24:8E"]
}

MQTT Topic Layout

State topics:

bluetti/state/<MODEL>-<SERIAL>/<FIELD>

Examples:

bluetti/state/AC500-2237000003358/ac_input_power
bluetti/state/AC500-2237000003358/total_battery_percent

Each parser message also publishes a raw JSON snapshot to:

bluetti/state/<MODEL>-<SERIAL>/_raw

Command topics:

bluetti/command/<MODEL>-<SERIAL>/<FIELD>

Payload expectations:

  • booleans: ON / OFF
  • integer fields: numeric string
  • enum fields: enum name string

Validation and Current Confidence

This project has been validated live on this machine against:

  • AC500 24:4C:AB:2C:24:8E

Successful live validation includes:

  • BLE scan
  • connect + device-name read
  • characteristic read/write/subscribe path
  • probe
  • poll
  • one-shot MQTT publish to a local broker

Limitations

  • Windows is the only runtime this repository is currently designed for.
  • The Windows helper is the only supported BLE runtime path in this repository.
  • MQTT command handling is implemented, but broader live validation of writable fields is still lighter than read-path validation.

Development Notes

Useful commands:

npm run typecheck
npm run lint
npm test
npm run coverage
npm run build
npm run helper:publish
npm run helper:publish:portable
npm run pack:dry-run
npm run validate
dotnet build helper\BluettiMqtt.BluetoothHelper\BluettiMqtt.BluetoothHelper.csproj

GitHub Actions validates:

  • npm run validate on Node.js 22.x, 24.x, and 26.x

Additional development docs:

Distribution Notes

For npm packaging, prepack builds the TypeScript output and publishes a self-contained Windows helper into artifacts/helper/win-x64.

That gives the package a better installation story than requiring every user to run the helper from source. A typical release flow is:

npm run validate
npm run pack:dry-run
npm publish

If you are distributing outside npm, the simplest layout is:

  • dist/
  • artifacts/helper/win-x64/BluettiMqtt.BluetoothHelper.exe
  • README.md

The CLI will automatically use the published helper artifact when it exists.

Helper Size Tradeoff

There are two practical helper distribution modes:

  • self-contained single-file publish
    • biggest artifact
    • no separate .NET runtime install required on the target machine
    • this is the default npm package artifact
  • framework-dependent single-file publish
    • much smaller artifact
    • requires a compatible .NET runtime on the target machine
    • useful when you control the installation environment

On the current implementation, the framework-dependent helper is roughly one quarter the size of the self-contained helper.

Keywords

bluetti

FAQs

Package last updated on 10 Aug 2026

Related posts