Skip to content

Commit e4d470b

Browse files
committed
Revert growatt_modbus.py to fix MIN profile communication errors
The dev branch version extended the 3000 register range from 111 to 251 registers and added 31000 range reading. This causes 'extra data' errors and communication timeouts with MIN profile inverters. Reverted growatt_modbus.py back to previous version that works with MIN profiles while keeping the updated MOD and SPH TL3 profile definitions. Fixes: 'No response received after 3 retries' and 'extra data' errors
1 parent fd7c700 commit e4d470b

1 file changed

Lines changed: 31 additions & 132 deletions

File tree

custom_components/growatt_modbus/growatt_modbus.py

Lines changed: 31 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -72,27 +72,11 @@ class GrowattData:
7272
pv3_power: float = 0.0 # W
7373
pv_total_power: float = 0.0 # W
7474

75-
# AC Output (generic - usually Phase R for 3-phase)
75+
# AC Output
7676
ac_voltage: float = 0.0 # V
7777
ac_current: float = 0.0 # A
7878
ac_power: float = 0.0 # W
7979
ac_frequency: float = 0.0 # Hz
80-
81-
# Three-Phase AC Output (individual phases)
82-
ac_voltage_r: float = 0.0 # V (Phase R/L1)
83-
ac_current_r: float = 0.0 # A (Phase R/L1)
84-
ac_power_r: float = 0.0 # W (Phase R/L1)
85-
ac_voltage_s: float = 0.0 # V (Phase S/L2)
86-
ac_current_s: float = 0.0 # A (Phase S/L2)
87-
ac_power_s: float = 0.0 # W (Phase S/L2)
88-
ac_voltage_t: float = 0.0 # V (Phase T/L3)
89-
ac_current_t: float = 0.0 # A (Phase T/L3)
90-
ac_power_t: float = 0.0 # W (Phase T/L3)
91-
92-
# Line-to-Line Voltages (3-phase only)
93-
ac_voltage_rs: float = 0.0 # V
94-
ac_voltage_st: float = 0.0 # V
95-
ac_voltage_tr: float = 0.0 # V
9680

9781
# Power Flow (storage/hybrid models)
9882
power_to_user: float = 0.0 # W
@@ -426,7 +410,6 @@ def read_all_data(self) -> Optional[GrowattData]:
426410
has_base_range = any(0 <= addr < 1000 for addr in addresses)
427411
has_storage_range = any(1000 <= addr < 2000 for addr in addresses)
428412
has_3000_range = any(3000 <= addr < 4000 for addr in addresses)
429-
has_31000_range = any(31000 <= addr < 32000 for addr in addresses)
430413

431414
# Read base range (0-124) if needed - SPH models
432415
if has_base_range:
@@ -452,31 +435,18 @@ def read_all_data(self) -> Optional[GrowattData]:
452435
for i, value in enumerate(registers):
453436
self._register_cache[1000 + i] = value
454437

455-
# Read 3000 range if needed - MIN/MOD models
438+
# Read 3000 range if needed - MIN models
456439
if has_3000_range:
457-
logger.debug("Reading 3000 range (3000-3250)")
458-
# Extended range to cover MOD battery registers up to 3250
459-
registers = self.read_input_registers(3000, 251)
440+
logger.debug("Reading 3000 range (3000-3110)")
441+
registers = self.read_input_registers(3000, 111)
460442
if registers is None:
461443
logger.error("Failed to read main input register block")
462444
return None
463-
445+
464446
# Populate cache
465447
for i, value in enumerate(registers):
466448
self._register_cache[3000 + i] = value
467-
468-
# Read 31000 range if needed - MOD extended battery/BMS range
469-
if has_31000_range:
470-
logger.debug("Reading 31000 range (31100-31300)")
471-
registers = self.read_input_registers(31100, 201)
472-
if registers is None:
473-
logger.warning("Failed to read extended battery register block (31100+)")
474-
# Don't return None - continue with what we have
475-
else:
476-
# Populate cache
477-
for i, value in enumerate(registers):
478-
self._register_cache[31100 + i] = value
479-
449+
480450
# Now extract values using the register map
481451
try:
482452
# Status
@@ -526,12 +496,12 @@ def read_all_data(self) -> Optional[GrowattData]:
526496
# Calculate from strings if not available
527497
data.pv_total_power = data.pv1_power + data.pv2_power + data.pv3_power
528498

