Skip to content

Several improvements and fixes #99

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 43 commits into
base: v1.1.10
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
ec88c27
soft-disable modbus registers that do not respond for 12 hours
jaredmauch Jul 1, 2025
c3ec93d
Merge branch 'main' of github.com:jaredmauch/PythonProtocolGateway
jaredmauch Jul 1, 2025
3036753
add documentation
jaredmauch Jul 1, 2025
bdf8812
per serial port locking
jaredmauch Jul 1, 2025
31076c2
Revert "per serial port locking"
jaredmauch Jul 1, 2025
b3e93b9
fix multiple serial ports
jaredmauch Jul 1, 2025
a175a30
test fix
jaredmauch Jul 1, 2025
12c8044
test fix
jaredmauch Jul 1, 2025
dae76f2
cleanup debugs
jaredmauch Jul 1, 2025
682d8c8
cleanup debugs
jaredmauch Jul 1, 2025
77bfa25
enum test fix
jaredmauch Jul 1, 2025
e762338
cleanup
jaredmauch Jul 1, 2025
4c6d4e6
Add EG4-12kpv
jaredmauch Jul 1, 2025
2072f2d
fix fwcode processing, fix failure logging
jaredmauch Jul 1, 2025
97aa2d0
improve error reporting
jaredmauch Jul 1, 2025
1a98884
improve error reporting
jaredmauch Jul 1, 2025
ccb2af7
better string handling
jaredmauch Jul 1, 2025
7990400
debug serial numbers
jaredmauch Jul 2, 2025
0b8ad34
debug serial numbers
jaredmauch Jul 2, 2025
51c2b51
concurrency fix
jaredmauch Jul 2, 2025
8246a41
concurrency fix
jaredmauch Jul 2, 2025
4ad77b9
concurrency fix
jaredmauch Jul 2, 2025
32e8d47
concurrency fix
jaredmauch Jul 2, 2025
9056e0f
concurrency fix
jaredmauch Jul 2, 2025
ab602fc
concurrency fix
jaredmauch Jul 2, 2025
27e3c2f
concurrency fix
jaredmauch Jul 2, 2025
2ec1fa8
concurrency fix
jaredmauch Jul 2, 2025
08e2843
concurrency fix
jaredmauch Jul 2, 2025
596700a
config parsing fix
jaredmauch Jul 2, 2025
fae0f26
concurrency debugs
jaredmauch Jul 2, 2025
8aeac43
concurrency debugs
jaredmauch Jul 2, 2025
71cb3ab
concurrency debugs
jaredmauch Jul 2, 2025
01a9bd1
concurrency debugs
jaredmauch Jul 2, 2025
e9f2582
concurrency debugs
jaredmauch Jul 2, 2025
fa5394f
concurrency debugs
jaredmauch Jul 2, 2025
dbd4a12
debugs
jaredmauch Jul 2, 2025
0efc1a0
debugs
jaredmauch Jul 2, 2025
257de4c
debugs
jaredmauch Jul 2, 2025
1e57cb2
debugs
jaredmauch Jul 2, 2025
53a31a2
fix protocol settings
jaredmauch Jul 2, 2025
fe2b368
remove forced disconnects between reads
jaredmauch Jul 2, 2025
cec1ed8
move logs from info to debug
jaredmauch Jul 2, 2025
8706bf0
Delete REGISTER_FAILURE_TRACKING_SUMMARY.md
jaredmauch Jul 2, 2025
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ solark_v1.1 = SolarArk 8/12K Inverters - Untested
hdhk_16ch_ac_module = some chinese current monitoring device :P
srne_2021_v1.96 = SRNE inverters 2021+ (tested at ASF48100S200-H, ok-ish for HF2430U60-100 )

