{
  "spec_version": 1,
  "slug": "felicity-flb-lfp-battery",
  "manufacturer": "Felicity Solar",
  "model": "FLB48314TG1 / FLB48100 / LPBF48 / LPBA48 LiFePO4 battery",
  "category": "Home battery",
  "supplier_url": "https://www.felicitysolar.com/",
  "default_configuration": {
    "protocol": "modbus_tcp",
    "port": 502,
    "unit_id": 1,
    "addressing": "zero_based",
    "byte_order": "BigEndian",
    "word_order": "HighFirst",
    "native_interface": "rs485",
    "serial": {
      "parity": "None",
      "baud_rate": 9600,
      "data_bits": 8,
      "stop_bits": 1
    }
  },
  "coils": [],
  "discrete_inputs": [],
  "input_registers": [],
  "holding_registers": [
    {
      "address": 1,
      "count": 1,
      "name": "Protocol type",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Voltronic LIB protocol frame; every pack answers the same holding-register block."
    },
    {
      "address": 2,
      "count": 1,
      "name": "Protocol version",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Document default 0."
    },
    {
      "address": 16,
      "count": 1,
      "name": "Number of cells",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Cells beyond this count read 0."
    },
    {
      "address": 37,
      "count": 1,
      "name": "Number of temperature sensors",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 38,
      "count": 1,
      "name": "Temperature sensor 1",
      "data_type": "UInt16",
      "units": "K",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Raw 3012 = 28.05 degC: degC = raw / 10 - 273.15. Sensor 6 is the MOSFET sensor; unused sensors read 0."
    },
    {
      "address": 39,
      "count": 1,
      "name": "Temperature sensor 2",
      "data_type": "UInt16",
      "units": "K",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "degC = raw / 10 - 273.15."
    },
    {
      "address": 40,
      "count": 1,
      "name": "Temperature sensor 3",
      "data_type": "UInt16",
      "units": "K",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "degC = raw / 10 - 273.15."
    },
    {
      "address": 48,
      "count": 1,
      "name": "Charge current",
      "data_type": "UInt16",
      "units": "A",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "0 while the pack is discharging. Verified as 0.1 A units (raw 19 = 1.9 A on the discharge register)."
    },
    {
      "address": 49,
      "count": 1,
      "name": "Discharge current",
      "data_type": "Int16",
      "units": "A",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Signed in the source (s16, 0.1 A); the pack reports negative while discharging and the source says to use the absolute value. Temperature rows use degC = raw / 10 - 273.15."
    },
    {
      "address": 50,
      "count": 1,
      "name": "Pack voltage",
      "data_type": "UInt16",
      "units": "V",
      "scale_factor": 0.001,
      "offset": 0,
      "access": "R",
      "description": "Felicity firmware reports millivolts (53400 = 53.400 V); the Voltronic document says 0.1 V. The verified scale is used."
    },
    {
      "address": 51,
      "count": 1,
      "name": "State of charge",
      "data_type": "UInt16",
      "units": "%",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 52,
      "count": 2,
      "name": "Full-charge capacity",
      "data_type": "UInt32",
      "units": "Ah",
      "scale_factor": 0.001,
      "offset": 0,
      "access": "R",
      "description": "High word first; 0x0005 0x5730 = 350000 mAh."
    },
    {
      "address": 54,
      "count": 1,
      "name": "Packs online",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Number of packs answering on the bus."
    },
    {
      "address": 55,
      "count": 1,
      "name": "Charge alarm",
      "data_type": "Hex",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Bit field: b0 CHT (charge high temperature), b1 COV (cell over-voltage), b2 CLT (charge low temperature), b3 OCC (over-current charging)."
    },
    {
      "address": 56,
      "count": 1,
      "name": "Discharge alarm",
      "data_type": "Hex",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Bit field: b0 DHT, b1 DLT, b2 FETHT, b3 CUV."
    },
    {
      "address": 57,
      "count": 1,
      "name": "Charge protection status",
      "data_type": "Hex",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Bit field: b0 PRES, b1 BoostNRDY, b2 AFEComm, b3 AFEOCC, b4 AFEOCD, b5 AFESCD, b6 FETHT, b7 SUV, b8 CHT, b9 CLT, b10 OCV, b11 OCC, b12 2NDOVP, b13 CANID, b15 OCC2."
    },
    {
      "address": 58,
      "count": 1,
      "name": "Charge protection status 2",
      "data_type": "Hex",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Bit field: b0 ShutdownByCmd, b1 Shutdown, b2 OCCHw, b3 IDError."
    },
    {
      "address": 59,
      "count": 1,
      "name": "Discharge protection status",
      "data_type": "Hex",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Bit field: b0 PRES, b1 BoostNRDY, b2 AFEOCC, b3 AFEOCD, b4 AFESCD, b6 IDError, b10 FETHT, b11 CUV, b12 OCD, b13 DLT, b14 DHT, b15 Shutdown."
    },
    {
      "address": 60,
      "count": 1,
      "name": "Discharge protection status 2",
      "data_type": "Hex",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Bit field: b0 AFEComm, b1 Short, b2 OCD2, b4 2NDOVP, b5 DHT2, b6 ShutdownByCmd, b13 CANID."
    },
    {
      "address": 61,
      "count": 1,
      "name": "BMS state",
      "data_type": "UInt16",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "Reserved, reads 0 in the documented firmware."
    },
    {
      "address": 62,
      "count": 2,
      "name": "Design capacity",
      "data_type": "UInt32",
      "units": "Ah",
      "scale_factor": 0.001,
      "offset": 0,
      "access": "R",
      "description": "High word first."
    },
    {
      "address": 112,
      "count": 1,
      "name": "Charge voltage limit",
      "data_type": "UInt16",
      "units": "V",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Raw 576 = 57.6 V."
    },
    {
      "address": 113,
      "count": 1,
      "name": "Discharge voltage limit",
      "data_type": "UInt16",
      "units": "V",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Raw 480 = 48.0 V."
    },
    {
      "address": 114,
      "count": 1,
      "name": "Charge current limit",
      "data_type": "UInt16",
      "units": "A",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Raw 320 / 400 / 480 = 32 / 40 / 48 A; differs per pack model."
    },
    {
      "address": 115,
      "count": 1,
      "name": "Discharge current limit",
      "data_type": "UInt16",
      "units": "A",
      "scale_factor": 0.1,
      "offset": 0,
      "access": "R",
      "description": "Raw 1600 = 160 A."
    },
    {
      "address": 116,
      "count": 1,
      "name": "Charge / discharge status",
      "data_type": "Hex",
      "units": "",
      "scale_factor": 1,
      "offset": 0,
      "access": "R",
      "description": "b7 charge enable, b6 discharge enable, b5 charge immediately (SOC <= 9 %), b4 charge immediately 2 (SOC 10-14 %), b3 full-charge request, b2 small-current charge request. Observed 0xC0 when idle."
    },
    {
      "address": 117,
      "count": 1,
      "name": "Run time to empty",
      "data_type": "UInt16",
      "units": "min",
      "scale_factor": 1,
      "offset": 0,
      "access": "R"
    },
    {
      "address": 118,
      "count": 2,
      "name": "Remaining capacity",
      "data_type": "UInt32",
      "units": "Ah",
      "scale_factor": 0.001,
      "offset": 0,
      "access": "R",
      "description": "High word first."
    }
  ],
  "combined_registers": [],
  "notes": "Secondary source (community document, not a vendor publication): \"Felicity Solar LiFePO4 battery - RS485 register map\" by Krzysztof Hajdamowicz, 2026-10-10, https://github.com/KrzysztofHajdamowicz/felicity-battery-modbus/blob/main/docs/felicity-battery-registers.pdf (human-readable protocol notes in docs/protocol.md of the same repository). It documents the Voltronic \"LIB\" BMS protocol as implemented by the Felicity FLB48314TG1 and the FLB48100 / LPBF48 / LPBA48 family, Modbus RTU 9600 8N1 at pack address 1 in its example frame, function 0x03, and states which rows are hardware-verified and which come from the Voltronic document. The source gives no factory pack address, so the unit 1 recorded here is a placeholder, not a cited value, and the user must set their pack's own address. Deliberate omissions: the cell-voltage array (17-36) and the per-module state arrays (64-105) - the point descriptions there are shifted against their register numbers in the source, so the rows could not be paired with confidence; and the BMS firmware/hardware version pair (3-6), whose encoding the source leaves open. Voltronic's error frames replace the Modbus byte count with a 16-bit register count, so a standard client rejects them; this affects error handling only, not the map. One master per bus, at least 500 ms between polls of a pack."
}
