
Security News
GPT-6 Astra Attempts Supply Chain Attacks Against Open Source Maintainers in Testing
GPT-6 Astra hits 100% on ExploitBench and finds zero-days autonomously, while independent tests reveal scope violations and monitoring gaps.
bluetti-mqtt-node
Advanced tools
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
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.
c8 coverage reporting and a single npm run validate CI contractIncluded:
Explicitly out of scope:
The TypeScript registry currently supports the same models ported from the Python library:
The project is split into a few clear layers:
src/core
src/devices
src/bluetooth
src/app
src/broker
src/cli
helper/BluettiMqtt.BluetoothHelper
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:
node-gyp and Windows BLE adapter quirksThe helper communicates with Node over line-delimited JSON on stdio.
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
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.
Runtime requirements:
Development requirements:
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.
If this package is installed as a CLI package, the declared executable names are:
bluetti-mqtt-nodebluetti-mqtt-node-discoverybluetti-mqtt-node-loggerbluetti-mqtt-node-pollbluetti-mqtt-node-probeThe repo-local npm run ... scripts remain the easiest way to use the commands during development.
The Node runtime resolves the Windows helper in this order:
BLUETTI_HELPER_PATH if you set itartifacts/helper/win-x64/BluettiMqtt.BluetoothHelper.exedotnet run --project helper/BluettiMqtt.BluetoothHelper/BluettiMqtt.BluetoothHelper.csprojThat means:
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.
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.
npm run probe -- <BLUETOOTH_MAC>
This:
ReadHoldingRegisters(10, 40)npm run poll -- <BLUETOOTH_MAC>
This runs the device's pollingCommands set and prints:
npm run bluetti-logger -- <BLUETOOTH_MAC>
This runs the broader loggingCommands set for the device and prints the parsed output.
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.
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>--onceExample:
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:
brokerusernamepasswordtls.caPathtls.certPathtls.keyPathtls.servernametls.rejectUnauthorizedintervaloncelogLeveladdressesCLI flags override config-file values when both are provided.
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"]
}
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:
ON / OFFThis project has been validated live on this machine against:
24:4C:AB:2C:24:8ESuccessful live validation includes:
probepollUseful 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.xAdditional development docs:
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.exeREADME.mdThe CLI will automatically use the published helper artifact when it exists.
There are two practical helper distribution modes:
On the current implementation, the framework-dependent helper is roughly one quarter the size of the self-contained helper.
FAQs
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
We found that bluetti-mqtt-node demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
GPT-6 Astra hits 100% on ExploitBench and finds zero-days autonomously, while independent tests reveal scope violations and monitoring gaps.

Product
Socket can now send alerts and supply chain attack notifications to Microsoft Teams, with filters that route the right updates to each channel.

Security News
pnpm 12 rewrites the package manager in Rust, cutting install times by up to 90% while preserving pnpm 11 workflows and lockfiles.