Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 182 additions & 0 deletions prostar_mppt.preset.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# Preset for Morningstar ProStar MPPT Solar Charge Controller
# Register values use IEEE 754 half-precision float (Float16) unless noted.
# Reference: ProStar MPPT MODBUS Specification v05 (MS-001723), 2 March 2021

config_version = 1
# Name of this device preset, used for lookup
name = "prostar_mppt"
# Type of this preset
type = "device"
# Dependencies required by all inputs in this device preset
_dependencies = [ "pymodbus", "pyserial" ]

# Preset-level metadata; format follows that specified in the top-level
[metadata]
name_full = "Morningstar ProStar MPPT charge controller"
author = "C.A.M. Gerlach and the UAH HAMMA group"
description = "Device preset for the Morningstar ProStar MPPT solar charge controller"
homepage = "https://hamma.dev/"
repo = "https://github.com/hamma-dev/mjolnir-presets"
preset_version = "0.1.0"
brokkr_version_min = "0.3.0"

# Data type presets to use for the data types that follow
# Float16 registers decode directly via struct format "e" (no scale/base/power)
[type_presets]
float16_v = { input_type = "e", unit = "V", uncertainty = true, digits = 3 }
float16_a = { input_type = "e", unit = "A", uncertainty = true, digits = 3 }
float16_w = { input_type = "e", unit = "W", uncertainty = true, digits = 1 }
float16_c = { input_type = "e", unit = "C", uncertainty = true, digits = 1 }
float16_ah = { input_type = "e", unit = "Ah", uncertainty = true, digits = 1 }
amp_hours = { input_type = "I", conversion = "custom", unit = "Ah", uncertainty = true, scale = 0.1, digits = 1 }
kilowatt_hours = { conversion = "custom", unit = "kWh", uncertainty = true, scale = 0.1, digits = 1 }
bitfield = { conversion = "bitfield", unit = false, uncertainty = false }
bitfield_32 = { input_type = "I", conversion = "bitfield", unit = false, uncertainty = false }

# Data types referenced in individual presets
[data_types]
# Filtered ADC measurements (registers 0x0010-0x0019)
adc_ic = { full_name = "Charge Current", type_presets = "float16_a" }
adc_ia = { full_name = "Array Current", type_presets = "float16_a" }
adc_vbterm = { full_name = "Batt Terminal Voltage", type_presets = "float16_v" }
adc_va = { full_name = "Array Voltage", type_presets = "float16_v" }
adc_vl = { full_name = "Load Voltage", type_presets = "float16_v" }
adc_ib = { full_name = "Battery Current (Net)", type_presets = "float16_a" }
adc_il = { full_name = "Load Current", type_presets = "float16_a" }
adc_vbsense = { full_name = "Batt Sense Voltage", type_presets = "float16_v" }
adc_vb_f_1m = { full_name = "Batt Voltage (60s Filter)", type_presets = "float16_v" }
adc_ib_f_1m = { full_name = "Batt Current (60s Filter)", type_presets = "float16_a" }

# Temperatures (registers 0x001A-0x0020)
t_hs = { full_name = "Heatsink Temp", type_presets = "float16_c" }
t_batt = { full_name = "Battery Temp", type_presets = "float16_c" }
t_amb = { full_name = "Ambient Temp", type_presets = "float16_c" }
t_rts = { full_name = "Remote Temp", type_presets = "float16_c" }
t_ind_u = { full_name = "Phase U Inductor Temp", type_presets = "float16_c" }
t_ind_v = { full_name = "Phase V Inductor Temp", type_presets = "float16_c" }
t_ind_w = { full_name = "Phase W Inductor Temp", type_presets = "float16_c" }

# Charger status (registers 0x0021-0x0025)
charge_state = { unit = false, uncertainty = false }
array_fault = { type_presets = "bitfield" }
vb_f = { full_name = "Batt Voltage (25s Filter)", type_presets = "float16_v" }
vb_ref = { full_name = "Ref Voltage", type_presets = "float16_v" }
vb_ref_charge_slave = { full_name = "Ref Voltage Slave", type_presets = "float16_v" }

# Charge accumulation (registers 0x0026-0x002B)
ahc_r = { full_name = "Ah Charge (rst)", type_presets = "amp_hours" }
ahc_t = { full_name = "Ah Charge (tot)", type_presets = "amp_hours" }
kwhc_r = { full_name = "kWh Charge (rst)", type_presets = "kilowatt_hours" }
kwhc_t = { full_name = "kWh Charge (tot)", type_presets = "kilowatt_hours" }