529-
# AC Output (generic - will use Phase R via alias for 3-phase)
499+
# AC Output
530500
ac_voltage_addr = self._find_register_by_name('ac_voltage')
531501
ac_current_addr = self._find_register_by_name('ac_current')
532502
ac_power_addr = self._find_register_by_name('ac_power_low')
533503
ac_freq_addr = self._find_register_by_name('ac_frequency')
534-
504+
535505
if ac_voltage_addr:
536506
data.ac_voltage = self._get_register_value(ac_voltage_addr) or 0.0
537507
if ac_current_addr:
@@ -540,51 +510,6 @@ def read_all_data(self) -> Optional[GrowattData]:
540510
data.ac_power = self._get_register_value(ac_power_addr) or 0.0
541511
if ac_freq_addr:
542512
data.ac_frequency = self._get_register_value(ac_freq_addr) or 0.0
543-
544-
# Three-Phase AC Output (individual phases)
545-
# Phase R
546-
ac_voltage_r_addr = self._find_register_by_name('ac_voltage_r')
547-
ac_current_r_addr = self._find_register_by_name('ac_current_r')
548-
ac_power_r_addr = self._find_register_by_name('ac_power_r_low')
549-
if ac_voltage_r_addr:
550-
data.ac_voltage_r = self._get_register_value(ac_voltage_r_addr) or 0.0
551-
if ac_current_r_addr:
552-
data.ac_current_r = self._get_register_value(ac_current_r_addr) or 0.0
553-
if ac_power_r_addr:
554-
data.ac_power_r = self._get_register_value(ac_power_r_addr) or 0.0
555-
556-
# Phase S
557-
ac_voltage_s_addr = self._find_register_by_name('ac_voltage_s')
558-
ac_current_s_addr = self._find_register_by_name('ac_current_s')
559-
ac_power_s_addr = self._find_register_by_name('ac_power_s_low')
560-
if ac_voltage_s_addr:
561-
data.ac_voltage_s = self._get_register_value(ac_voltage_s_addr) or 0.0
562-
if ac_current_s_addr:
563-
data.ac_current_s = self._get_register_value(ac_current_s_addr) or 0.0
564-
if ac_power_s_addr:
565-
data.ac_power_s = self._get_register_value(ac_power_s_addr) or 0.0
566-
567-
# Phase T
568-
ac_voltage_t_addr = self._find_register_by_name('ac_voltage_t')
569-
ac_current_t_addr = self._find_register_by_name('ac_current_t')
570-
ac_power_t_addr = self._find_register_by_name('ac_power_t_low')
571-
if ac_voltage_t_addr:
572-
data.ac_voltage_t = self._get_register_value(ac_voltage_t_addr) or 0.0
573-
if ac_current_t_addr:
574-
data.ac_current_t = self._get_register_value(ac_current_t_addr) or 0.0
575-
if ac_power_t_addr:
576-
data.ac_power_t = self._get_register_value(ac_power_t_addr) or 0.0
577-
578-
# Line-to-Line Voltages
579-
ac_voltage_rs_addr = self._find_register_by_name('line_voltage_rs')
580-
ac_voltage_st_addr = self._find_register_by_name('line_voltage_st')
581-
ac_voltage_tr_addr = self._find_register_by_name('line_voltage_tr')
582-
if ac_voltage_rs_addr:
583-
data.ac_voltage_rs = self._get_register_value(ac_voltage_rs_addr) or 0.0
584-
if ac_voltage_st_addr:
585-
data.ac_voltage_st = self._get_register_value(ac_voltage_st_addr) or 0.0
586-
if ac_voltage_tr_addr:
587-
data.ac_voltage_tr = self._get_register_value(ac_voltage_tr_addr) or 0.0
588513

589514
# Power Flow (if available - storage/hybrid models)
590515
power_to_user_addr = self._find_register_by_name('power_to_user_low')
@@ -686,15 +611,11 @@ def write_register(self, register: int, value: int) -> bool:
686611

687612

688613
def _find_register_by_name(self, name: str) -> Optional[int]:
689-
"""Find register address by its name or alias"""
614+
"""Find register address by its name"""
690615
input_regs = self.register_map['input_registers']
691616
for addr, reg_info in input_regs.items():
692-
# Check exact name match
693617
if reg_info['name'] == name:
694618
return addr
695-
# Check alias match (for 3-phase compatibility)
696-
if reg_info.get('alias') == name:
697-
return addr
698619
return None
699620

700621
def _read_energy_breakdown(self, data: GrowattData) -> None:
@@ -757,53 +678,31 @@ def _read_battery_data(self, data: GrowattData) -> None:
757678
data.battery_temp = self._get_register_value(addr) or 0.0
758679
logger.debug(f"Battery temp from reg {addr}: {data.battery_temp}°C")
759680

