Start | End | Block description |
---|---|---|
3972 | 3972 | Unknown |
4096 | 4111 | Brand and model name |
4112 | 4239 | Empty |
4320 | 4320 | Date and time |
4352 | 4415 | Same as 5120-5183 |
4416 | 4607 | Empty |
4608 | 4671 | Unknown, maybe settings (seems static) |
4672 | 4863 | Empty |
5120 | 5183 | BMS status |
5184 | 5199 | Empty |
5200 | 5215 | BMS SN |
5216 | 5231 | Pack 0-x - Module 0-x Voltage |
5232 | 5295 | Empty |
5296 | 5311 | Pack 0-x - Module 0-x Temperature |
5312 | 5375 | Empty |
5376 | 5503 | Pack 0 Module 0-4 Cell Voltage |
5504 | 6143 | ?? Pack 1-5 Module 0-4 Cell Voltage |
6144 | 6271 | Pack 0 Module 0-4 Cell Temperature |
6272 | 6911 | ?? Pack 1-5 Module 0-4 Cell Temperature |
Last active
March 7, 2025 16:31
-
-
Save pavelmaca/170c282bdb9e20b6c624e8c7633be3b2 to your computer and use it in GitHub Desktop.
Pylontech Force H2 - Solarman Modbus RTU registry map
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
requests: | |
# Brand, Device name, FW Version | |
- start: 4096 | |
end: 4106 | |
mb_functioncode: 0x03 | |
# Device Date and Time - TODO | |
#- start: 4320 | |
# end: 4325 | |
# mb_functioncode: 0x03 | |
# BMS Status | |
- start: 5120 | |
end: 5135 | |
mb_functioncode: 0x03 | |
# Cell/Module Max/Min Temperature and Voltage | |
- start: 5136 | |
end: 5151 | |
mb_functioncode: 0x03 | |
# Total Charge, Discharge | |
- start: 5152 | |
end: 5167 | |
mb_functioncode: 0x03 | |
# Pack, Module, Cell count | |
- start: 5174 | |
end: 5175 | |
mb_functioncode: 0x03 | |
# Device SN | |
- start: 5200 | |
end: 5207 | |
mb_functioncode: 0x03 | |
# Pack 0 Module 0-3 Voltage | |
- start: 5216 | |
end: 5219 | |
mb_functioncode: 0x03 | |
# Pack 0 Module 0-3 Temperature | |
- start: 5296 | |
end: 5299 | |
mb_functioncode: 0x03 | |
# Pack 0 Module 0-3 Cells Voltage | |
#- start: 5376 | |
# end: 5465 | |
# mb_functioncode: 0x03 | |
# Pack 0 Module 0-3 Cells Temperature | |
#- start: 6144 | |
# end: 6233 | |
# mb_functioncode: 0x03 | |
parameters: | |
- group: Basic information | |
items: | |
- name: "Device SN" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 5 | |
registers: [ 5200,5201,5202,5203,5204,5205,5206,5207 ] | |
isstr: true | |
#- name: "Device Time" # TODO - cant parse format is [y, m, d, h, m, s] | |
# class: "" | |
# state_class: "" | |
# uom: "" | |
# scale: 1 | |
# rule: 8 | |
# registers: [4320,4321,4322,4323,4324,4325] | |
# isstr: true | |
- name: "Brand" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 5 | |
registers: [ 4096,4097,4098 ] | |
isstr: true | |
- name: "Device Name" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 5 | |
registers: [ 4101,4102,4103,4104,4105 ] | |
isstr: true | |
- name: "FW Version" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 7 | |
registers: [ 4106 ] # 00000001 00000110 = V1.6 | |
isstr: true | |
- name: "Total Charge" | |
class: "energy" | |
state_class: "total_increasing" | |
uom: "kWh" | |
scale: 1 | |
rule: 1 | |
registers: [ 5164 ] | |
icon: 'mdi:battery-plus' | |
- name: "Total Discharge" | |
class: "energy" | |
state_class: "total_increasing" | |
uom: "kWh" | |
scale: 1 | |
rule: 1 | |
registers: [ 5166 ] | |
icon: 'mdi:battery-minus' | |
#- name: "Battery Pack (parallel)" # not tested | |
# class: "" | |
# state_class: "" | |
# uom: "" | |
# scale: 1 | |
# rule: 1 | |
# registers: [5173] | |
- name: "Battery Module (series)" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 1 | |
registers: [ 5174 ] | |
- name: "Battery Cell (series)" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 1 | |
registers: [ 5175 ] | |
- group: Battery | |
items: | |
- name: "Battery Voltage" | |
class: "voltage" | |
state_class: "measurement" | |
uom: "V" | |
scale: 0.1 | |
rule: 1 | |
registers: [ 5123 ] | |
icon: 'mdi:battery' | |
- name: "Battery Current" | |
class: "current" | |
state_class: "measurement" | |
uom: "A" | |
scale: 0.01 | |
rule: 2 | |
registers: [ 5125 ] | |
icon: 'mdi:current-dc' | |
- name: "Battery Temperature" | |
class: "temperature" | |
state_class: "measurement" | |
uom: "°C" | |
scale: 0.1 | |
rule: 2 | |
registers: [ 5126 ] | |
icon: 'mdi:thermometer' | |
- name: "Battery Charge" | |
class: "battery" | |
state_class: "measurement" | |
uom: "%" | |
scale: 1 | |
rule: 1 | |
registers: [ 5127 ] | |
icon: 'mdi:battery' | |
- name: "Battery Cycle Times" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 1 | |
registers: [ 5128 ] | |
icon: 'mdi:battery-heart' | |
- name: "Max Charging Voltage" | |
class: "voltage" | |
state_class: "measurement" | |
uom: "V" | |
scale: 0.1 | |
rule: 1 | |
registers: [ 5129 ] | |
- name: "Max Charging Current" | |
class: "current" | |
state_class: "measurement" | |
uom: "A" | |
scale: 0.01 | |
rule: 2 | |
registers: [ 5131 ] | |
icon: 'mdi:current-dc' | |
- name: "Min Discharging Voltage" | |
class: "voltage" | |
state_class: "measurement" | |
uom: "V" | |
scale: 0.1 | |
rule: 1 | |
registers: [ 5132 ] | |
- name: "Max Discharging Current" | |
class: "current" | |
state_class: "measurement" | |
uom: "A" | |
scale: 0.01 | |
rule: 2 | |
registers: [ 5134 ] | |
icon: 'mdi:current-dc' | |
- name: "Max Cell Voltage" | |
class: "voltage" | |
state_class: "measurement" | |
uom: "V" | |
scale: 0.001 | |
rule: 1 | |
registers: [ 5136 ] | |
icon: 'mdi:battery' | |
- name: "Min Cell Voltage" | |
class: "voltage" | |
state_class: "measurement" | |
uom: "V" | |
scale: 0.001 | |
rule: 1 | |
registers: [ 5137 ] | |
icon: 'mdi:battery' | |
- name: "Max Cell Voltage ID" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 1 | |
registers: [ 5138 ] | |
- name: "Min Cell Voltage ID" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 1 | |
registers: [ 5139 ] | |
- name: "Max Cell Temperature" | |
class: "temperature" | |
state_class: "measurement" | |
uom: "°C" | |
scale: 0.1 | |
rule: 2 | |
registers: [ 5140 ] | |
icon: 'mdi:thermometer' | |
- name: "Min Cell Temperature" | |
class: "temperature" | |
state_class: "measurement" | |
uom: "°C" | |
scale: 0.1 | |
rule: 2 | |
registers: [ 5141 ] | |
icon: 'mdi:thermometer' | |
- name: "Max Cell Temperature ID" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 1 | |
registers: [ 5142 ] | |
- name: "Min Cell Temperature ID" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 1 | |
registers: [ 5143 ] | |
- name: "Max Module Voltage" | |
class: "voltage" | |
state_class: "measurement" | |
uom: "V" | |
scale: 0.01 | |
rule: 1 | |
registers: [ 5144 ] | |
icon: 'mdi:battery' | |
- name: "Min Module Voltage" | |
class: "voltage" | |
state_class: "measurement" | |
uom: "V" | |
scale: 0.01 | |
rule: 1 | |
registers: [ 5145 ] | |
icon: 'mdi:battery' | |
- name: "Max Module Voltage ID" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 1 | |
registers: [ 5146 ] | |
- name: "Min Module Voltage ID" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 1 | |
registers: [ 5147 ] | |
- name: "Max Module Temperature" | |
class: "temperature" | |
state_class: "measurement" | |
uom: "°C" | |
scale: 0.1 | |
rule: 2 | |
registers: [ 5148 ] | |
icon: 'mdi:thermometer' | |
- name: "Min Module Temperature" | |
class: "temperature" | |
state_class: "measurement" | |
uom: "°C" | |
scale: 0.1 | |
rule: 2 | |
registers: [ 5149 ] | |
icon: 'mdi:thermometer' | |
- name: "Max Module Temperature ID" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 1 | |
registers: [ 5150 ] | |
- name: "Min Module Temperature ID" | |
class: "" | |
state_class: "" | |
uom: "" | |
scale: 1 | |
rule: 1 | |
registers: [ 5151 ] | |
- name: "Battery SOH" | |
class: "battery" | |
state_class: "measurement" | |
uom: "%" | |
scale: 1 | |
rule: 1 | |
registers: [ 5152 ] | |
icon: 'mdi:battery' | |
- name: "Today Charge" | |
class: "energy" | |
state_class: "total_increasing" | |
uom: "kWh" | |
scale: 0.001 | |
rule: 1 | |
registers: [ 5160 ] | |
- name: "Today Discharge" | |
class: "energy" | |
state_class: "total_increasing" | |
uom: "kWh" | |
scale: 0.001 | |
rule: 1 | |
registers: [ 5162 ] | |
- group: Battery Module 0 | |
items: | |
- name: "Battery Module 0 Voltage" | |
class: "voltage" | |
state_class: "measurement" | |
uom: "V" | |
scale: 0.01 | |
rule: 1 | |
registers: [ 5216 ] | |
icon: 'mdi:battery' | |
- name: "Battery Module 0 Temperature" | |
class: "temperature" | |
state_class: "measurement" | |
uom: "°C" | |
scale: 0.1 | |
rule: 2 | |
registers: [ 5296 ] | |
icon: 'mdi:thermometer' | |
- group: Battery Module 1 | |
items: | |
- name: "Battery Module 1 Voltage" | |
class: "voltage" | |
state_class: "measurement" | |
uom: "V" | |
scale: 0.01 | |
rule: 1 | |
registers: [ 5217 ] | |
icon: 'mdi:battery' | |
- name: "Battery Module 1 Temperature" | |
class: "temperature" | |
state_class: "measurement" | |
uom: "°C" | |
scale: 0.1 | |
rule: 2 | |
registers: [ 5297 ] | |
icon: 'mdi:thermometer' | |
- group: Battery Module 2 | |
items: | |
- name: "Battery Module 2 Voltage" | |
class: "voltage" | |
state_class: "measurement" | |
uom: "V" | |
scale: 0.01 | |
rule: 1 | |
registers: [ 5218 ] | |
icon: 'mdi:battery' | |
- name: "Battery Module 2 Temperature" | |
class: "temperature" | |
state_class: "measurement" | |
uom: "°C" | |
scale: 0.1 | |
rule: 2 | |
registers: [ 5298 ] | |
icon: 'mdi:thermometer' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" Scan Modbus registers to find valid registers""" | |
from pysolarmanv5 import PySolarmanV5, V5FrameError | |
import umodbus.exceptions | |
import argparse | |
# Docs: | |
# - https://pysolarmanv5.readthedocs.io/en/stable/solarmanv5_protocol.html | |
# - https://github.com/jmccrohan/pysolarmanv5 | |
# | |
# Usage: | |
# pip install pysolarmanv5 | |
# python solarmanPylontechScan.py 5120 5199 > scan_240224_10_10.csv | |
deviceIP="192.168.x.x" # string IP address | |
deviceSerialNumber=123456789 # int device serial number | |
def main(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument("address", help="Address to start scanning from", type=int) | |
parser.add_argument("addressStop", help="Last address to scan", type=int) | |
args = parser.parse_args() | |
if args.address < 0: | |
print("Address must be greater than or equal to 0") | |
return | |
if args.addressStop < 0: | |
print("AddressStop must be greater than or equal to 0") | |
return | |
if args.addressStop < args.address: | |
print("AddressStop must be greater than or equal to address") | |
return | |
modbus = PySolarmanV5( | |
deviceIP, deviceSerialNumber, port=8899, mb_slave_id=1, verbose=False | |
) | |
# print as csv header | |
print("Register, Register Hex, Length, Value Int, Value Hex, Value Bin1, Value Bin2") | |
for x in range(args.address, args.addressStop): | |
try: | |
val = modbus.read_holding_registers(register_addr=x, quantity=1)[0] | |
binLeft = (val >> 8) & 0xff | |
binRight = val & 0xff | |
# csv row | |
print(f"{x}, {x:#06x}, 1, {val:05}, {val:#06x}, {binLeft:08b}, {binRight:08b}") | |
except (V5FrameError, umodbus.exceptions.IllegalDataAddressError): | |
print(f"{x}, {x:#06x}, 1") | |
continue | |
modbus.disconnect() | |
if __name__ == "__main__": | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you for this, this has been especially useful!
If the solarman logger is set to a "transparency" mode (config_hide.html), the communication with the battery can be done through Modbus RTU over Telnet over TCP, forgoing the solarman v5 protocol. The telnet part here is important; otherwise the communication will not succeed.
One caveat with some of these registers is that I believe some of the data might be 32-bit big-endian, split across 2 registers. In particular this could apply to the "charge/discharge today" registers, as otherwise the 16-bit register would be able to accommodate at most 2kW worth of continuous charge/discharge. This is very noticeable with max discharge current which is signed negative integer, and the register 5132 has value of
-1
(i.e. sign extended).