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

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,106 @@
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 {
15
+ this.metadata = new Map(super.getMetadata())
16
+ const md = this.addMetadatum('encryptionKey','', "Encryption Key")
17
+ md.isParam = true
18
+ }
19
+
20
+ static async identifyMode(device, mode){
21
+
22
+ try{
23
+ const md = await this.getDeviceProp(device,'ManufacturerData')
24
+ if (!md) return null
25
+ const data = md[0x2e1]
26
+ if (data && data.value[0]==0x10 && data.value[4]==mode)
27
+ return this
28
+ else
29
+ return null
30
+ } catch (e){
31
+ console.log(e)
32
+ return null
33
+ }
34
+
35
+ }
36
+
37
+ getAuxModeAndCurrent(offset, decData=null){
38
+ if (decData==null){
39
+ decData=this.getManufacturerData(0x2e1)
40
+ if (this.encryptionKey)
41
+ decData=this.decrypt(decData)
42
+ else
43
+ return {current:NaN, auxMode:NaN}
44
+ }
45
+ const auxModeAndCurrent = int24.readInt24LE(decData,offset)
46
+ return {
47
+ current : (this.NaNif(auxModeAndCurrent >> 2,0x3FFFFF))/1000,
48
+ auxMode : auxModeAndCurrent & 0b11
49
+ }
50
+ }
51
+
52
+ async init(){
53
+ await super.init()
54
+ this.model_id=this.getManufacturerData(0x2e1).readUInt16LE(2)
55
+ }
56
+ alarmReason(alarmValue){
57
+ return this.constructor.AlarmReason[alarmValue]
58
+ }
59
+ getModelName(){
60
+ return VC.MODEL_ID_MAP[this.model_id]
61
+ }
62
+
63
+ decrypt(data){
64
+ if (!this.encryptionKey)
65
+ throw Error("Unable to decrypt: no encryption key set")
66
+
67
+ const encMethod = 'aes-128-ctr';
68
+ const iv = data.readUInt16LE(5);
69
+ const key = Buffer.from(this.encryptionKey,'hex')
70
+ const ivBuffer = Buffer.alloc(16); // 128 bits = 16 bytes
71
+
72
+ ivBuffer.writeUInt16LE(iv)
73
+
74
+ var encData = Buffer.from([...data.slice(8)])
75
+
76
+ const decipher = crypto.createDecipheriv(encMethod, key, ivBuffer)
77
+
78
+ const decData=decipher.update(encData)
79
+
80
+ return Buffer.from(decData)
81
+
82
+ }
83
+ getName(){
84
+ return `Victron ${this.getModelName()}`
85
+ }
86
+ propertiesChanged(props){
87
+ super.propertiesChanged(props)
88
+ if (this.usingGATT()) return
89
+ try{
90
+ const buff = this.getManufacturerData(0x2e1)
91
+ const decData=this.decrypt(buff)
92
+ this.emitValuesFrom(decData)
93
+ }
94
+ catch (error) {
95
+ throw new Error(`Unable to read data from ${ this.getDisplayName()}: ${error}` )
96
+ }
97
+ }
98
+
99
+ initGATT(){
100
+ throw new Error( "GATT Connection unimplemented for "+this.getDisplayName())
101
+ }
102
+
103
+
104
+
105
+ }
106
+ module.exports=VictronSensor
@@ -0,0 +1,64 @@
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
+ static {
32
+ this.metadata = new Map(super.getMetadata())
33
+
34
+ this.addMetadatum('state','', 'device state',
35
+ (buff)=>{return VC.OperationMode.get(buff.readUInt8(0))})
36
+ this.addMetadatum('error','', 'error code',
37
+ (buff)=>{return VC.ChargerError.get(buff.readUInt8(1))})
38
+
39
+ this.addMetadatum('batt1','V', 'battery 1 voltage',
40
+ (buff)=>{return this.NaNif((buff.readUInt16BE(2)>>3), 0x1FFF)/100})
41
+
42
+ this.addMetadatum('curr1','A', 'battery 1 current',
43
+ (buff)=>{return this.NaNif(buff.readUInt16BE(3)&0x7FF,0x7FF)/10})
44
+
45
+ this.addMetadatum('batt2','V', 'battery 2 voltage',
46
+ (buff)=>{return this.NaNif((buff.readUInt16BE(5)>>3), 0x1FFF)/100})
47
+
48
+ this.addMetadatum('curr2','A', 'battery 2 current',
49
+ (buff)=>{return this.NaNif(buff.readUInt16BE(7)&0x7FF,0x7FF)/10})
50
+
51
+ this.addMetadatum('batt3','V', 'battery 3 voltage',
52
+ (buff)=>{return this.NaNif((buff.readUInt16BE(8)>>3), 0x1FFF)/100})
53
+
54
+ this.addMetadatum('curr3','A', 'battery 3 current',
55
+ (buff)=>{return this.NaNif(buff.readUInt16BE(9)&0x7FF,0x7FF)/10})
56
+
57
+ this.addMetadatum('temp', 'K', 'battery temperature',
58
+ (buff)=>{return this.NaNif(buff.readUInt8(11)>>1,0x7F)+233.15}) //-40 plus K conversion
59
+
60
+ this.addMetadatum('acCurr','A', 'AC current',
61
+ (buff)=>{return this.NaNif((buff.readInt16BE(11))&0x1FFF,0x1FFF)})
62
+ }
63
+ }
64
+ module.exports=VictronACCharger
@@ -0,0 +1,160 @@
1
+ const VictronSensor = require("./Victron/VictronSensor.js");
2
+ const VC=require("./Victron/VictronConstants.js")
3
+ class VictronBatteryMonitor extends VictronSensor{
4
+ static {
5
+ this.metadata = new Map(super.getMetadata())
6
+ this.addMetadatum('current', 'A', 'house battery amperage',
7
+ (buff,offset=0)=>{return buff.readInt32LE(offset)/1000},
8
+ '6597ed8c-4bda-4c1e-af4b-551c4cf74769')
9
+ this.addMetadatum('power','W', 'house battery wattage',
10
+ (buff,offset=0)=>{return buff.readInt16LE(offset)},
11
+ '6597ed8e-4bda-4c1e-af4b-551c4cf74769')
12
+ this.addMetadatum('voltage','V', 'house battery voltage',
13
+ (buff,offset=0)=>{return this.NaNif(buff.readInt16LE(offset), 0x7FFF)/100},
14
+ '6597ed8d-4bda-4c1e-af4b-551c4cf74769',)
15
+ const alarmMD = this.addMetadatum('alarm','', 'alarm',
16
+ (buff,offset=0)=>{return buff.readInt16LE(offset)})
17
+ alarmMD.notify=true
18
+
19
+ this.addMetadatum( 'consumed','C', 'amp-hours consumed',
20
+ (buff,offset=0)=>{return buff.readInt32LE(offset)/10},
21
+ '6597eeff-4bda-4c1e-af4b-551c4cf74769',)
22
+
23
+ this.addMetadatum( 'soc','ratio', 'state of charge',
24
+ (buff,offset=0)=>{return buff.readUInt16LE(offset)/10000},
25
+ '65970fff-4bda-4c1e-af4b-551c4cf74769')
26
+
27
+ this.addMetadatum( 'ttg','s','time to go',
28
+ (buff,offset=0)=>{return this.NaNif(buff.readUInt16LE(offset),0xFFFF)*60},
29
+ '65970ffe-4bda-4c1e-af4b-551c4cf74769')
30
+ }
31
+
32
+ static async identify(device){
33
+ return await this.identifyMode(device, 0x02)
34
+ }
35
+
36
+ characteristics=[]
37
+ async init(){
38
+ await super.init()
39
+ const modecurrent = this.getAuxModeAndCurrent()
40
+ this.auxMode= modecurrent.auxMode
41
+ switch(this.auxMode){
42
+ case VC.AuxMode.STARTER_VOLTAGE:
43
+ this.addMetadatum('starterVoltage','V', 'starter battery voltage',
44
+ (buff,offset=0)=>{return buff.readInt16LE(offset)/100},
45
+ '6597ed7d-4bda-4c1e-af4b-551c4cf74769')
46
+ break;
47
+ case VC.AuxMode.MIDPOINT_VOLTAGE:
48
+ this.addMetadatum('midpointVoltage','V', 'midpoint battery voltage',
49
+ (buff,offset=0)=>{return buff.readInt16LE(offset)/100},
50
+ '6597ed7d-4bda-4c1e-af4b-551c4cf74769')
51
+ break;
52
+
53
+ case VC.AuxMode.TEMPERATURE:
54
+ this.addMetadatum('temperature','K', 'House battery temperature',
55
+ (buff,offset=0)=>{return buff.readInt16LE(offset)/100},
56
+ '6597ed7d-4bda-4c1e-af4b-551c4cf74769')
57
+ break;
58
+ default:
59
+ break
60
+ }
61
+ }
62
+
63
+ emitValuesFrom(decData){
64
+ this.emitData("ttg",decData,0)
65
+ this.emitData("voltage",decData,2);
66
+ const alarm = this.getMetadatum("alarm").read(decData,4)
67
+ if (alarm>0){
68
+ this.emit(
69
+ `ALARM #${alarm} from ${this.getDisplayName()})`,
70
+ { message: AlarmReason.get(alarm), state: 'alert'})
71
+ }
72
+
73
+ this.emit("current", (this.getAuxModeAndCurrent(8,decData)).current)
74
+ switch(this.auxMode){
75
+ case VC.AuxMode.STARTER_VOLTAGE:
76
+ this.emitData("starterVoltage",decData,6);
77
+ break;
78
+ case VC.AuxMode.MIDPOINT_VOLTAGE:
79
+ this.emitData("midpointVoltage",decData,6);
80
+ break;
81
+ case VC.AuxMode.TEMPERATURE:
82
+ this.emitData("temperature",decData,6);
83
+ break;
84
+ default:
85
+ break
86
+ }
87
+ this.emit("consumed",decData.readInt16LE(11) / 10 ); //TODO this ain't right
88
+ var soc = decData.readUInt16LE(13)
89
+ this.emit("soc", ((soc & 0x3FFF) >> 4) / 1000)
90
+ }
91
+
92
+ initGATT() {
93
+ return new Promise((resolve,reject )=>{
94
+ if (!this.valueIfVariant(this.currentProperties.Paired))
95
+ reject(`${this.getName()} must be paired with the Signalk server to use GATT protocol`)
96
+ this.device.connect().then(async ()=>{
97
+ if (!this.gattServer) {
98
+ this.gattServer = await this.device.gatt()
99
+ this.gattService= await this.gattServer.getPrimaryService("65970000-4bda-4c1e-af4b-551c4cf74769")
100
+ const keepAlive = await this.gattService.getCharacteristic('6597ffff-4bda-4c1e-af4b-551c4cf74769')
101
+ await keepAlive.writeValue(Buffer.from([0xFF,0xFF]), { offset: 0, type: 'request' })
102
+ }
103
+ resolve(this)
104
+ }).catch((e)=>reject(e.message))
105
+ })
106
+ }
107
+ emitGATT(){
108
+ this.getPathMetadata().forEach( (datum, tag)=> {
109
+ if (datum.gatt) {
110
+ this.gattService.getCharacteristic(datum.gatt).then((gattCharacteristic)=>{
111
+ gattCharacteristic.readValue().then((buffer)=>{
112
+ this.emitData(tag, buffer)
113
+ })
114
+ }).catch((e)=>{
115
+ throw new Error(e)
116
+ })}
117
+ })
118
+ }
119
+ initGATTNotifications(){
120
+ return new Promise((resolve,reject )=>{
121
+
122
+ this.getPathMetadata().forEach((datum, tag)=> {
123
+ if (datum.gatt) {
124
+ this.gattService.getCharacteristic(datum.gatt).then(async (gattCharacteristic)=>{
125
+ const buffer = await gattCharacteristic.readValue()
126
+ this.emitData(tag, buffer)
127
+
128
+ gattCharacteristic.startNotifications().then(()=>{
129
+ gattCharacteristic.on('valuechanged', buffer => {
130
+ this.emitData(tag, buffer)
131
+ })
132
+ this.characteristics.push(gattCharacteristic)
133
+ })
134
+ })
135
+ }})
136
+ resolve(this)})
137
+ }
138
+ propertiesChanged(props){
139
+ super.propertiesChanged(props)
140
+ }
141
+ canUseGATT(){
142
+ return true
143
+ }
144
+
145
+ getGATTDescription(){
146
+ return "To use the GATT connection the SignalK server computer and the Smart Shunt must first be paired."
147
+ }
148
+
149
+ async disconnect(){
150
+ super.disconnect()
151
+ for (var c of this.characteristics){
152
+ await c.stopNotifications()
153
+ }
154
+ if (await this.device.isConnected()){
155
+ console.log(`Disconnecting from ${ this.getMacAddress()}`)
156
+ await this.device.disconnect()
157
+ }
158
+ }
159
+ }
160
+ 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
+ static {
11
+ this.metadata= new Map(super.getMetadata())
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,68 @@
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
+ const modeCurrent = this.getAuxModeAndCurrent()
12
+ this.auxMode= modeCurrent.auxMode
13
+ switch(this.auxMode){
14
+ case VC.AuxMode.STARTER_VOLTAGE:
15
+ this.addMetadatum('starterVoltage','V', 'starter battery voltage',
16
+ (buff,offset=0)=>{return buff.readInt16LE(offset)/100})
17
+ break;
18
+
19
+ case VC.AuxMode.TEMPERATURE:
20
+ this.addMetadatum('temperature','K','House battery temperature',
21
+ (buff,offset=0)=>{
22
+ const temp = buff.readUInt16LE(offset)
23
+ if (temp==0xffff)
24
+ return null
25
+ else
26
+ return temp / 100
27
+ })
28
+ break;
29
+ default:
30
+ break
31
+ }
32
+ }
33
+ static {
34
+ this.metadata = new Map(super.getMetadata())
35
+ this.addMetadatum('meterType','', 'meter type',
36
+ (buff)=>{return VC.MeterType.get( buff.readInt16LE(0))})
37
+ this.addMetadatum('voltage','','voltage',
38
+ (buff)=>{return buff.readInt16LE(2)/100})
39
+ this.addMetadatum('alarm','', 'alarm',
40
+ (buff)=>{return buff.readUInt16LE(4)})
41
+ this.addMetadatum('current','A', 'current')
42
+ }
43
+ emitValuesFrom(decData){
44
+ this.emitData("meterType",decData,0)
45
+ this.emitData("voltage",decData,2);
46
+ const alarm = this.getMetadatum("alarm").read(decData,4)
47
+ if (alarm>0){
48
+ this.emit(
49
+ `ALARM #${alarm} from ${this.getDisplayName()})`,
50
+ { message: AlarmReason(alarm), state: 'alert'})
51
+ }
52
+ switch(this.auxMode){
53
+ case VC.AuxMode.STARTER_VOLTAGE:
54
+ this.emitData("starterVoltage",decData,6);
55
+ break;
56
+ case VC.AuxMode.TEMPERATURE:
57
+ this.emitData("temperature",decData,6);
58
+ break;
59
+ default:
60
+ break
61
+ }
62
+ this.emit("current", this.getAuxModeAndCurrent(8,decData).current)
63
+
64
+ }
65
+
66
+
67
+ }
68
+ 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
+ static {
30
+ this.metadata = new Map(super.getMetadata())
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,44 @@
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
+ static {
11
+ var md
12
+ this.metadata= new Map(super.getMetadata())
13
+ this.addMetadatum('deviceState','', 'inverter device state',
14
+ (buff)=>{return VC.OperationMode.get(buff.readIntU8(0))})
15
+ md = this.addMetadatum('alarmReason','', 'reason for alarm',
16
+ (buff)=>{return buff.readIntU16LE(1)})
17
+ md.notify=true
18
+
19
+ this.addMetadatum('batteryVoltage','V', 'battery voltage',
20
+ (buff)=>{return this.NaNif(buff.readInt16LE(3),0x7FFF)/100})
21
+ this.addMetadatum('acPower','W', 'AC power (in watts: Apparent Power * Power Factor)',
22
+ (buff)=>{return this.NaNif( buff.readUInt16LE(5), 0xFFFF )*this.powerFactor})
23
+ this.addMetadatum('acVoltage','V','AC Voltage',
24
+ (buff)=>{return this.NaNif((buff.readUInt16BE(5)>>1),0x7FFF)/10})
25
+ this.addMetadatum('acCurrent','A', 'AC Current',
26
+ (buff)=>{return this.NaNif(((buff.readUInt32BE(5)&0x7ffff)>>6),0x7FF)/10}
27
+ )
28
+
29
+ }
30
+ powerFactor = .8 //parameterize anon
31
+
32
+ emitValuesFrom(decData){
33
+ super.emitValuesFrom(decData)
34
+ const alarm = this.getMetadatum("alarmReason").read(decData)
35
+ if (alarm>0){
36
+ this.emit(
37
+ `ALARM #${alarm} from ${this.getDisplayName()})`,
38
+ { message: VC.AlarmReason.get(alarm), state: 'alert'})
39
+ }
40
+ }
41
+
42
+
43
+ }
44
+ 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
+ static {
14
+ var md
15
+ this.metadata= new Map(super.getMetadata())
16
+ this.addMetadatum('deviceState','', 'inverter device state',
17
+ (buff)=>{return VC.OperationMode.get(buff.readIntU8(0))})
18
+ 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,50 @@
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
+ static {
27
+ this.metadata = new Map(super.getMetadata())
28
+
29
+ this.addMetadatum('error','', 'error code',
30
+ (buff)=>{return buff.readUInt8(0)})
31
+
32
+ this.addMetadatum('ttg','s', 'time to go (in seconds)',
33
+ (buff)=>{return this.NaNif(buff.readUInt16LE(1),0xFFFF)*60})
34
+ this.addMetadatum('voltage','V', 'channel 1 voltage',
35
+ (buff)=>{return this.NaNif(buff.readInt16LE(3),0x7FFF)/100})
36
+ this.addMetadatum('current','A','channel 1 current',
37
+ (buff)=>{return this.NaNif(buff.readInt16LE(5),0x7FFF)/10})
38
+ this.addMetadatum('ioStatus','','IO Status', //TODO
39
+ (buff)=>{return buff.readInt16LE(7)})
40
+ this.addMetadatum('warningsAndAlarms','','warnings and alarms', //TODO
41
+ (buff)=>{return (int24.readUInt24BE(buff,9)>>6)})
42
+ this.addMetadatum('soc','','state of charge',
43
+ (buff)=>{return this.NaNif(((buff.readUInt16BE(11)&0x3fff)>>4),0x3FF)/1000})
44
+ this.addMetadatum('consumedAh','Ah','amp-hours consumed',
45
+ (buff)=>{return this.NaNif((int24.readUInt24BE(13)>>4),0xFFFFF)/10} )
46
+ this.addMetadatum('temp', 'K', 'battery temperature',
47
+ (buff)=>{this.NaNif( buff.readUInt8(15)>>1,0x7f) +233.15})
48
+ }
49
+ }
50
+ module.exports=VictronLynxSmartBMS
@@ -0,0 +1,31 @@
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
+ static {
12
+ this.metadata = new Map(super.getMetadata())
13
+
14
+ this.addMetadatum('deviceState','', 'device state',
15
+ (buff)=>{return VC.OperationMode.get(buff.readUInt8(0))})
16
+ this.addMetadatum('chargerError','', 'charger error',
17
+ (buff)=>{return VC.ChargerError.get(buff.readUInt8(1))})
18
+ this.addMetadatum('outputVoltage','V', 'output voltage',
19
+ (buff)=>{return this.NaNif(buff.readInt16LE(2),0x7FF)/100})
20
+ this.addMetadatum('current','A','output current',
21
+ (buff)=>{return this.NaNif(buff.readUInt16LE(4),0xFFFF)/10})
22
+ this.addMetadatum('inputVoltage','V', 'input voltage',
23
+ (buff)=>{return this.NaNif(buff.readInt16LE(6),0x07FF)/100})
24
+ this.addMetadatum('inputCurrent','A','input current',
25
+ (buff)=>{return this.NaNif(buff.readUInt16LE(8),0xFFFF)/10})
26
+ this.addMetadatum('deviceOffReason','', 'device off reason',
27
+ (buff)=>{return VC.OffReasons(buff.readUInt32(10))})
28
+ }
29
+
30
+ }
31
+ module.exports=VictronOrionXS