# Temperature foldback limits (registers 0x002C-0x002D)
tb_lo_limit_100 = { full_name = "Batt Temp Foldback 100%", type_presets = "float16_c" }
tb_lo_limit_0 = { full_name = "Batt Temp Foldback 0%", type_presets = "float16_c" }

# Load status (registers 0x002E-0x0035)
load_state = { unit = false, uncertainty = false }
load_fault = { type_presets = "bitfield" }
v_lvd = { full_name = "LVD Voltage", type_presets = "float16_v" }
v_lhvd = { full_name = "Load HVD Voltage", type_presets = "float16_v" }
ahl_r = { full_name = "Ah Load (rst)", type_presets = "amp_hours" }
ahl_t = { full_name = "Ah Load (tot)", type_presets = "amp_hours" }

# Miscellaneous (registers 0x0036-0x003B)
hourmeter = { input_type = "I", unit = "h", uncertainty = false }
alarm = { type_presets = "bitfield_32" }
dip_switch = { type_presets = "bitfield" }
led_state = { full_name = "SOC LED State", unit = false, uncertainty = false }

# MPPT (registers 0x003C-0x0040)
power_out = { full_name = "Charger Output Power", type_presets = "float16_w" }
sweep_vmp = { full_name = "Array Vmp (Sweep)", type_presets = "float16_v" }
sweep_pmax = { full_name = "Array Max Power (Sweep)", type_presets = "float16_w" }
sweep_voc = { full_name = "Array Voc (Sweep)", type_presets = "float16_v" }
va_ref = { full_name = "Array Target Voltage", type_presets = "float16_v" }

# Daily logger (registers 0x0041-0x004C)
vb_min_daily = { full_name = "Batt Voltage Min (Daily)", type_presets = "float16_v" }
vb_max_daily = { full_name = "Batt Voltage Max (Daily)", type_presets = "float16_v" }
ahc_daily = { full_name = "Ah Charge (Daily)", type_presets = "float16_ah" }
ahl_daily = { full_name = "Ah Load (Daily)", type_presets = "float16_ah" }
array_fault_daily = { type_presets = "bitfield" }
load_fault_daily = { type_presets = "bitfield" }
alarm_daily = { type_presets = "bitfield_32" }
time_ab_daily = { full_name = "Time in Absorption (Daily)", unit = "s", uncertainty = false }
time_eq_daily = { full_name = "Time in Equalization (Daily)", unit = "s", uncertainty = false }
time_fl_daily = { full_name = "Time in Float (Daily)", unit = "s", uncertainty = false }
va_max_daily = { full_name = "Array Voltage Max (Daily)", type_presets = "float16_v" }

[inputs]
# Input to read the RAM status data (holding registers) of the ProStar MPPT
# Reads 61 contiguous registers from 0x0010 to 0x004C
[inputs.ram]
_module_path = "brokkr.inputs.modbus"
_class_name = "ModbusSerialInput"
_dependencies = []
name = "ProStar MPPT RAM Status Data"
unit = 1
start_address = 0x0010
serial_port = ""
serial_pids = [ 24597 ]
try_usb_reset = true
modbus_kwargs.baudrate = 9600
modbus_kwargs.parity = "N"
modbus_kwargs.stopbits = 2
modbus_kwargs.strict = false
data_types = [
"adc_ic",
"adc_ia",
"adc_vbterm",
"adc_va",
"adc_vl",
"adc_ib",
"adc_il",
"adc_vbsense",
"adc_vb_f_1m",
"adc_ib_f_1m",
"t_hs",
"t_batt",
"t_amb",
"t_rts",
"t_ind_u",
"t_ind_v",
"t_ind_w",
"charge_state",
"array_fault",
"vb_f",
"vb_ref",
"vb_ref_charge_slave",
"ahc_r",
"ahc_t",
"kwhc_r",
"kwhc_t",
"tb_lo_limit_100",
"tb_lo_limit_0",
"load_state",
"load_fault",
"v_lvd",
"v_lhvd",
"ahl_r",
"ahl_t",
"hourmeter",
"alarm",
"dip_switch",
"led_state",
"power_out",
"sweep_vmp",
"sweep_pmax",
"sweep_voc",
"va_ref",
"vb_min_daily",
"vb_max_daily",
"ahc_daily",
"ahl_daily",
"array_fault_daily",
"load_fault_daily",
"alarm_daily",
"time_ab_daily",
"time_eq_daily",
"time_fl_daily",
"va_max_daily",
]