Skip to content

Commit 33ee383

Browse files
committed
sun2000: optimize reading by grouping registers
Groups are done automatically basing on set of registers desired to read. The idea was discovered by @wlcrs and implemented in: https://github.com/wlcrs/huawei-solar-lib/blob/04ee7a765772f30f98aeca712344fd791d5579f9/src/huawei_solar/huawei_solar.py#L243 Then it was also implemented by @amreo in his fork: amreo@1ec907c In my environment whole reading set went from 5.5s down to 2.3s. This commit is not yet rust-formatted due to see the relevant changes easily.
1 parent b21d85b commit 33ee383

File tree

1 file changed

+49
-12
lines changed

1 file changed

+49
-12
lines changed

src/sun2000.rs

+49-12
Original file line numberDiff line numberDiff line change
@@ -1075,23 +1075,54 @@ impl Sun2000 {
10751075
let mut params: Vec<Parameter> = vec![];
10761076
let mut disconnected = false;
10771077
let now = Instant::now();
1078-
for p in parameters.into_iter().filter(|s| {
1078+
let mut params_wanted: Vec<_> = parameters.into_iter().filter(|s| {
10791079
(initial_read && s.initial_read)
10801080
|| (!initial_read
10811081
&& (s.save_to_influx
10821082
|| s.name.starts_with("state_")
10831083
|| s.name.starts_with("alarm_")
10841084
|| s.name.ends_with("_status")
10851085
|| s.name.ends_with("_code")))
1086-
}) {
1086+
}).collect();
1087+
1088+
//sort by register address
1089+
params_wanted.sort_by(|a, b| a.reg_address.cmp(&b.reg_address));
1090+
1091+
//group to 64-bytes register blocks
1092+
let mut reg_block = vec![];
1093+
let mut all_blocks = vec![];
1094+
let mut start_addr = None;
1095+
let mut pe = params_wanted.into_iter().peekable();
1096+
while pe.peek().is_some() {
1097+
let p = pe.next().unwrap();
1098+
if start_addr.is_none() {
1099+
start_addr = Some(p.reg_address);
1100+
} else {
1101+
if p.reg_address + p.len - start_addr.unwrap() > 64 {
1102+
start_addr = Some(p.reg_address);
1103+
all_blocks.push(reg_block);
1104+
reg_block = vec![];
1105+
}
1106+
}
1107+
reg_block.push(p);
1108+
}
1109+
//add remainder
1110+
all_blocks.push(reg_block);
1111+
1112+
for (i, reg_block) in all_blocks.iter().enumerate() {
10871113
if disconnected {
10881114
break;
10891115
}
1116+
1117+
let last = reg_block.last().unwrap();
1118+
let start_addr = reg_block[0].reg_address;
1119+
let len = last.reg_address + last.len - start_addr;
1120+
10901121
let mut attempts = 0;
10911122
while attempts < SUN2000_ATTEMPTS_PER_PARAM {
10921123
attempts = attempts + 1;
1093-
debug!("-> obtaining {} ({:?})...", p.name, p.desc);
1094-
let retval = ctx.read_holding_registers(p.reg_address, p.len);
1124+
debug!("-> obtaining register block #{} start={:#x}, len={}, attempt={}", i, start_addr, len, attempts);
1125+
let retval = ctx.read_holding_registers(start_addr, len);
10951126
let read_res;
10961127
let start = Instant::now();
10971128
let read_time;
@@ -1102,8 +1133,8 @@ impl Sun2000 {
11021133
}
11031134
Err(e) => {
11041135
let msg = format!(
1105-
"<i>{}</i>: read timeout (attempt #{} of {}), register: <green><i>{}</>, error: <b>{}</>",
1106-
self.name, attempts, SUN2000_ATTEMPTS_PER_PARAM, p.name, e
1136+
"<i>{}</i>: read timeout (attempt #{} of {}), register: <green><i>{:#x}+{}</>, error: <b>{}</>",
1137+
self.name, attempts, SUN2000_ATTEMPTS_PER_PARAM, start_addr, len, e
11071138
);
11081139
if attempts == SUN2000_ATTEMPTS_PER_PARAM {
11091140
error!("{}", msg);
@@ -1118,11 +1149,15 @@ impl Sun2000 {
11181149
Ok(data) => {
11191150
if read_time > Duration::from_secs_f32(3.5) {
11201151
warn!(
1121-
"<i>{}</i>: inverter has lagged during read, register: <green><i>{}</>, read time: <b>{:?}</>",
1122-
self.name, p.name, read_time
1152+
"<i>{}</i>: inverter has lagged during read, register: <green><i>{:#x}+{}</>, read time: <b>{:?}</>",
1153+
self.name, start_addr, len, read_time
11231154
);
11241155
}
11251156

1157+
for p in reg_block {
1158+
let offset = (p.reg_address - start_addr) as usize;
1159+
let data = &data[offset..offset + (p.len as usize)];
1160+
debug!("-> parsing {} ({:?}) @ {:#x} offset={:#x} len={}...", p.name, p.desc, p.reg_address, offset, p.len);
11261161
let mut val;
11271162
match &p.value {
11281163
ParamKind::Text(_) => {
@@ -1181,13 +1216,15 @@ impl Sun2000 {
11811216
let _ = Sun2000::save_to_influxdb(c, &self.name, param).await;
11821217
}
11831218
}
1184-
1185-
break; //read next parameter
1219+
}
1220+
//we parsed all parameters in this block,
1221+
//break the attempt loop and try next register block
1222+
break;
11861223
}
11871224
Err(e) => {
11881225
let msg = format!(
1189-
"<i>{}</i>: read error (attempt #{} of {}), register: <green><i>{}</>, error: <b>{}</>, read time: <b>{:?}</>",
1190-
self.name, attempts, SUN2000_ATTEMPTS_PER_PARAM, p.name, e, read_time
1226+
"<i>{}</i>: read error (attempt #{} of {}), register: <green><i>{:#x}+{}</>, error: <b>{}</>, read time: <b>{:?}</>",
1227+
self.name, attempts, SUN2000_ATTEMPTS_PER_PARAM, start_addr, len, e, read_time
11911228
);
11921229
match e.kind() {
11931230
ErrorKind::BrokenPipe | ErrorKind::ConnectionReset => {

0 commit comments

Comments
 (0)