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

givenergy-modbus

v2.0.0

Published

Native Node.js client for GivEnergy inverters over their proprietary Modbus TCP protocol

Readme

givenergy-modbus

CI npm node license GitHub Sponsors Buy Me a Coffee

Native Node.js client for GivEnergy inverters over their proprietary Modbus TCP protocol.

Attribution

This library would not exist without giv_tcp by britkat1980. The protocol framing, register mappings, validation quirks, and device discovery logic were all ported from that project. giv_tcp is the definitive reference for GivEnergy's undocumented Modbus protocol — if you need a battle-tested solution with a web UI and Home Assistant integration, use that.

Local connection

This library communicates directly with the inverter over your local network (port 8899). No GivEnergy cloud account or internet connection is required. If you prefer to use the official cloud API, GivEnergy provides a REST API — see the GivEnergy developer documentation for details.

Do not run this library at the same time as GivTCP (or any other client connected to port 8899). The GivEnergy data adapter does not reliably handle multiple concurrent TCP connections — responses may be routed to the wrong client, causing timeouts and missing data in both.

Installation

npm install givenergy-modbus

Requires Node.js 20+. TypeScript is optional — full type definitions are included.

Identify an inverter

If you just need to know what's at a given IP — without starting a full polling session — use identify(). It reads a single register block and closes the connection immediately:

import { GivEnergyInverter } from 'givenergy-modbus';

const identity = await GivEnergyInverter.identify({ host: '192.168.1.100' });
console.log(identity.serialNumber); // e.g. "SD2227G895"
console.log(identity.generation);   // "gen2", "gen3", or "three_phase"
console.log(identity.modelCode);    // raw device type code from HR(0)

This is useful during pairing or discovery when you don't need live data.

Quick start

import { discover, GivEnergyInverter } from 'givenergy-modbus';

// Find inverters on the local network
const devices = await discover(); // auto-detects subnet
// or: await discover('192.168.1.0/24')

if (devices.length === 0) {
  console.error('No inverters found');
  process.exit(1);
}

// Connect and auto-detect inverter generation (gen2, gen3, three-phase)
const inverter = await GivEnergyInverter.connect({ host: devices[0].host });

// Listen for data updates (every ~15 seconds)
inverter.on('data', (snapshot) => {
  console.log(`Solar: ${snapshot.solarPower}W`);
  console.log(`Battery: ${snapshot.stateOfCharge}%`);
  console.log(`Grid: ${snapshot.gridPower}W (+ = export)`);
});

// Listen for connection loss
inverter.on('lost', (err) => {
  console.error('Connection lost:', err.message);
});

// Read the latest snapshot at any time
const snapshot = inverter.getData();

// Control the inverter — modes are independent toggles
await inverter.setEcoMode(true);
await inverter.setTimedCharge(true);
await inverter.setChargeSlot(1, { start: '00:30', end: '04:30', targetStateOfCharge: 100 });
await inverter.setChargeRate(2600);
await inverter.syncDateTime();

Library scope

This library is stateless — it reads the current inverter state and sends individual register writes, but does not track what it has changed or automatically revert anything. Each method call is a single Modbus transaction: read registers, write a register, or poll for updates.

This means higher-level workflows like "force charge for 2 hours then revert to normal" need to be orchestrated by your application, not by this library. The library gives you the building blocks; you decide when and how to use them.

Orchestrating force charge / force discharge

A common use case is forcing the battery to charge from the grid (e.g. during cheap overnight rates) or discharge to the grid (e.g. during peak export rates). Here's how to build this on top of the library:

Force charge

import { GivEnergyInverter } from 'givenergy-modbus';

const inverter = await GivEnergyInverter.connect({ host: '192.168.1.100' });

// 1. Save the current state so you can restore it later
const before = inverter.getData();

// 2. Enable timed charge and set a charge slot covering "now"
await inverter.setTimedCharge(true);
await inverter.setChargeSlot(1, { start: '00:00', end: '23:59', targetStateOfCharge: 100 });

// 3. Your app is responsible for reverting when done — use a timer, cron, etc.
setTimeout(async () => {
  await inverter.setTimedCharge(before.timedCharge);
  // Restore original charge slot, rate, etc.
  await inverter.stop();
}, 2 * 60 * 60 * 1000); // 2 hours

Force discharge

// 1. Save current state
const before = inverter.getData();

// 2. Enable timed export with a discharge slot covering "now"
await inverter.setTimedExport(true);
await inverter.setDischargeSlot(1, { start: '00:00', end: '23:59' });

// 3. Revert when done (your app's responsibility)

Key points

  • Always save state before changing it. The library doesn't track previous values — snapshot fields like ecoMode, timedExport, timedCharge, chargeRatePercent, batteryReservePercent, and chargeSlots tell you the current config so you can restore it.
  • Your app owns the timer/revert logic. Whether that's setTimeout, a cron job, or a home automation trigger is up to you.
  • Modes are independent toggles, not mutually exclusive states. Eco mode (HR 27), timed export (HR 59), and timed charge (HR 96) can each be toggled independently without affecting each other. Gen3 inverters also have a battery pause mode (HR 318) and timed discharge slot (HR 319-320).
  • The inverter may take a few seconds to act on register writes. Poll with getData() or listen for 'data' events to confirm changes took effect.

API documentation

Full API reference is available at jak.github.io/givenergy-modbus — auto-generated from source with TypeDoc.

Built with this library

  • givenergy-mqtt — Bridge your inverter data to MQTT with Home Assistant auto-discovery.
  • GivEnergy for Homey — Homey app for monitoring solar, battery, and grid power, tracking energy in the Homey Energy dashboard, and automating inverter modes and charging schedules.

Protocol note

GivEnergy uses a non-standard Modbus framing — the standard Modbus TCP Application Data Unit (MBAP) header is modified with a proprietary wrapper that includes a device serial number, data adapter address, and function codes not found in the Modbus specification. This library implements that framing directly using Node.js net.Socket. No external Modbus library is used.