lxp-packet 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/lib/lxp/packet/read_input1.rb +52 -28
- data/lib/lxp/packet/read_input2.rb +30 -11
- data/lib/lxp/packet/read_input3.rb +16 -4
- data/lib/lxp/utils.rb +3 -5
- data/lib/lxp/version.rb +1 -1
- data/spec/parser_spec.rb +24 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4fc4ef9aa204639ee245d39bba281bb3ec005013a7a7d3f16f975d5e31a6eca6
|
4
|
+
data.tar.gz: 9cb28af9771bf98ec9f793bf77785611337529b3514d7b8061d8ee53e234620a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb39026d5d05f414ddfae9d1087646310fb52c1d5a9b59752472eaa69046e793697165b88153e4a03bb9372c562a331e3db4284b312c0164b810b4508d6f052d
|
7
|
+
data.tar.gz: 6bf3e09ff9a48c98c884f6bb45fe776cf15ca80dd6cac1445889c9a9cbb89d3b1631f9df9c18210a1c100af404e0ffbea000af695a767196a6c99ca0824ee1e4
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
### Added
|
11
|
+
|
12
|
+
- support 3 PV strings in `ReadInput1` and `ReadInput2`
|
13
|
+
- support 3 phase power in `ReadInput1`
|
14
|
+
- support `t_bat` key in `ReadInput2#to_h` (suspect this is Lead Acid only as mine is 0)
|
15
|
+
- support `uptime` key in `ReadInput2#to_h`
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
|
19
|
+
- parsing of temperatures above 255C in ReadInput2
|
20
|
+
|
21
|
+
|
10
22
|
## [0.4.0] - 2020-04-07
|
11
23
|
|
12
24
|
### Added
|
@@ -8,44 +8,68 @@ class LXP
|
|
8
8
|
# Decode the data and return a hash of values in this input packet
|
9
9
|
def to_h
|
10
10
|
{
|
11
|
-
|
11
|
+
# 0 = static 1
|
12
|
+
# 1 = R_INPUT
|
13
|
+
# 2..12 = serial
|
14
|
+
# 13/14 = length
|
12
15
|
|
13
|
-
|
16
|
+
status: Utils.int(@data[15, 2]),
|
17
|
+
|
18
|
+
# 17-22 all observed zeroes (v_pv, v_pv_2, v_pv_3 ?)
|
19
|
+
|
20
|
+
v_bat: Utils.int(@data[23, 2]) / 10.0, # V
|
14
21
|
soc: @data[25], # %
|
22
|
+
# 26 used for anything?
|
23
|
+
|
24
|
+
# observed [0, 47] => 12032 or 0x2F00
|
25
|
+
_unknown_i1_28: @data[28],
|
26
|
+
_unknown_i1_27_28: Utils.int(@data[27, 2]),
|
15
27
|
|
16
|
-
|
28
|
+
p_pv: Utils.int(@data[29, 2]) +
|
29
|
+
Utils.int(@data[31, 2]) +
|
30
|
+
Utils.int(@data[33, 2]), # W
|
31
|
+
p_pv_1: Utils.int(@data[29, 2]), # W
|
32
|
+
p_pv_2: Utils.int(@data[31, 2]), # W
|
33
|
+
p_pv_3: Utils.int(@data[33, 2]), # W
|
34
|
+
p_charge: Utils.int(@data[35, 2]), # W
|
35
|
+
p_discharge: Utils.int(@data[37, 2]), # W
|
36
|
+
v_ac_r: Utils.int(@data[39, 2]) / 10.0, # V
|
37
|
+
v_ac_s: Utils.int(@data[41, 2]) / 10.0, # V
|
38
|
+
v_ac_t: Utils.int(@data[43, 2]) / 10.0, # V
|
39
|
+
f_ac: Utils.int(@data[45, 2]) / 100.0, # Hz
|
17
40
|
|
18
|
-
|
19
|
-
|
20
|
-
p_discharge: Utils.int(@data[37, 2], :lsb), # W
|
21
|
-
v_acr: Utils.int(@data[39, 2], :lsb) / 10.0, # V
|
22
|
-
f_ac: Utils.int(@data[45, 2], :lsb) / 100.0, # Hz
|
41
|
+
p_inv: Utils.int(@data[47, 2]), # W
|
42
|
+
p_rec: Utils.int(@data[49, 2]), # W
|
23
43
|
|
24
|
-
|
25
|
-
p_rec: Utils.int(@data[49, 2], :lsb), # W
|
44
|
+
_unknown_i1_51_52: Utils.int(@data[51, 2]),
|
26
45
|
|
27
|
-
#
|
46
|
+
pf: Utils.int(@data[53, 2]) / 1000.0, # Hz
|
28
47
|
|
29
|
-
|
30
|
-
|
48
|
+
v_eps_r: Utils.int(@data[55, 2]) / 10.0, # V
|
49
|
+
v_eps_s: Utils.int(@data[57, 2]) / 10.0, # V
|
50
|
+
v_eps_t: Utils.int(@data[59, 2]) / 10.0, # V
|
51
|
+
f_eps: Utils.int(@data[61, 2]) / 100.0, # Hz
|
31
52
|
|
32
53
|
# peps and seps in 63..66?
|
33
54
|
|
34
|
-
p_to_grid: Utils.int(@data[67, 2]
|
35
|
-
p_to_user: Utils.int(@data[69, 2]
|
36
|
-
|
37
|
-
e_pv_day: Utils.int(@data[71, 2]
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
55
|
+
p_to_grid: Utils.int(@data[67, 2]), # W
|
56
|
+
p_to_user: Utils.int(@data[69, 2]), # W
|
57
|
+
|
58
|
+
e_pv_day: (Utils.int(@data[71, 2]) +
|
59
|
+
Utils.int(@data[73, 2]) + Utils.int(@data[75, 2])) / 10.0, # kWh
|
60
|
+
e_pv_1_day: Utils.int(@data[71, 2]) / 10.0, # kWh
|
61
|
+
e_pv_2_day: Utils.int(@data[73, 2]) / 10.0, # kWh
|
62
|
+
e_pv_3_day: Utils.int(@data[75, 2]) / 10.0, # kWh
|
63
|
+
e_inv_day: Utils.int(@data[77, 2]) / 10.0, # kWh
|
64
|
+
e_rec_day: Utils.int(@data[79, 2]) / 10.0, # kWh
|
65
|
+
e_chg_day: Utils.int(@data[81, 2]) / 10.0, # kWh
|
66
|
+
e_dischg_day: Utils.int(@data[83, 2]) / 10.0, # kWh
|
67
|
+
e_eps_day: Utils.int(@data[85, 2]) / 10.0, # kWh
|
68
|
+
e_to_grid_day: Utils.int(@data[87, 2]) / 10.0, # kWh
|
69
|
+
e_to_user_day: Utils.int(@data[89, 2]) / 10.0, # kWh
|
70
|
+
|
71
|
+
v_bus_1: Utils.int(@data[91, 2]) / 10.0, # V
|
72
|
+
v_bus_2: Utils.int(@data[93, 2]) / 10.0 # V
|
49
73
|
}
|
50
74
|
end
|
51
75
|
end
|
@@ -8,18 +8,37 @@ class LXP
|
|
8
8
|
# Decode the data and return a hash of values in this input packet
|
9
9
|
def to_h
|
10
10
|
{
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
e_dischg_all: Utils.int(@data[39, 4], :lsb) / 10.0, # kWh
|
16
|
-
e_eps_all: Utils.int(@data[43, 4], :lsb) / 10.0, # kWh
|
17
|
-
e_to_grid_all: Utils.int(@data[47, 4], :lsb) / 10.0, # kWh
|
18
|
-
e_to_user_all: Utils.int(@data[51, 4], :lsb) / 10.0, # kWh
|
11
|
+
# 0 = static 1
|
12
|
+
# 1 = R_INPUT
|
13
|
+
# 2..12 = serial
|
14
|
+
# 13/14 = length
|
19
15
|
|
20
|
-
|
21
|
-
|
22
|
-
|
16
|
+
e_pv_all: (Utils.int(@data[15, 4]) +
|
17
|
+
Utils.int(@data[19, 4]) +
|
18
|
+
Utils.int(@data[23, 4])) / 10.0, # kWh
|
19
|
+
e_pv_1_all: Utils.int(@data[15, 4]) / 10.0, # kWh
|
20
|
+
e_pv_2_all: Utils.int(@data[19, 4]) / 10.0, # kWh
|
21
|
+
e_pv_3_all: Utils.int(@data[23, 4]) / 10.0, # kWh
|
22
|
+
e_inv_all: Utils.int(@data[27, 4]) / 10.0, # kWh
|
23
|
+
e_rec_all: Utils.int(@data[31, 4]) / 10.0, # kWh
|
24
|
+
e_chg_all: Utils.int(@data[35, 4]) / 10.0, # kWh
|
25
|
+
e_dischg_all: Utils.int(@data[39, 4]) / 10.0, # kWh
|
26
|
+
e_eps_all: Utils.int(@data[43, 4]) / 10.0, # kWh
|
27
|
+
e_to_grid_all: Utils.int(@data[47, 4]) / 10.0, # kWh
|
28
|
+
e_to_user_all: Utils.int(@data[51, 4]) / 10.0, # kWh
|
29
|
+
|
30
|
+
# 55 .. 62?
|
31
|
+
# fault code? 4 bytes?
|
32
|
+
# warning code? 4 bytes?
|
33
|
+
|
34
|
+
t_inner: Utils.int(@data[63, 2]),
|
35
|
+
t_rad_1: Utils.int(@data[65, 2]),
|
36
|
+
t_rad_2: Utils.int(@data[67, 2]),
|
37
|
+
t_bat: Utils.int(@data[69, 2]),
|
38
|
+
|
39
|
+
# 71..72 ?
|
40
|
+
|
41
|
+
uptime: Utils.int(@data[73, 4]) # seconds
|
23
42
|
}
|
24
43
|
end
|
25
44
|
end
|
@@ -8,11 +8,20 @@ class LXP
|
|
8
8
|
# Decode the data and return a hash of values in this input packet
|
9
9
|
def to_h
|
10
10
|
{
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
# 0 = static 1
|
12
|
+
# 1 = R_INPUT
|
13
|
+
# 2..12 = serial
|
14
|
+
# 13/14 = length
|
15
15
|
|
16
|
+
# 15..16? .. (observed: 10)
|
17
|
+
|
18
|
+
max_chg_curr: Utils.int(@data[17, 2]) / 100.0, # A
|
19
|
+
max_dischg_curr: Utils.int(@data[19, 2]) / 100.0, # A
|
20
|
+
charge_volt_ref: Utils.int(@data[21, 2]) / 10.0, # V
|
21
|
+
dischg_cut_volt: Utils.int(@data[23, 2]) / 10.0, # V
|
22
|
+
|
23
|
+
# are these actually 2 bytes as well?
|
24
|
+
# never seen data in them so its hard to tell.
|
16
25
|
bat_status_0: @data[25],
|
17
26
|
bat_status_1: @data[27],
|
18
27
|
bat_status_2: @data[29],
|
@@ -24,6 +33,9 @@ class LXP
|
|
24
33
|
bat_status_8: @data[41],
|
25
34
|
bat_status_9: @data[43],
|
26
35
|
bat_status_inv: @data[45]
|
36
|
+
|
37
|
+
# 47/48 = battery count? seen a 6 but unconfirmed it changes
|
38
|
+
# when battery count does.. TODO..
|
27
39
|
}
|
28
40
|
end
|
29
41
|
end
|
data/lib/lxp/utils.rb
CHANGED
@@ -4,16 +4,14 @@ class LXP
|
|
4
4
|
module Utils
|
5
5
|
module_function
|
6
6
|
|
7
|
-
def int(bytes
|
8
|
-
bytes = bytes.reverse if order == :msb
|
9
|
-
|
7
|
+
def int(bytes)
|
10
8
|
bytes.each_with_index.map do |b, idx|
|
11
9
|
b << (idx * 8)
|
12
10
|
end.inject(:|)
|
13
11
|
end
|
14
12
|
|
15
|
-
def int_complement(bytes
|
16
|
-
r = int(bytes
|
13
|
+
def int_complement(bytes)
|
14
|
+
r = int(bytes)
|
17
15
|
r -= 0x10000 if r & 0x8000 == 0x8000
|
18
16
|
r
|
19
17
|
end
|
data/lib/lxp/version.rb
CHANGED
data/spec/parser_spec.rb
CHANGED
@@ -74,7 +74,30 @@ RSpec.describe LXP::Packet::Parser do
|
|
74
74
|
|
75
75
|
describe '#to_h' do
|
76
76
|
subject { packet.to_h }
|
77
|
-
it { is_expected.to eq status: 16, v_bat: 49.7, soc: 95, p_pv: 0, p_charge: 0, p_discharge: 633,
|
77
|
+
it { is_expected.to eq _unknown_i1_28: 47, _unknown_i1_27_28: 12_032, _unknown_i1_51_52: 227, status: 16, v_bat: 49.7, soc: 95, p_pv: 0, p_pv_1: 0, p_pv_2: 0, p_pv_3: 0, p_charge: 0, p_discharge: 633, v_ac_r: 247.6, v_ac_s: 0.1, v_ac_t: 0.0, f_ac: 50.1, p_inv: 569, p_rec: 0, pf: 1.0, v_eps_r: 247.6, v_eps_s: 281.6, v_eps_t: 2875.2, f_eps: 50.1, p_to_grid: 0, p_to_user: 0, e_pv_day: 22.1, e_pv_1_day: 22.1, e_pv_2_day: 0.0, e_pv_3_day: 0.0, e_inv_day: 4.2, e_rec_day: 7.3, e_chg_day: 8.6, e_dischg_day: 5.2, e_eps_day: 0.0, e_to_grid_day: 3.6, e_to_user_day: 0.2, v_bus_1: 375.6, v_bus_2: 299.7 }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'ReadInput2 data' do
|
82
|
+
let(:input) { [161, 26, 2, 0, 111, 0, 1, 194, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 97, 0, 1, 4, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 40, 0, 80, 83, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 38, 0, 0, 43, 45, 0, 0, 105, 51, 0, 0, 44, 47, 0, 0, 0, 0, 0, 0, 95, 5, 0, 0, 63, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 36, 0, 37, 0, 0, 0, 0, 0, 35, 136, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 199] }
|
83
|
+
|
84
|
+
it { is_expected.to be_a LXP::Packet::ReadInput2 }
|
85
|
+
|
86
|
+
it 'has the correct attributes' do
|
87
|
+
expect(packet).to have_attributes register: 40,
|
88
|
+
values: [83, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 38, 0, 0, 43, 45, 0, 0, 105, 51, 0, 0, 44, 47, 0, 0, 0, 0, 0, 0, 95, 5, 0, 0, 63, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 36, 0, 37, 0, 0, 0, 0, 0, 35, 136, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
89
|
+
protocol: 2,
|
90
|
+
packet_length: 111, data_length: 97,
|
91
|
+
tcp_function: LXP::Packet::TcpFunctions::TRANSLATED_DATA,
|
92
|
+
device_function: LXP::Packet::DeviceFunctions::READ_INPUT,
|
93
|
+
inverter_serial: 'XXXXXXXXXX',
|
94
|
+
datalog_serial: 'cccccccccc',
|
95
|
+
bytes: input
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '#to_h' do
|
99
|
+
subject { packet.to_h }
|
100
|
+
it { is_expected.to eq e_chg_all: 1316.1, e_dischg_all: 1207.6, e_eps_all: 0.0, e_inv_all: 990.7, e_pv_all: 1774.7, e_pv_1_all: 1774.7, e_pv_2_all: 0.0, e_pv_3_all: 0.0, e_rec_all: 1156.3, e_to_grid_all: 137.5, e_to_user_all: 1183.9, t_bat: 0, t_inner: 48, t_rad_1: 36, t_rad_2: 37, uptime: 14_714_915 }
|
78
101
|
end
|
79
102
|
end
|
80
103
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lxp-packet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Elsworth
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-04-
|
11
|
+
date: 2020-04-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|