eg4_v58 = eg4 inverters ( EG4-6000XP, EG4-18K ) - confirmed working
eg4_v58 = eg4 inverters ( EG4-6000XP, EG4-12K, EG4-18K ) - confirmed working
eg4_3000ehv_v1 = eg4 inverters ( EG4_3000EHV )
```

Expand Down
59 changes: 57 additions & 2 deletions classes/protocol_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import os
import re
import time
import copy
from dataclasses import dataclass
from enum import Enum
from typing import TYPE_CHECKING, Union
Expand Down Expand Up @@ -224,6 +225,9 @@ class registry_map_entry:
write_mode : WriteMode = WriteMode.READ
''' enable disable reading/writing '''

has_enum_mapping : bool = False
''' indicates if this field has enum mappings that should be treated as strings '''

def __str__(self):
return self.variable_name

Expand Down Expand Up @@ -685,7 +689,8 @@ def process_row(row):
value_regex=value_regex,
read_command = read_command,
read_interval=read_interval,
write_mode=writeMode
write_mode=writeMode,
has_enum_mapping=value_is_json
)
registry_map.append(item)

Expand Down Expand Up @@ -794,6 +799,11 @@ def calculate_registry_ranges(self, map : list[registry_map_entry], max_register
except ValueError:
pass

# Debug: log the parameters
import logging
log = logging.getLogger(__name__)
log.debug(f"calculate_registry_ranges: max_register={max_register}, max_batch_size={max_batch_size}, map_size={len(map)}, init={init}")

start = -max_batch_size
ranges : list[tuple] = []

Expand Down Expand Up @@ -871,6 +881,7 @@ def load_registry_map(self, registry_type : Registry_Type, file : str = "", sett
size = item.register

self.registry_map_size[registry_type] = size
self._log.debug(f"load_registry_map: {registry_type.name} - loaded {len(self.registry_map[registry_type])} entries, max_register={size}")
self.registry_map_ranges[registry_type] = self.calculate_registry_ranges(self.registry_map[registry_type], self.registry_map_size[registry_type], init=True)

def process_register_bytes(self, registry : dict[int,bytes], entry : registry_map_entry):
Expand Down Expand Up @@ -1115,7 +1126,8 @@ def process_register_ushort(self, registry : dict[int, int], entry : registry_ma
value = registry[entry.register].to_bytes((16 + 7) // 8, byteorder=byte_order) #convert to ushort to bytes
value = value.hex() #convert bytes to hex
elif entry.data_type == Data_Type.ASCII:
value = registry[entry.register].to_bytes((16 + 7) // 8, byteorder=byte_order) #convert to ushort to bytes
# For ASCII data, use little-endian byte order to read characters in correct order
value = registry[entry.register].to_bytes((16 + 7) // 8, byteorder="little") #convert to ushort to bytes
try:
value = value.decode("utf-8") #convert bytes to ascii
except UnicodeDecodeError as e:
Expand Down Expand Up @@ -1300,4 +1312,47 @@ def replace_vars(match):
for r in results:
print(evaluate_expression(r))

def reset_register_timestamps(self):
"""Reset the next_read_timestamp values for all registry entries"""
for registry_type in Registry_Type:
if registry_type in self.registry_map:
for entry in self.registry_map[registry_type]:
entry.next_read_timestamp = 0
self._log.debug(f"Reset timestamps for all registry entries in protocol {self.protocol}")

def __deepcopy__(self, memo):
"""Custom deep copy implementation to handle non-copyable attributes"""
# Create a new instance
new_instance = protocol_settings.__new__(protocol_settings)

# Copy basic attributes
new_instance.protocol = self.protocol
new_instance.settings_dir = self.settings_dir
new_instance.transport_settings = self.transport_settings
new_instance.byteorder = self.byteorder

# Copy dictionaries and lists
new_instance.variable_mask = copy.deepcopy(self.variable_mask, memo)
new_instance.variable_screen = copy.deepcopy(self.variable_screen, memo)
new_instance.codes = copy.deepcopy(self.codes, memo)
new_instance.settings = copy.deepcopy(self.settings, memo)

# Copy registry maps with deep copy of entries
new_instance.registry_map = {}
for registry_type, entries in self.registry_map.items():
new_instance.registry_map[registry_type] = copy.deepcopy(entries, memo)

new_instance.registry_map_size = copy.deepcopy(self.registry_map_size, memo)
new_instance.registry_map_ranges = copy.deepcopy(self.registry_map_ranges, memo)

# Copy transport
new_instance.transport = self.transport

# Recreate logger (not copyable)
new_instance._log_level = self._log_level
new_instance._log = logging.getLogger(__name__)
new_instance._log.setLevel(new_instance._log_level)

return new_instance

#settings = protocol_settings('v0.14')
Loading