760-
# Battery power (signed: positive=charging, negative=discharging)
761-
# Try new signed battery_power register first (MOD series @ 31126)
762-
addr = self._find_register_by_name('battery_power_low')
681+
# Charge power (try to read from registers first)
682+
addr = self._find_register_by_name('charge_power_low')
763683
if addr:
764684
raw_low = self._register_cache.get(addr, 0)
765-
pair_addr = self._find_register_by_name('battery_power_high')
685+
pair_addr = self._find_register_by_name('charge_power_high')
766686
raw_high = self._register_cache.get(pair_addr, 0) if pair_addr else 0
767-
battery_power = self._get_register_value(addr) or 0.0
768-
logger.debug(f"Battery power (signed): HIGH={raw_high} (reg {pair_addr}), LOW={raw_low} (reg {addr}) → {battery_power}W")
769-
770-
# Split into charge/discharge based on sign
771-
if battery_power > 0:
772-
data.charge_power = battery_power
773-
data.discharge_power = 0.0
774-
logger.debug(f" → Charging: {data.charge_power}W")
775-
elif battery_power < 0:
776-
data.charge_power = 0.0
777-
data.discharge_power = abs(battery_power)
778-
logger.debug(f" → Discharging: {data.discharge_power}W")
779-
else:
780-
data.charge_power = 0.0
781-
data.discharge_power = 0.0
782-
else:
783-
# Fallback: Try old separate charge/discharge registers (SPH series)
784-
addr = self._find_register_by_name('charge_power_low')
785-
if addr:
786-
raw_low = self._register_cache.get(addr, 0)
787-
pair_addr = self._find_register_by_name('charge_power_high')
788-
raw_high = self._register_cache.get(pair_addr, 0) if pair_addr else 0
789-
data.charge_power = self._get_register_value(addr) or 0.0
790-
logger.debug(f"Charge power: HIGH={raw_high} (reg {pair_addr}), LOW={raw_low} (reg {addr}) → {data.charge_power}W")
791-
elif data.battery_voltage > 0 and data.battery_current < 0:
792-
# Fallback: Calculate from V×I when charging (negative current)
793-
data.charge_power = data.battery_voltage * abs(data.battery_current)
794-
logger.debug(f"Charge power (calculated): {data.battery_voltage}V × {abs(data.battery_current)}A = {data.charge_power}W")
795-
796-
addr = self._find_register_by_name('discharge_power_low')
797-
if addr:
798-
raw_low = self._register_cache.get(addr, 0)
799-
pair_addr = self._find_register_by_name('discharge_power_high')
800-
raw_high = self._register_cache.get(pair_addr, 0) if pair_addr else 0
801-
data.discharge_power = self._get_register_value(addr) or 0.0
802-
logger.debug(f"Discharge power: HIGH={raw_high} (reg {pair_addr}), LOW={raw_low} (reg {addr}) → {data.discharge_power}W")
803-
elif data.battery_voltage > 0 and data.battery_current > 0:
804-
# Fallback: Calculate from V×I when discharging (positive current)
805-
data.discharge_power = data.battery_voltage * data.battery_current
806-
logger.debug(f"Discharge power (calculated): {data.battery_voltage}V × {data.battery_current}A = {data.discharge_power}W")
687+
data.charge_power = self._get_register_value(addr) or 0.0
688+
logger.debug(f"Charge power: HIGH={raw_high} (reg {pair_addr}), LOW={raw_low} (reg {addr}) → {data.charge_power}W")
689+
elif data.battery_voltage > 0 and data.battery_current < 0:
690+
# Fallback: Calculate from V×I when charging (negative current)
691+
data.charge_power = data.battery_voltage * abs(data.battery_current)
692+
logger.debug(f"Charge power (calculated): {data.battery_voltage}V × {abs(data.battery_current)}A = {data.charge_power}W")
693+
694+
# Discharge power (try to read from registers first)
695+
addr = self._find_register_by_name('discharge_power_low')
696+
if addr:
697+
raw_low = self._register_cache.get(addr, 0)
698+
pair_addr = self._find_register_by_name('discharge_power_high')
699+
raw_high = self._register_cache.get(pair_addr, 0) if pair_addr else 0
700+
data.discharge_power = self._get_register_value(addr) or 0.0
701+
logger.debug(f"Discharge power: HIGH={raw_high} (reg {pair_addr}), LOW={raw_low} (reg {addr}) → {data.discharge_power}W")
702+
elif data.battery_voltage > 0 and data.battery_current > 0:
703+
# Fallback: Calculate from V×I when discharging (positive current)
704+
data.discharge_power = data.battery_voltage * data.battery_current
705+
logger.debug(f"Discharge power (calculated): {data.battery_voltage}V × {data.battery_current}A = {data.discharge_power}W")
807706

808707
# Charge energy today
809708
addr = self._find_register_by_name('charge_energy_today_low')

0 commit comments

Comments
 (0)