@rhizomatics/signalk-bluetti-plugin 1.4.1 → 1.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +40 -4
  3. package/cli.js +69 -9
  4. package/docs/assets/icon.svg +36 -0
  5. package/docs/assets/screenshots/bluetti_data.png +0 -0
  6. package/docs/examples/model_definition.yaml +112 -0
  7. package/index.js +78 -25
  8. package/lib/path-mapper.js +51 -9
  9. package/lib/register-loader.js +120 -0
  10. package/lib/scanner.js +1 -1
  11. package/package.json +12 -5
  12. package/registers/ac180.yaml +58 -0
  13. package/registers/ac180p.yaml +34 -0
  14. package/registers/ac180t.yaml +58 -0
  15. package/registers/ac200l.yaml +48 -0
  16. package/registers/ac200m.yaml +48 -0
  17. package/registers/ac200p.yaml +89 -0
  18. package/registers/ac200pl.yaml +48 -0
  19. package/registers/ac2a.yaml +34 -0
  20. package/registers/ac2p.yaml +34 -0
  21. package/registers/ac300.yaml +57 -0
  22. package/registers/ac500.yaml +56 -0
  23. package/registers/ac50b.yaml +31 -0
  24. package/registers/ac60.yaml +33 -0
  25. package/registers/ac60p.yaml +33 -0
  26. package/registers/ac70.yaml +62 -0
  27. package/registers/ac70p.yaml +58 -0
  28. package/registers/ap300.yaml +34 -0
  29. package/registers/eb3a.yaml +41 -0
  30. package/registers/el100v2.yaml +43 -0
  31. package/registers/el30v2.yaml +38 -0
  32. package/registers/ep2000.yaml +75 -0
  33. package/registers/ep500.yaml +57 -0
  34. package/registers/ep500p.yaml +57 -0
  35. package/registers/ep600.yaml +151 -0
  36. package/registers/ep760.yaml +72 -0
  37. package/registers/ep800.yaml +21 -0
  38. package/registers/handsfree1.yaml +62 -0
  39. package/registers/pr100v2.yaml +34 -0
  40. package/registers/pr30v2.yaml +34 -0
  41. package/lib/csv-loader.js +0 -160
  42. package/registers/ac200p.csv +0 -47
  43. package/registers/el100v2.csv +0 -27
