bt-sensors-plugin-sk 1.0.3 → 1.1.0-beta.2

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.
@@ -0,0 +1,105 @@
1
+ const BTSensor = require("../../BTSensor.js");
2
+ const crypto = require('node:crypto');
3
+ const int24 = require('int24')
4
+ const util = require('util')
5
+ const VC = require('./VictronConstants.js')
6
+
7
+ class VictronSensor extends BTSensor{
8
+
9
+ constructor(device,config,gattConfig){
10
+ super(device,config,gattConfig)
11
+ this.encryptionKey = config?.encryptionKey
12
+ }
13
+
14
+ static async identifyMode(device, mode){
15
+
16
+ try{
17
+ const md = await this.getDeviceProp(device,'ManufacturerData')
18
+ if (!md) return null
19
+ const data = md[0x2e1]
20
+ if (data && data.value[0]==0x10 && data.value[4]==mode)
21
+ return this
22
+ else
23
+ return null
24
+ } catch (e){
25
+ console.log(e)
26
+ return null
27
+ }
28
+
29
+ }
30
+
31
+ getAuxModeAndCurrent(offset, decData=null){
32
+ if (decData==null){
33
+ decData=this.getManufacturerData(0x2e1)
34
+ if (this.encryptionKey)
35
+ decData=this.decrypt(decData)
36
+ else
37
+ return {current:NaN, auxMode:NaN}
38
+ }
39
+ const auxModeAndCurrent = int24.readInt24LE(decData,offset)
40
+ return {
41
+ current : (this.NaNif(auxModeAndCurrent >> 2,0x3FFFFF))/1000,
42
+ auxMode : auxModeAndCurrent & 0b11
43
+ }
44
+ }
45
+
46
+ async init(){
47
+ await super.init()
48
+ var md = this.addMetadatum('encryptionKey','', "Encryption Key")
49
+ md.isParam = true
50
+ this.metadata = new Map(super.getMetadata())
51
+ md = this.addMetadatum('encryptionKey','', "Encryption Key")
52
+ md.isParam = true
53
+ this.model_id=this.getManufacturerData(0x2e1).readUInt16LE(2)
54
+ }
55
+ alarmReason(alarmValue){
56
+ return this.constructor.AlarmReason[alarmValue]
57
+ }
58
+ getModelName(){
59
+ return VC.MODEL_ID_MAP[this.model_id]
60
+ }
61
+
62
+ decrypt(data){
63
+ if (!this.encryptionKey)
64
+ throw Error("Unable to decrypt: no encryption key set")
65
+
66
+ const encMethod = 'aes-128-ctr';
67
+ const iv = data.readUInt16LE(5);
68
+ const key = Buffer.from(this.encryptionKey,'hex')
69
+ const ivBuffer = Buffer.alloc(16); // 128 bits = 16 bytes
70
+
71
+ ivBuffer.writeUInt16LE(iv)
72
+
73
+ var encData = Buffer.from([...data.slice(8)])
74
+
75
+ const decipher = crypto.createDecipheriv(encMethod, key, ivBuffer)
76
+
77
+ const decData=decipher.update(encData)
78
+
79
+ return Buffer.from(decData)
80
+
81
+ }
82
+ getName(){
83
+ return `Victron ${this.getModelName()}`
84
+ }
85
+ propertiesChanged(props){
86
+ super.propertiesChanged(props)
87
+ if (this.usingGATT()) return
88
+ try{
89
+ const buff = this.getManufacturerData(0x2e1)
90
+ const decData=this.decrypt(buff)
91
+ this.emitValuesFrom(decData)
92
+ }
93
+ catch (error) {
94
+ throw new Error(`Unable to read data from ${ this.getDisplayName()}: ${error}` )
95
+ }
96
+ }
97
+
98
+ initGATT(){
99
+ throw new Error( "GATT Connection unimplemented for "+this.getDisplayName())
100
+ }
101
+
102
+
103
+
104
+ }
105
+ module.exports=VictronSensor
@@ -0,0 +1,63 @@
1
+ /*AC Charger
2
+ Record layout is still to be determined and might change.
3
+ Last update: 2022/12/14 13:25 rend:ble:extra_manufacturer_data https://wiki.victronenergy.com/rend/ble/extra_manufacturer_data
4
+ https://wiki.victronenergy.com/ Printed on 2022/12/14 13:27
5
+ Startbit Nr of bits Meaning Units Range NA value Remark
6
+ 32 8 Device state 0 .. 0xFE 0xFF VE_REG_DEVICE_STATE
7
+ 40 8 Charger Error 0 .. 0xFE 0xFF VE_REG_CHR_ERROR_CODE
8
+ 48 13 Battery voltage 1 0.01 V 0 .. 81.90V 0x1FFF VE_REG_DC_CHANNEL1_VOLTAGE
9
+ 61 11 Battery current 1 0.1A 0 .. 204.6A 0x7FF VE_REG_DC_CHANNEL1_CURRENT
10
+ 72 13 Battery voltage 2 0.01 V 0 .. 81.90V 0x1FFF VE_REG_DC_CHANNEL2_VOLTAGE
11
+ 85 11 Battery current 2 0.1A 0 .. 204.6A 0x7FF VE_REG_DC_CHANNEL2_CURRENT
12
+ 96 13 Battery voltage 3 0.01 V 0 .. 81.90V 0x1FFF VE_REG_DC_CHANNEL3_VOLTAGE
13
+ 109 11 Battery current 3 0.1A 0 .. 204.6A 0x7FF VE_REG_DC_CHANNEL3_CURRENT
14
+ 120 7 Temperature °C -40 .. 86°C 0x7F VE_REG_BAT_TEMPERATURE Temperature = Record value - 40
15
+ 127 9 AC current 0.1A 0 .. 51.0 A 0x1FF VE_REG_AC_ACTIVE_INPUT_L1_CURRENT
16
+ 136 24 Unused
17
+ */
18
+
19
+
20
+
21
+ const VictronSensor = require ("./Victron/VictronSensor.js")
22
+ const VC = require("./Victron/VictronConstants.js")
23
+ const int24 = require('int24')
24
+
25
+ class VictronACCharger extends VictronSensor{
26
+
27
+ static async identify(device){
28
+ return await this.identifyMode(device, 0x0A)
29
+ }
30
+
31
+ async init(){
32
+ await super.init()
33
+ this.addMetadatum('state','', 'device state',
34
+ (buff)=>{return VC.OperationMode.get(buff.readUInt8(0))})
35
+ this.addMetadatum('error','', 'error code',
36
+ (buff)=>{return VC.ChargerError.get(buff.readUInt8(1))})
37
+
38
+ this.addMetadatum('batt1','V', 'battery 1 voltage',
39
+ (buff)=>{return this.NaNif((buff.readUInt16BE(2)>>3), 0x1FFF)/100})
40
+
41
+ this.addMetadatum('curr1','A', 'battery 1 current',
42
+ (buff)=>{return this.NaNif(buff.readUInt16BE(3)&0x7FF,0x7FF)/10})
43
+
44
+ this.addMetadatum('batt2','V', 'battery 2 voltage',
45
+ (buff)=>{return this.NaNif((buff.readUInt16BE(5)>>3), 0x1FFF)/100})
46
+
47
+ this.addMetadatum('curr2','A', 'battery 2 current',
48
+ (buff)=>{return this.NaNif(buff.readUInt16BE(7)&0x7FF,0x7FF)/10})
49
+
50
+ this.addMetadatum('batt3','V', 'battery 3 voltage',
51
+ (buff)=>{return this.NaNif((buff.readUInt16BE(8)>>3), 0x1FFF)/100})
52
+
53
+ this.addMetadatum('curr3','A', 'battery 3 current',
54
+ (buff)=>{return this.NaNif(buff.readUInt16BE(9)&0x7FF,0x7FF)/10})
55
+
56
+ this.addMetadatum('temp', 'K', 'battery temperature',
57
+ (buff)=>{return this.NaNif(buff.readUInt8(11)>>1,0x7F)+233.15}) //-40 plus K conversion
58
+
59
+ this.addMetadatum('acCurr','A', 'AC current',
60
+ (buff)=>{return this.NaNif((buff.readInt16BE(11))&0x1FFF,0x1FFF)})
61
+ }
62
+ }
63
+ module.exports=VictronACCharger
@@ -0,0 +1,158 @@
1
+ const VictronSensor = require("./Victron/VictronSensor.js");
2
+ const VC=require("./Victron/VictronConstants.js")
3
+ class VictronBatteryMonitor extends VictronSensor{
4
+
5
+
6
+ static async identify(device){
7
+ return await this.identifyMode(device, 0x02)
8
+ }
9
+
10
+ characteristics=[]
11
+ async init(){
12
+ await super.init()
13
+ this.addMetadatum('current', 'A', 'house battery amperage',
14
+ (buff,offset=0)=>{return buff.readInt32LE(offset)/1000},
15
+ '6597ed8c-4bda-4c1e-af4b-551c4cf74769')
16
+ this.addMetadatum('power','W', 'house battery wattage',
17
+ (buff,offset=0)=>{return buff.readInt16LE(offset)},
18
+ '6597ed8e-4bda-4c1e-af4b-551c4cf74769')
19
+ this.addMetadatum('voltage','V', 'house battery voltage',
20
+ (buff,offset=0)=>{return this.NaNif(buff.readInt16LE(offset), 0x7FFF)/100},
21
+ '6597ed8d-4bda-4c1e-af4b-551c4cf74769',)
22
+ const alarmMD = this.addMetadatum('alarm','', 'alarm',
23
+ (buff,offset=0)=>{return buff.readInt16LE(offset)})
24
+ alarmMD.notify=true
25
+
26
+ this.addMetadatum( 'consumed','C', 'amp-hours consumed',
27
+ (buff,offset=0)=>{return buff.readInt32LE(offset)/10},
28
+ '6597eeff-4bda-4c1e-af4b-551c4cf74769',)
29
+
30
+ this.addMetadatum( 'soc','ratio', 'state of charge',
31
+ (buff,offset=0)=>{return buff.readUInt16LE(offset)/10000},
32
+ '65970fff-4bda-4c1e-af4b-551c4cf74769')
33
+
34
+ this.addMetadatum( 'ttg','s','time to go',
35
+ (buff,offset=0)=>{return this.NaNif(buff.readUInt16LE(offset),0xFFFF)*60},
36
+ '65970ffe-4bda-4c1e-af4b-551c4cf74769')
37
+ const modecurrent = this.getAuxModeAndCurrent()
38
+ this.auxMode= modecurrent.auxMode
39
+ switch(this.auxMode){
40
+ case VC.AuxMode.STARTER_VOLTAGE:
41
+ this.addMetadatum('starterVoltage','V', 'starter battery voltage',
42
+ (buff,offset=0)=>{return buff.readInt16LE(offset)/100},
43
+ '6597ed7d-4bda-4c1e-af4b-551c4cf74769')
44
+ break;
45
+ case VC.AuxMode.MIDPOINT_VOLTAGE:
46
+ this.addMetadatum('midpointVoltage','V', 'midpoint battery voltage',
47
+ (buff,offset=0)=>{return buff.readInt16LE(offset)/100},
48
+ '6597ed7d-4bda-4c1e-af4b-551c4cf74769')
49
+ break;
50
+
51
+ case VC.AuxMode.TEMPERATURE:
52
+ this.addMetadatum('temperature','K', 'House battery temperature',
53
+ (buff,offset=0)=>{return buff.readInt16LE(offset)/100},
54
+ '6597ed7d-4bda-4c1e-af4b-551c4cf74769')
55
+ break;
56
+ default:
57
+ break
58
+ }
59
+ }
60
+
61
+ emitValuesFrom(decData){
62
+ this.emitData("ttg",decData,0)
63
+ this.emitData("voltage",decData,2);
64
+ const alarm = this.getMetadatum("alarm").read(decData,4)
65
+ if (alarm>0){
66
+ this.emit(
67
+ `ALARM #${alarm} from ${this.getDisplayName()})`,
68
+ { message: AlarmReason.get(alarm), state: 'alert'})
69
+ }
70
+
71
+ this.emit("current", (this.getAuxModeAndCurrent(8,decData)).current)
72
+ switch(this.auxMode){
73
+ case VC.AuxMode.STARTER_VOLTAGE:
74
+ this.emitData("starterVoltage",decData,6);
75
+ break;
76
+ case VC.AuxMode.MIDPOINT_VOLTAGE:
77
+ this.emitData("midpointVoltage",decData,6);
78
+ break;
79
+ case VC.AuxMode.TEMPERATURE:
80
+ this.emitData("temperature",decData,6);
81
+ break;
82
+ default:
83
+ break
84
+ }
85
+ this.emit("consumed",decData.readInt16LE(11) / 10 ); //TODO this ain't right
86
+ var soc = decData.readUInt16LE(13)
87
+ this.emit("soc", ((soc & 0x3FFF) >> 4) / 1000)
88
+ }
89
+
90
+ initGATT() {
91
+ return new Promise((resolve,reject )=>{
92
+ if (!this.valueIfVariant(this.currentProperties.Paired))
93
+ reject(`${this.getName()} must be paired with the Signalk server to use GATT protocol`)
94
+ this.device.connect().then(async ()=>{
95
+ if (!this.gattServer) {
96
+ this.gattServer = await this.device.gatt()
97
+ this.gattService= await this.gattServer.getPrimaryService("65970000-4bda-4c1e-af4b-551c4cf74769")
98
+ const keepAlive = await this.gattService.getCharacteristic('6597ffff-4bda-4c1e-af4b-551c4cf74769')
99
+ await keepAlive.writeValue(Buffer.from([0xFF,0xFF]), { offset: 0, type: 'request' })
100
+ }
101
+ resolve(this)
102
+ }).catch((e)=>reject(e.message))
103
+ })
104
+ }
105
+ emitGATT(){
106
+ this.getPathMetadata().forEach( (datum, tag)=> {
107
+ if (datum.gatt) {
108
+ this.gattService.getCharacteristic(datum.gatt).then((gattCharacteristic)=>{
109
+ gattCharacteristic.readValue().then((buffer)=>{
110
+ this.emitData(tag, buffer)
111
+ })
112
+ }).catch((e)=>{
113
+ throw new Error(e)
114
+ })}
115
+ })
116
+ }
117
+ initGATTNotifications(){
118
+ return new Promise((resolve,reject )=>{
119
+
120
+ this.getPathMetadata().forEach((datum, tag)=> {
121
+ if (datum.gatt) {
122
+ this.gattService.getCharacteristic(datum.gatt).then(async (gattCharacteristic)=>{
123
+ const buffer = await gattCharacteristic.readValue()
124
+ this.emitData(tag, buffer)
125
+
126
+ gattCharacteristic.startNotifications().then(()=>{
127
+ gattCharacteristic.on('valuechanged', buffer => {
128
+ this.emitData(tag, buffer)
129
+ })
130
+ this.characteristics.push(gattCharacteristic)
131
+ })
132
+ })
133
+ }})
134
+ resolve(this)})
135
+ }
136
+ propertiesChanged(props){
137
+ super.propertiesChanged(props)
138
+ }
139
+ hasGATT(){
140
+ return true
141
+ }
142
+
143
+ getGATTDescription(){
144
+ return "To use the GATT connection the SignalK server computer and the Smart Shunt must first be paired."
145
+ }
146
+
147
+ async disconnect(){
148
+ super.disconnect()
149
+ for (var c of this.characteristics){
150
+ await c.stopNotifications()
151
+ }
152
+ if (await this.device.isConnected()){
153
+ console.log(`Disconnecting from ${ this.getMacAddress()}`)
154
+ await this.device.disconnect()
155
+ }
156
+ }
157
+ }
158
+ module.exports=VictronBatteryMonitor
@@ -0,0 +1,26 @@
1
+ const VictronSensor = require("./Victron/VictronSensor");
2
+ const VC=require("./Victron/VictronConstants.js")
3
+
4
+ class VictronDCDCConverter extends VictronSensor{
5
+
6
+ static async identify(device){
7
+ return await this.identifyMode(device,0x04)
8
+ }
9
+
10
+ async init(){
11
+ await super.init()
12
+ this.addMetadatum('deviceState','', 'device state',
13
+ (buff)=>{return VC.OperationMode.get(buff.readUInt8(0))})
14
+ this.addMetadatum('chargerError','', 'charger error',
15
+ (buff)=>{return VC.ChargerError.get(buff.readUInt8(1))})
16
+ this.addMetadatum('inputVoltage','V', 'input voltage',
17
+ (buff)=>{return this.NaNif(buff.readUInt16LE(2),0xFFFF)/100})
18
+ this.addMetadatum('outputVoltage','V', 'output voltage',
19
+ (buff)=>{return this.NaNif(buff.readInt16LE(4),0x7FFF)/100 })
20
+ this.addMetadatum('offReason','', 'reason unit is off',
21
+ (buff)=>{return VC.OffReasons.get(buff.readUInt32LE(6))})
22
+
23
+ }
24
+
25
+ }
26
+ module.exports=VictronDCDCConverter
@@ -0,0 +1,66 @@
1
+ const VictronSensor = require("./Victron/VictronSensor");
2
+ const VC=require("./Victron/VictronConstants.js")
3
+
4
+ class VictronDCEnergyMeter extends VictronSensor{
5
+
6
+ static async identify(device){
7
+ return await this.identifyMode(device, 0x0D)
8
+ }
9
+ async init(){
10
+ await super.init()
11
+ this.addMetadatum('meterType','', 'meter type',
12
+ (buff)=>{return VC.MeterType.get( buff.readInt16LE(0))})
13
+ this.addMetadatum('voltage','','voltage',
14
+ (buff)=>{return buff.readInt16LE(2)/100})
15
+ this.addMetadatum('alarm','', 'alarm',
16
+ (buff)=>{return buff.readUInt16LE(4)})
17
+ this.addMetadatum('current','A', 'current')
18
+ const modeCurrent = this.getAuxModeAndCurrent()
19
+ this.auxMode= modeCurrent.auxMode
20
+ switch(this.auxMode){
21
+ case VC.AuxMode.STARTER_VOLTAGE:
22
+ this.addMetadatum('starterVoltage','V', 'starter battery voltage',
23
+ (buff,offset=0)=>{return buff.readInt16LE(offset)/100})
24
+ break;
25
+
26
+ case VC.AuxMode.TEMPERATURE:
27
+ this.addMetadatum('temperature','K','House battery temperature',
28
+ (buff,offset=0)=>{
29
+ const temp = buff.readUInt16LE(offset)
30
+ if (temp==0xffff)
31
+ return null
32
+ else
33
+ return temp / 100
34
+ })
35
+ break;
36
+ default:
37
+ break
38
+ }
39
+ }
40
+
41
+ emitValuesFrom(decData){
42
+ this.emitData("meterType",decData,0)
43
+ this.emitData("voltage",decData,2);
44
+ const alarm = this.getMetadatum("alarm").read(decData,4)
45
+ if (alarm>0){
46
+ this.emit(
47
+ `ALARM #${alarm} from ${this.getDisplayName()})`,
48
+ { message: AlarmReason(alarm), state: 'alert'})
49
+ }
50
+ switch(this.auxMode){
51
+ case VC.AuxMode.STARTER_VOLTAGE:
52
+ this.emitData("starterVoltage",decData,6);
53
+ break;
54
+ case VC.AuxMode.TEMPERATURE:
55
+ this.emitData("temperature",decData,6);
56
+ break;
57
+ default:
58
+ break
59
+ }
60
+ this.emit("current", this.getAuxModeAndCurrent(8,decData).current)
61
+
62
+ }
63
+
64
+
65
+ }
66
+ module.exports=VictronDCEnergyMeter
@@ -0,0 +1,43 @@
1
+ const VictronSensor = require ("./Victron/VictronSensor.js")
2
+ const VC = require("./Victron/VictronConstants.js")
3
+ const int24 = require('int24')
4
+ class VictronGXDevice extends VictronSensor{
5
+ /*
6
+ Record layout is still to be determined and might change.
7
+ Start
8
+ bit
9
+ Nr of
10
+ bits Meaning Units Range NA value Remark
11
+ 0 0 32 16 Battery voltage 0.01 V 0 .. 655.34
12
+ V
13
+ 0xFFFF VE_REG_DC_CHANNEL1_VOLTAGE
14
+ 2 16 48 20 PV power W 0 .. 1 MW 0xFFFFF VE_REG_DC_INPUT_POWER
15
+ 4 36 68 7 SOC 1% 0 .. 100% 0x7F VE_REG_SOC
16
+ 5 43 75 21 Battery power W -1 .. 1 MW 0x0FFFFF VE_REG_DC_CHANNEL1_POWER
17
+ 96 21 DC power W -1 .. 1 MW 0x0FFFFF
18
+ TBD - AC in power
19
+ TBD - AC out power
20
+ TBD - Warnings /
21
+ Alarms
22
+ TBD
23
+ 117 43 Unuse
24
+ */
25
+ static async identify(device){
26
+ return await this.identifyMode(device, 0x07)
27
+ }
28
+
29
+ async init() {
30
+ super.init()
31
+ this.addMetadatum('voltage','V', 'channel #1 voltage',
32
+ (buff)=>{return this.NaNif(buff.readInt16LE(0),0xFFFF)/100})
33
+ this.addMetadatum('pvPower','W','DC input power in watts',
34
+ (buff)=>{return this.NaNif(int24.readInt24BE(buff,2)>>4,0xFFFFF)})
35
+ this.addMetadatum('soc','ratio', 'state of charge',
36
+ (buff)=>{ return ((buff.readUInt16BE(4)&0xfff)>>5)/100})
37
+ this.addMetadatum('batteryPower','W', 'battery power',
38
+ (buff)=>{return (this.NaNif(int24.readInt24BE(buff,5)&0x1ffff),0x0FFFFF )})
39
+ this.addMetadatum('DCPower','W', 'DCpower',
40
+ (buff)=>{return this.NaNif(int24.readInt24BE(buff,8)>>3,0x0FFFFF )})
41
+ }
42
+ }
43
+ module.exports=VictronGXDevice
@@ -0,0 +1,43 @@
1
+ const VictronSensor = require("./Victron/VictronSensor");
2
+ const VC=require("./Victron/VictronConstants.js")
3
+
4
+
5
+ class VictronInverter extends VictronSensor{
6
+ static async identify(device){
7
+ return await this.identifyMode(device, 0x03)
8
+ }
9
+
10
+ async init() {
11
+ await super.init()
12
+ this.addMetadatum('deviceState','', 'inverter device state',
13
+ (buff)=>{return VC.OperationMode.get(buff.readIntU8(0))})
14
+ const md = this.addMetadatum('alarmReason','', 'reason for alarm',
15
+ (buff)=>{return buff.readIntU16LE(1)})
16
+ md.notify=true
17
+
18
+ this.addMetadatum('batteryVoltage','V', 'battery voltage',
19
+ (buff)=>{return this.NaNif(buff.readInt16LE(3),0x7FFF)/100})
20
+ this.addMetadatum('acPower','W', 'AC power (in watts: Apparent Power * Power Factor)',
21
+ (buff)=>{return this.NaNif( buff.readUInt16LE(5), 0xFFFF )*this.powerFactor})
22
+ this.addMetadatum('acVoltage','V','AC Voltage',
23
+ (buff)=>{return this.NaNif((buff.readUInt16BE(5)>>1),0x7FFF)/10})
24
+ this.addMetadatum('acCurrent','A', 'AC Current',
25
+ (buff)=>{return this.NaNif(((buff.readUInt32BE(5)&0x7ffff)>>6),0x7FF)/10}
26
+ )
27
+
28
+ }
29
+ powerFactor = .8 //parameterize anon
30
+
31
+ emitValuesFrom(decData){
32
+ super.emitValuesFrom(decData)
33
+ const alarm = this.getMetadatum("alarmReason").read(decData)
34
+ if (alarm>0){
35
+ this.emit(
36
+ `ALARM #${alarm} from ${this.getDisplayName()})`,
37
+ { message: VC.AlarmReason.get(alarm), state: 'alert'})
38
+ }
39
+ }
40
+
41
+
42
+ }
43
+ module.exports=VictronInverter
@@ -0,0 +1,44 @@
1
+ const VictronSensor = require("./Victron/VictronSensor");
2
+ const VC=require("./Victron/VictronConstants.js")
3
+
4
+ function toBinaryString(buff){
5
+ return [...buff].map((b) => b.toString(2).padStart(8, "0")).join("");
6
+ }
7
+ class VictronInverterRS extends VictronSensor{
8
+ static async identify(device){
9
+ return await this.identifyMode(device, 0x06)
10
+ }
11
+
12
+
13
+ async init() {
14
+ await super.init()
15
+
16
+ this.addMetadatum('deviceState','', 'inverter device state',
17
+ (buff)=>{return VC.OperationMode.get(buff.readIntU8(0))})
18
+ const md = this.addMetadatum('chargerError','', 'charger error',
19
+ (buff)=>{return VC.ChargerError(buff.readIntU8(1))})
20
+ md.notify=true
21
+
22
+ this.addMetadatum('batteryVoltage','V', 'battery voltage',
23
+ (buff)=>{return this.NaNif(buff.readInt16LE(2),0x7FFF)/100})
24
+ this.addMetadatum('pvPower','W', 'PV power',
25
+ (buff)=>{return this.NaNif(buff.readUInt16LE(4), 0xffff)})
26
+ this.addMetadatum('yieldToday','W', 'yield yoday in watts',
27
+ (buff)=>{return this.NaNif(buff.readUInt16LE(6), 0xffff)*10})
28
+ this.addMetadatum('acOutPower','W', 'AC out power in watts',
29
+ (buff)=>{this.NaNif(buff.readInt16LE(8), 0x7fff)})
30
+ }
31
+
32
+ emitValuesFrom(decData){
33
+ super.emitValuesFrom(decData)
34
+ const error = this.getMetadatum("chargerError").read(decData)
35
+ if (error>0){
36
+ this.emit(
37
+ `Charger Error #${error} from ${this.getDisplayName()})`,
38
+ { message: VC.ChargerError.get(error), state: 'error'})
39
+ }
40
+ }
41
+
42
+
43
+ }
44
+ module.exports=VictronInverterRS
@@ -0,0 +1,49 @@
1
+ /*(Lynx Smart) BMS (0x0A)
2
+ Start Bit Nr of Bits Meaning Units Range NA Value Remark
3
+ 32 8 Error 0x0 VE_REG_BMS_ERROR
4
+ 40 16 TTG 1min 0..45.5 days 0xFFFF VE_REG_TTG
5
+ 56 16 Battery voltage 0.01V -327.68..327.66 V 0x7FFF VE_REG_DC_CHANNEL1_VOLTAGE
6
+ 72 16 Battery current 0.1A -3276.8..3276.6 0x7FFF VE_REG_DC_CHANNEL1_CURRENT
7
+ 88 16 IO status 0x0 VE_REG_BMS_IO
8
+ 104 18 Warnings/Alarms 0x0 VE_REG_BMS_WARNINGS_ALARMS
9
+ 122 10 SOC 0.1% 0..100.0% 0x3FF VE_REG_SOC
10
+ 132 20 Consumed Ah 0.1Ah -104,857..0 Ah 0xFFFFF VE_REG_CAH Consumed Ah = -Record value
11
+ 152 7 Temperature °C -40..86 °C 0x7F VE_REG_BAT_TEMPERATURE Temperature = Record value - 40
12
+ 159 1 Unused*/
13
+
14
+
15
+
16
+ const VictronSensor = require ("./Victron/VictronSensor.js")
17
+ const VC = require("./Victron/VictronConstants.js")
18
+ const int24 = require('int24')
19
+
20
+ class VictronLynxSmartBMS extends VictronSensor{
21
+
22
+ static async identify(device){
23
+ return await this.identifyMode(device, 0x0A)
24
+ }
25
+
26
+ async init() {
27
+ await super.init()
28
+ this.addMetadatum('error','', 'error code',
29
+ (buff)=>{return buff.readUInt8(0)})
30
+
31
+ this.addMetadatum('ttg','s', 'time to go (in seconds)',
32
+ (buff)=>{return this.NaNif(buff.readUInt16LE(1),0xFFFF)*60})
33
+ this.addMetadatum('voltage','V', 'channel 1 voltage',
34
+ (buff)=>{return this.NaNif(buff.readInt16LE(3),0x7FFF)/100})
35
+ this.addMetadatum('current','A','channel 1 current',
36
+ (buff)=>{return this.NaNif(buff.readInt16LE(5),0x7FFF)/10})
37
+ this.addMetadatum('ioStatus','','IO Status', //TODO
38
+ (buff)=>{return buff.readInt16LE(7)})
39
+ this.addMetadatum('warningsAndAlarms','','warnings and alarms', //TODO
40
+ (buff)=>{return (int24.readUInt24BE(buff,9)>>6)})
41
+ this.addMetadatum('soc','','state of charge',
42
+ (buff)=>{return this.NaNif(((buff.readUInt16BE(11)&0x3fff)>>4),0x3FF)/1000})
43
+ this.addMetadatum('consumedAh','Ah','amp-hours consumed',
44
+ (buff)=>{return this.NaNif((int24.readUInt24BE(13)>>4),0xFFFFF)/10} )
45
+ this.addMetadatum('temp', 'K', 'battery temperature',
46
+ (buff)=>{this.NaNif( buff.readUInt8(15)>>1,0x7f) +233.15})
47
+ }
48
+ }
49
+ module.exports=VictronLynxSmartBMS
@@ -0,0 +1,30 @@
1
+ /*
2
+
3
+ */
4
+ const VictronSensor = require ("./Victron/VictronSensor.js")
5
+ const VC = require("./Victron/VictronConstants.js")
6
+ class VictronOrionXS extends VictronSensor{
7
+
8
+ static async identify(device){
9
+ return await this.identifyMode(device, 0x0F)
10
+ }
11
+ async init() {
12
+ await super.init()
13
+ this.addMetadatum('deviceState','', 'device state',
14
+ (buff)=>{return VC.OperationMode.get(buff.readUInt8(0))})
15
+ this.addMetadatum('chargerError','', 'charger error',
16
+ (buff)=>{return VC.ChargerError.get(buff.readUInt8(1))})
17
+ this.addMetadatum('outputVoltage','V', 'output voltage',
18
+ (buff)=>{return this.NaNif(buff.readInt16LE(2),0x7FF)/100})
19
+ this.addMetadatum('current','A','output current',
20
+ (buff)=>{return this.NaNif(buff.readUInt16LE(4),0xFFFF)/10})
21
+ this.addMetadatum('inputVoltage','V', 'input voltage',
22
+ (buff)=>{return this.NaNif(buff.readInt16LE(6),0x07FF)/100})
23
+ this.addMetadatum('inputCurrent','A','input current',
24
+ (buff)=>{return this.NaNif(buff.readUInt16LE(8),0xFFFF)/10})
25
+ this.addMetadatum('deviceOffReason','', 'device off reason',
26
+ (buff)=>{return VC.OffReasons(buff.readUInt32(10))})
27
+ }
28
+
29
+ }
30
+ module.exports=VictronOrionXS