@@ -0,0 +1,57 @@
1
+ # Bluetti EP500P register map
2
+ # Source: https://github.com/Patrick762/bluetti-bt-lib (bluetti_bt_lib/devices/ep500p.py)
3
+ #
4
+ # field_name is a standard Bluetti register name — the code maps these to
5
+ # SignalK paths on its own (see lib/path-mapper.js). `path` on a field is an
6
+ # override, only needed if you're exposing a register the code doesn't
7
+ # recognise. `constants` are fixed, non-register facts about this model —
8
+ # a bare scalar (string/number) or { value, unit } for one that needs unit
9
+ # conversion (e.g. total_capacity in Wh -> J). No verified nominal capacity
10
+ # is bundled for most models — add a total_capacity constant yourself if you
11
+ # know it, to enable the derived remaining-capacity calculation.
12
+ #
13
+
14
+ fields:
15
+ battery_soc:
16
+ register: 43
17
+ unit: "%"
18
+ dc_input_power:
19
+ register: 36
20
+ unit: W
21
+ ac_input_power:
22
+ register: 37
23
+ unit: W
24
+ ac_output_power:
25
+ register: 38
26
+ unit: W
27
+ dc_output_power:
28
+ register: 39
29
+ unit: W
30
+ ac_output_voltage:
31
+ register: 71
32
+ scale: 0.1
33
+ unit: V
34
+ ac_output_frequency:
35
+ register: 74
36
+ scale: 0.01
37
+ unit: Hz
38
+ ac_input_voltage:
39
+ register: 77
40
+ scale: 0.1
41
+ unit: V
42
+ ac_input_frequency:
43
+ register: 80
44
+ scale: 0.01
45
+ unit: Hz
46
+ dc_input_voltage:
47
+ register: 86
48
+ scale: 0.1
49
+ unit: V
50
+ dc_input_current:
51
+ register: 88
52
+ scale: 0.1
53
+ unit: A
54
+ constants:
55
+ battery_chemistry: LiFePO4
56
+ battery_manufacturer_name: Bluetti
57
+ battery_manufacturer_model: EP500P
@@ -0,0 +1,151 @@
1
+ # Bluetti EP600 register map
2
+ # Source: https://github.com/Patrick762/bluetti-bt-lib (bluetti_bt_lib/devices/ep600.py)
3
+ #
4
+ # field_name is a standard Bluetti register name — the code maps these to
5
+ # SignalK paths on its own (see lib/path-mapper.js). `path` on a field is an
6
+ # override, only needed if you're exposing a register the code doesn't
7
+ # recognise. `constants` are fixed, non-register facts about this model —
8
+ # a bare scalar (string/number) or { value, unit } for one that needs unit
9
+ # conversion (e.g. total_capacity in Wh -> J). No verified nominal capacity
10
+ # is bundled for most models — add a total_capacity constant yourself if you
11
+ # know it, to enable the derived remaining-capacity calculation.
12
+ #
13
+
14
+ fields:
15
+ battery_soc:
16
+ register: 102
17
+ unit: "%"
18
+ power_generation:
19
+ register: 1202
20
+ scale: 0.1
21
+ unit: kWh
22
+ dc_input_power:
23
+ register: 1212
24
+ unit: W
25
+ dc_input_voltage:
26
+ register: 1213
27
+ scale: 0.1
28
+ unit: V
29
+ dc_input_current:
30
+ register: 1214
31
+ scale: 0.1
32
+ unit: A
33
+ pv_s2_power:
34
+ register: 1220
35
+ unit: W
36
+ pv_s2_voltage:
37
+ register: 1221
38
+ scale: 0.1
39
+ unit: V
40
+ pv_s2_current:
41
+ register: 1222
42
+ scale: 0.1
43
+ unit: A
44
+ sm_p1_power:
45
+ register: 1228
46
+ unit: W
47
+ sm_p1_voltage:
48
+ register: 1229
49
+ scale: 0.1
50
+ unit: V
51
+ sm_p1_current:
52
+ register: 1230
53
+ unit: A
54
+ sm_p2_power:
55
+ register: 1236
56
+ unit: W
57
+ sm_p2_voltage:
58
+ register: 1237
59
+ scale: 0.1
60
+ unit: V
61
+ sm_p2_current:
62
+ register: 1238
63
+ unit: A
64
+ sm_p3_power:
65
+ register: 1244
66
+ unit: W
67
+ sm_p3_voltage:
68
+ register: 1245
69
+ scale: 0.1
70
+ unit: V
71
+ sm_p3_current:
72
+ register: 1246
73
+ unit: A
74
+ grid_frequency:
75
+ register: 1300
76
+ scale: 0.1
77
+ unit: Hz
78
+ grid_p1_power:
79
+ register: 1313
80
+ unit: W
81
+ grid_p1_voltage:
82
+ register: 1314
83
+ scale: 0.1
84
+ unit: V
85
+ grid_p1_current:
86
+ register: 1315
87
+ scale: 0.1
88
+ unit: A
89
+ grid_p2_power:
90
+ register: 1319
91
+ unit: W
92
+ grid_p2_voltage:
93
+ register: 1320
94
+ scale: 0.1
95
+ unit: V
96
+ grid_p2_current:
97
+ register: 1321
98
+ scale: 0.1
99
+ unit: A
100
+ grid_p3_power:
101
+ register: 1325
102
+ unit: W
103
+ grid_p3_voltage:
104
+ register: 1326
105
+ scale: 0.1
106
+ unit: V
107
+ grid_p3_current:
108
+ register: 1327
109
+ scale: 0.1
110
+ unit: A
111
+ ac_output_frequency:
112
+ register: 1500
113
+ scale: 0.1
114
+ unit: Hz
115
+ ac_p1_power:
116
+ register: 1510
117
+ unit: W
118
+ ac_p1_voltage:
119
+ register: 1511
120
+ scale: 0.1
121
+ unit: V
122
+ ac_p1_current:
123
+ register: 1512
124
+ scale: 0.1
125
+ unit: A
126
+ ac_p2_power:
127
+ register: 1517
128
+ unit: W
129
+ ac_p2_voltage:
130
+ register: 1518
131
+ scale: 0.1
132
+ unit: V
133
+ ac_p2_current:
134
+ register: 1519
135
+ scale: 0.1
136
+ unit: A
137
+ ac_p3_power:
138
+ register: 1524
139
+ unit: W
140
+ ac_p3_voltage:
141
+ register: 1525
142
+ scale: 0.1
143
+ unit: V
144
+ ac_p3_current:
145
+ register: 1526
146
+ scale: 0.1
147
+ unit: A
148
+ constants:
149
+ battery_chemistry: LiFePO4
150
+ battery_manufacturer_name: Bluetti
151
+ battery_manufacturer_model: EP600
@@ -0,0 +1,72 @@
1
+ # Bluetti EP760 register map
2
+ # Source: https://github.com/Patrick762/bluetti-bt-lib (bluetti_bt_lib/devices/ep760.py)
3
+ #
4
+ # field_name is a standard Bluetti register name — the code maps these to
5
+ # SignalK paths on its own (see lib/path-mapper.js). `path` on a field is an
6
+ # override, only needed if you're exposing a register the code doesn't
7
+ # recognise. `constants` are fixed, non-register facts about this model —
8
+ # a bare scalar (string/number) or { value, unit } for one that needs unit
9
+ # conversion (e.g. total_capacity in Wh -> J). No verified nominal capacity
10
+ # is bundled for most models — add a total_capacity constant yourself if you
11
+ # know it, to enable the derived remaining-capacity calculation.
12
+ #
13
+
14
+ fields:
15
+ battery_soc:
16
+ register: 102
17
+ unit: "%"
18
+ dc_input_power:
19
+ register: 1212
20
+ unit: W
21
+ dc_input_voltage:
22
+ register: 1213
23
+ scale: 0.1
24
+ unit: V
25
+ dc_input_current:
26
+ register: 1214
27
+ scale: 0.1
28
+ unit: A
29
+ sm_p1_power:
30
+ register: 1228
31
+ unit: W
32
+ sm_p1_voltage:
33
+ register: 1229
34
+ scale: 0.1
35
+ unit: V
36
+ sm_p1_current:
37
+ register: 1230
38
+ unit: A
39
+ ac_input_frequency:
40
+ register: 1300
41
+ scale: 0.1
42
+ unit: Hz
43
+ ac_input_power:
44
+ register: 1313
45
+ unit: W
46
+ ac_input_voltage:
47
+ register: 1314
48
+ scale: 0.1
49
+ unit: V
50
+ ac_input_current:
51
+ register: 1315
52
+ scale: 0.1
53
+ unit: A
54
+ ac_output_frequency:
55
+ register: 1500
56
+ scale: 0.1
57
+ unit: Hz
58
+ ac_output_power:
59
+ register: 1510
60
+ unit: W
61
+ ac_output_voltage:
62
+ register: 1511
63
+ scale: 0.1
64
+ unit: V
65
+ ac_output_current:
66
+ register: 1512
67
+ scale: 0.1
68
+ unit: A
69
+ constants:
70
+ battery_chemistry: LiFePO4
71
+ battery_manufacturer_name: Bluetti
72
+ battery_manufacturer_model: EP760
@@ -0,0 +1,21 @@
1
+ # Bluetti EP800 register map
2
+ # Source: https://github.com/Patrick762/bluetti-bt-lib (bluetti_bt_lib/devices/ep800.py)
3
+ #
4
+ # field_name is a standard Bluetti register name — the code maps these to
5
+ # SignalK paths on its own (see lib/path-mapper.js). `path` on a field is an
6
+ # override, only needed if you're exposing a register the code doesn't
7
+ # recognise. `constants` are fixed, non-register facts about this model —
8
+ # a bare scalar (string/number) or { value, unit } for one that needs unit
9
+ # conversion (e.g. total_capacity in Wh -> J). No verified nominal capacity
10
+ # is bundled for most models — add a total_capacity constant yourself if you
11
+ # know it, to enable the derived remaining-capacity calculation.
12
+ #
13
+
14
+ fields:
15
+ battery_soc:
16
+ register: 102
17
+ unit: "%"
18
+ constants:
19
+ battery_chemistry: LiFePO4
20
+ battery_manufacturer_name: Bluetti
21
+ battery_manufacturer_model: EP800
@@ -0,0 +1,62 @@
1
+ # Bluetti HANDSFREE1 register map
2
+ # Source: https://github.com/Patrick762/bluetti-bt-lib (bluetti_bt_lib/devices/handsfree1.py)
3
+ #
4
+ # field_name is a standard Bluetti register name — the code maps these to
5
+ # SignalK paths on its own (see lib/path-mapper.js). `path` on a field is an
6
+ # override, only needed if you're exposing a register the code doesn't
7
+ # recognise. `constants` are fixed, non-register facts about this model —
8
+ # a bare scalar (string/number) or { value, unit } for one that needs unit
9
+ # conversion (e.g. total_capacity in Wh -> J). No verified nominal capacity
10
+ # is bundled for most models — add a total_capacity constant yourself if you
11
+ # know it, to enable the derived remaining-capacity calculation.
12
+ #
13
+
14
+ fields:
15
+ dc_output_power:
16
+ register: 140
17
+ unit: W
18
+ ac_output_power:
19
+ register: 142
20
+ unit: W
21
+ dc_input_power:
22
+ register: 144
23
+ unit: W
24
+ ac_input_power:
25
+ register: 146
26
+ unit: W
27
+ time_remaining_minutes:
28
+ register: 104
29
+ scale: 6
30
+ unit: min
31
+ dc_input_voltage:
32
+ register: 1213
33
+ scale: 0.1
34
+ unit: V
35
+ dc_input_current:
36
+ register: 1214
37
+ scale: 0.1
38
+ unit: A
39
+ ac_input_frequency:
40
+ register: 1300
41
+ scale: 0.1
42
+ unit: Hz
43
+ ac_input_voltage:
44
+ register: 1314
45
+ scale: 0.1
46
+ unit: V
47
+ ac_input_current:
48
+ register: 1315
49
+ scale: 0.1
50
+ unit: A
51
+ ac_output_frequency:
52
+ register: 1500
53
+ scale: 0.1
54
+ unit: Hz
55
+ ac_output_voltage:
56
+ register: 1511
57
+ scale: 0.1
58
+ unit: V
59
+ constants:
60
+ battery_chemistry: LiFePO4
61
+ battery_manufacturer_name: Bluetti
62
+ battery_manufacturer_model: Handsfree 1
@@ -0,0 +1,34 @@
1
+ # Bluetti PR100V2 register map
2
+ # Source: https://github.com/Patrick762/bluetti-bt-lib (bluetti_bt_lib/devices/pr100v2.py)
3
+ #
4
+ # field_name is a standard Bluetti register name — the code maps these to
5
+ # SignalK paths on its own (see lib/path-mapper.js). `path` on a field is an
6
+ # override, only needed if you're exposing a register the code doesn't
7
+ # recognise. `constants` are fixed, non-register facts about this model —
8
+ # a bare scalar (string/number) or { value, unit } for one that needs unit
9
+ # conversion (e.g. total_capacity in Wh -> J). No verified nominal capacity
10
+ # is bundled for most models — add a total_capacity constant yourself if you
11
+ # know it, to enable the derived remaining-capacity calculation.
12
+ #
13
+
14
+ fields:
15
+ dc_output_power:
16
+ register: 140
17
+ unit: W
18
+ ac_output_power:
19
+ register: 142
20
+ unit: W
21
+ dc_input_power:
22
+ register: 144
23
+ unit: W
24
+ ac_input_power:
25
+ register: 146
26
+ unit: W
27
+ ac_input_voltage:
28
+ register: 1314
29
+ scale: 0.1
30
+ unit: V
31
+ constants:
32
+ battery_chemistry: LiFePO4
33
+ battery_manufacturer_name: Bluetti
34
+ battery_manufacturer_model: PR100 V2
@@ -0,0 +1,34 @@
1
+ # Bluetti PR30V2 register map
2
+ # Source: https://github.com/Patrick762/bluetti-bt-lib (bluetti_bt_lib/devices/pr30v2.py)
3
+ #
4
+ # field_name is a standard Bluetti register name — the code maps these to
5
+ # SignalK paths on its own (see lib/path-mapper.js). `path` on a field is an
6
+ # override, only needed if you're exposing a register the code doesn't
7
+ # recognise. `constants` are fixed, non-register facts about this model —
8
+ # a bare scalar (string/number) or { value, unit } for one that needs unit
9
+ # conversion (e.g. total_capacity in Wh -> J). No verified nominal capacity
10
+ # is bundled for most models — add a total_capacity constant yourself if you
11
+ # know it, to enable the derived remaining-capacity calculation.
12
+ #
13
+
14
+ fields:
15
+ dc_output_power:
16
+ register: 140
17
+ unit: W
18
+ ac_output_power:
19
+ register: 142
20
+ unit: W
21
+ dc_input_power:
22
+ register: 144
23
+ unit: W
24
+ ac_input_power:
25
+ register: 146
26
+ unit: W
27
+ ac_input_voltage:
28
+ register: 1314
29
+ scale: 0.1
30
+ unit: V
31
+ constants:
32
+ battery_chemistry: LiFePO4
33
+ battery_manufacturer_name: Bluetti
34
+ battery_manufacturer_model: PR30 V2
package/lib/csv-loader.js DELETED
@@ -1,160 +0,0 @@
1
- "use strict";
2
-
3
- const fs = require("fs");
4
- const { parse } = require("csv-parse/sync");
5
-
6
- // Column name aliases — Bluetti CSVs have been seen in English and Chinese headers.
7
- // Maps our internal key → list of possible header strings (case-insensitive match).
8
- const COL_ALIASES = {
9
- field_name: ["field_name", "fieldname", "name", "字段名", "field"],
10
- register_address: ["register_address", "register", "address", "addr", "reg", "no", "no.", "寄存器", "地址"],
11
- data_type: ["data_type", "datatype", "type", "数据type", "数据类型"],
12
- scale: ["scale", "倍率", "factor", "multiplier"],
13
- offset: ["offset", "偏移"],
14
- unit: ["unit", "units", "单位"],
15
- signalk_path: ["signalk_path", "signalk", "sk_path", "path"],
16
- register_count: ["register_count", "count", "length", "bytes", "数据长度"],
17
- constant_value: ["constant_value", "constant", "const", "fixed_value", "static_value"],
18
- };
19
-
20
- function resolveColumn(headers, key) {
21
- const aliases = COL_ALIASES[key];
22
- for (const alias of aliases) {
23
- const found = headers.find((h) => h.trim().toLowerCase() === alias.toLowerCase());
24
- if (found) return found;
25
- }
26
- return null;
27
- }
28
-
29
- // Parse the CSV and return an array of field descriptors.
30
- // Each descriptor is either register-backed: { fieldName, register, count, dataType, scale, offset, unit, signalkPath }
31
- // or a fixed constant (register_address left blank): { fieldName, register: null, count: 0, dataType: "const", ..., constantValue }
32
- function loadCsv(filePath) {
33
- const raw = fs.readFileSync(filePath, "utf8");
34
-
35
- // Strip BOM if present
36
- const content = raw.charCodeAt(0) === 0xfeff ? raw.slice(1) : raw;
37
-
38
- const records = parse(content, {
39
- columns: true,
40
- skip_empty_lines: true,
41
- trim: true,
42
- comment: "#",
43
- relax_column_count: true,
44
- });
45
-
46
- if (records.length === 0) throw new Error(`CSV file ${filePath} has no data rows`);
47
-
48
- const headers = Object.keys(records[0]);
49
-
50
- const col = {};
51
- for (const key of Object.keys(COL_ALIASES)) {
52
- col[key] = resolveColumn(headers, key);
53
- }
54
-
55
- if (!col.register_address) throw new Error("CSV must have a register address column");
56
- if (!col.field_name) throw new Error("CSV must have a field name column");
57
-
58
- const fields = [];
59
- for (const row of records) {
60
- const fieldName = (row[col.field_name] || "").trim();
61
- if (!fieldName) continue;
62
-
63
- const signalkPath = col.signalk_path ? (row[col.signalk_path] || "").trim() : "";
64
- const constantRaw = col.constant_value ? (row[col.constant_value] || "").trim() : "";
65
-
66
- const registerRaw = row[col.register_address];
67
- const register = parseInt(registerRaw, 10);
68
-
69
- if (isNaN(register)) {
70
- // No register address — only valid if this row instead supplies a fixed
71
- // constant (e.g. a model's nominal battery capacity or chemistry, which
72
- // isn't a live register on every device). Otherwise it's a header-like
73
- // row embedded in the data and gets skipped.
74
- if (!constantRaw) continue;
75
- // Numeric constants (e.g. a nominal capacity in Wh) need to go through
76
- // the same unit conversion as register-backed fields; text constants
77
- // (chemistry, manufacturer name) are left as-is.
78
- const asNumber = Number(constantRaw);
79
- const constantValue = Number.isNaN(asNumber) ? constantRaw : asNumber;
80
- const unit = col.unit ? (row[col.unit] || "").trim() : "";
81
- fields.push({ fieldName, register: null, count: 0, dataType: "const", scale: 1, offset: 0, unit, signalkPath, constantValue });
82
- continue;
83
- }
84
-
85
- const dataType = col.data_type ? (row[col.data_type] || "uint16").toLowerCase().trim() : "uint16";
86
- const scale = col.scale ? parseFloat(row[col.scale]) || 1 : 1;
87
- const offset = col.offset ? parseFloat(row[col.offset]) || 0 : 0;
88
- const unit = col.unit ? (row[col.unit] || "").trim() : "";
89
-
90
- // register_count: for multi-register types (int32, uint32, float32 = 2 regs; int64 = 4 regs)
91
- let count = col.register_count ? parseInt(row[col.register_count], 10) : NaN;
92
- if (isNaN(count)) count = registersForType(dataType);
93
-
94
- fields.push({ fieldName, register, count, dataType, scale, offset, unit, signalkPath });
95
- }
96
-
97
- if (fields.length === 0) throw new Error(`No valid register rows found in ${filePath}`);
98
- return fields;
99
- }
100
-
101
- function registersForType(dataType) {
102
- switch (dataType) {
103
- case "int32":
104
- case "uint32":
105
- case "float32":
106
- return 2;
107
- case "int64":
108
- case "uint64":
109
- return 4;
110
- default:
111
- return 1; // uint16, int16, bool, enum
112
- }
113
- }
114
-
115
- // Decode a raw register value (or pair of registers for 32-bit types) into a number.
116
- // rawRegs: Map<addr, uint16>, startAddr: the register address for this field
117
- function decodeValue(field, rawRegs) {
118
- const { register, count, dataType, scale, offset } = field;
119
-
120
- if (dataType === "const") return field.constantValue;
121
-
122
- let raw;
123
- if (count === 1) {
124
- raw = rawRegs.get(register);
125
- if (raw === undefined) return null;
126
- } else if (count === 2) {
127
- const hi = rawRegs.get(register);
128
- const lo = rawRegs.get(register + 1);
129
- if (hi === undefined || lo === undefined) return null;
130
- raw = (hi << 16) | lo;
131
- } else {
132
- return null;
133
- }
134
-
135
- let value;
136
- switch (dataType) {
137
- case "int16":
138
- value = raw > 0x7fff ? raw - 0x10000 : raw;
139
- break;
140
- case "int32": {
141
- const signed = raw > 0x7fffffff ? raw - 0x100000000 : raw;
142
- value = signed;
143
- break;
144
- }
145
- case "float32": {
146
- const tmpBuf = Buffer.alloc(4);
147
- tmpBuf.writeUInt32BE(raw, 0);
148
- value = tmpBuf.readFloatBE(0);
149
- break;
150
- }
151
- case "bool":
152
- return raw !== 0 ? 1 : 0;
153
- default:
154
- value = raw;
155
- }
156
-
157
- return value * scale + offset;
158
- }
159
-
160
- module.exports = { loadCsv, decodeValue };
@@ -1,47 +0,0 @@
1
- # Bluetti register map example — based on AC200P / AC200MAX community reverse-engineering.
2
- # Replace with your device's actual CSV. Columns the plugin recognises:
3
- #
4
- # field_name — a standard Bluetti register name (see lib/path-mapper.js
5
- # for the ones the code already maps to a SignalK path),
6
- # or any identifier you like if you're supplying signalk_path
7
- # register_address — Modbus holding register number (decimal); leave blank
8
- # for a fixed constant_value row instead (e.g. model specs)
9
- # register_count — number of 16-bit registers this field spans (1 for uint16/int16, 2 for int32/float32)
10
- # data_type — uint16 | int16 | uint32 | int32 | float32 | bool
11
- # scale — multiply raw value by this to get physical value
12
- # offset — add after scale (usually 0)
13
- # unit — V | A | W | Wh | % | °C | Hz | min — drives SignalK unit conversion
14
- # signalk_path — override; only needed for a register the code doesn't
15
- # recognise by field_name. Use {name} where the device name goes
16
- # constant_value — fixed value for a non-register row (register_address blank)
17
- #
18
- field_name,register_address,register_count,data_type,scale,offset,unit,signalk_path,constant_value
19
- # ── Battery ────────────────────────────────────────────────────────────────
20
- battery_percent,100,1,uint16,1,0,%,,
21
- battery_voltage,101,1,uint16,0.1,0,V,,
22
- battery_current,102,1,int16,0.1,0,A,,
23
- battery_power,103,1,int16,1,0,W,,
24
- battery_temperature,104,1,uint16,0.1,0,°C,,
25
- # ── DC / Solar input ────────────────────────────────────────────────────────
26
- dc_input_power,107,1,uint16,1,0,W,,
27
- dc_input_voltage,108,1,uint16,0.1,0,V,,
28
- dc_input_current,109,1,uint16,0.1,0,A,,
29
- # ── AC output (inverter) ────────────────────────────────────────────────────
30
- ac_output_power,110,1,uint16,1,0,W,,
31
- ac_output_voltage,111,1,uint16,0.1,0,V,,
32
- ac_output_current,112,1,uint16,0.1,0,A,,
33
- ac_output_frequency,113,1,uint16,0.1,0,Hz,,
34
- # ── AC input (charger / mains) ──────────────────────────────────────────────
35
- ac_input_power,114,1,uint16,1,0,W,,
36
- ac_input_voltage,115,1,uint16,0.1,0,V,,
37
- ac_input_current,116,1,uint16,0.1,0,A,,
38
- ac_input_frequency,117,1,uint16,0.1,0,Hz,,
39
- # ── Internal temperature ────────────────────────────────────────────────────
40
- internal_temperature,118,1,uint16,0.1,0,°C,,
41
- # ── Estimated time remaining ────────────────────────────────────────────────
42
- time_remaining_minutes,119,1,uint16,1,0,min,,
43
- # ── Fixed model facts ────────────────────────────────────────────────────────
44
- battery_chemistry,,,,,,,,LiFePO4
45
- total_capacity,,,,,,Wh,,2000
46
- battery_manufacturer_name,,,,,,,,Bluetti
47
- battery_manufacturer_model,,,,,,,,AC200P
@@ -1,27 +0,0 @@
1
- # Bluetti Elite 100 V2 (EL100V2) register map
2
- # Source: https://github.com/Patrick762/bluetti-bt-lib
3
- # BaseDeviceV2 fields: BATTERY_SOC (102)
4
- # EL100V2-specific fields: 140, 142, 144, 146, 1314
5
- # Note: DEVICE_TYPE (110) and DEVICE_SN (116) are string/serial fields — omitted.
6
- #
7
- # field_name is a standard Bluetti register name — the code maps these to
8
- # SignalK paths on its own (see lib/path-mapper.js). signalk_path is an
9
- # override, only needed if you're exposing a register the code doesn't
10
- # recognise. constant_value is for fixed, non-register facts about this model
11
- # (register_address left blank for those rows).
12
- #
13
- field_name,register_address,register_count,data_type,scale,offset,unit,signalk_path,constant_value
14
- battery_soc,102,1,uint16,1,0,%,,
15
- dc_output_power,140,1,uint16,1,0,W,,
16
- ac_output_power,142,1,uint16,1,0,W,,
17
- dc_input_power,144,1,uint16,1,0,W,,
18
- ac_input_power,146,1,uint16,1,0,W,,
19
- ac_input_voltage,1314,1,uint16,0.1,0,V,,
20
- # ── Fixed model facts ────────────────────────────────────────────────────────
21
- battery_chemistry,,,,,,,,LiFePO4
22
- total_capacity,,,,,,Wh,,1024
23
- battery_manufacturer_name,,,,,,,,Bluetti
24
- battery_manufacturer_model,,,,,,,,Elite 100 V2
25
- # dc_output_power (140) only reports power, not current — this fixed nominal
26
- # voltage (12V accessory port) is what lib/path-mapper.js derives current from.
27
- dc_output_voltage,,,,,,V,,12