123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- const readServiceID = '0000FFE0-0000-1000-8000-00805F9B34FB';
- const readID = '0000FFE4-0000-1000-8000-00805F9B34FB';
- const writeServiceID = '0000FFE5-0000-1000-8000-00805F9B34FB';
- const writeID = '0000FFE9-0000-1000-8000-00805F9B34FB';
- var readPart = '';
- function acceptDevice(device) {
- return device.btid ? true : false;
- }
- function isDevice(device, data) {
- const advertisData = new Uint8Array(data.advertisData);
- const mac = device.btid
- .split('')
- .map((p, i) => parseInt(p + device.btid[i + 1], 16))
- .filter((p, i) => i % 2 == 0);
- if (advertisData.slice(0, 2).toString() == [0x52, 0x53].toString() && advertisData.slice(4, 10).toString() == mac.toString()) {
- return true;
- }
- return false;
- }
- function readDataBP00(value, data) {
- if (value.split('HSO').length == 2) {
- data.imei = value.split('HSO')[0];
- value = value.split('HSO')[1];
- while (value != '') {
- switch (value[0]) {
- case 'P':
- data.quantity = parseInt(value.slice(1, 3));
- value = value.slice(3, value.length);
- break;
- case 'S':
- data.gpscount = parseInt(value.slice(1, 3), 16);
- value = value.slice(3, value.length);
- break;
- case 'G':
- data.gsmlevel = parseInt(value.slice(1, 3), 16);
- value = value.slice(3, value.length);
- break;
- case 'T':
- data.temp = parseInt(value.slice(1, 5), 16) < 0x8000 ? parseInt(value.slice(1, 5), 16) : parseInt(value.slice(1, 5), 16) - 0x10000;
- value = value.slice(5, value.length);
- break;
- case 'C':
- data.cycle = parseInt(value.slice(1, 5), 16);
- value = value.slice(5, value.length);
- break;
- case 'B':
- var state = parseInt(value.slice(1, 3), 16);
- data.lowTempProtectState = (state >> 0) & 1;
- data.highTempProtectState = (state >> 1) & 1;
- data.dischargeProtectState = (state >> 2) & 1;
- data.chargeProtectState = (state >> 3) & 1;
- data.lowVoltageState = (state >> 4) & 1;
- data.chargeState = (state >> 5) & 3;
- data.oilState = (state >> 7) & (1 == 0) ? 1 : 0;
- value = value.slice(3, value.length);
- break;
- case 'X':
- var state = parseInt(value.slice(1, 3), 16);
- data.autoProtectState = (state >> 0) & 1;
- data.elecState = (state >> 1) & (1 == 0) ? 1 : 0;
- data.factoryType = state >> 2;
- value = value.slice(3, value.length);
- break;
- default:
- if (['P', 'S', 'G', 'T', 'C', 'B', 'X'].indexOf(value[3]) == -1) {
- //data.voltage = parseInt(value.slice(0, 4), 16) / 100
- value = value.slice(4, value.length);
- } else {
- //data.voltage = parseInt(value.slice(0, 3), 16) / 100
- value = value.slice(3, value.length);
- }
- }
- }
- return data;
- }
- return false;
- }
- function readDataBS50(value, data) {
- const length = parseInt(value.slice(0, 4), 16);
- value = value.slice(4, value.length);
- if (value.length == length * 2) {
- return BMSReply(
- value
- .split('')
- .map((p, i) => parseInt(p + value[i + 1], 16))
- .filter((p, i) => i % 2 == 0),
- data
- );
- }
- return false;
- }
- function BMSReply(value, data) {
- if (value[0] == 0x4e && value[1] == 0x57) {
- //value = value.slice(2, value.length)
- const length = value[2] * 0x100 + value[3];
- if (value.length == length + 2) {
- data.bmsid = value
- .slice(4, 8)
- .map((p) => ('00' + p.toString(16)).substr(p.toString(16).length))
- .join('');
- if (
- value[8] == 0x06 &&
- value[value.length - 5] == 0x68 &&
- value.slice(0, value.length - 4).reduce((p, c) => p + c) == value[value.length - 2] * 0x100 + value[value.length - 1]
- ) {
- value = value.slice(11, value.length - 9);
- while (value.length != 0) {
- switch (value[0]) {
- case 0x79:
- const voltageLength = parseInt(value[1] / 3);
- data.voltageList = Array(voltageLength);
- let maxVoltage = -1;
- let minVoltage = 99999;
- let sumVoltage = 0;
- for (var i = 0; i < voltageLength; i++) {
- let _v = Math.round(value[i * 3 + 3] * 0x100 + value[i * 3 + 4]) / 1000;
- data.voltageList[value[i * 3 + 2] - 1] = _v;
- sumVoltage += _v;
- if (_v > maxVoltage) maxVoltage = _v;
- if (_v < minVoltage) minVoltage = _v;
- }
- data.maxVoltage = maxVoltage;
- data.minVoltage = minVoltage;
- data.sumVoltage = sumVoltage;
- value = value.slice(voltageLength * 3 + 2, value.length);
- break;
- case 0x80:
- data.powerMOSTemp = value[1] * 0x100 + value[2];
- if (data.powerMOSTemp > 100) data.powerMOSTemp = 100 - data.powerMOSTemp;
- value = value.slice(3, value.length);
- break;
- case 0x81:
- data.batteryChamberTemp = value[1] * 0x100 + value[2];
- if (data.batteryChamberTemp > 100) data.batteryChamberTemp = 100 - data.batteryChamberTemp;
- value = value.slice(3, value.length);
- break;
- case 0x82:
- data.temp = value[1] * 0x100 + value[2];
- if (data.temp > 100) data.temp = 100 - data.temp;
- value = value.slice(3, value.length);
- break;
- case 0x83:
- data.voltage = Math.round(value[1] * 0x100 + value[2]) / 100;
- value = value.slice(3, value.length);
- break;
- case 0x84:
- data.chargeState = 0;
- _value = value[1] * 0x100 + value[2];
- if (_value > 10000) {
- data.current = (_value - 10000) * 0.01 * -1;
- data.chargeState = 2;
- } else if (_value < 10000) {
- data.current = (10000 - _value) * 0.01;
- data.chargeState = 1;
- }
- value = value.slice(3, value.length);
- break;
- case 0x85:
- data.quantity = value[1];
- data.soc = value[1];
- value = value.slice(2, value.length);
- break;
- case 0x86:
- data.tempCount = value[1];
- value = value.slice(2, value.length);
- break;
- case 0x87:
- data.cycle = value[1] * 0x100 + value[2];
- value = value.slice(3, value.length);
- break;
- case 0x89:
- data.totalCirculatingCapacity = value[1] * 0x1000000 + value[2] * 0x10000 + value[3] * 0x100 + value[4];
- value = value.slice(5, value.length);
- break;
- case 0x8a:
- data.count = value[1] * 0x100 + value[2];
- value = value.slice(3, value.length);
- break;
- case 0x8b:
- data.alarmState = [];
- if (((value[2] >> 0) & 1) == 1) data.alarmState.push('低容量报警');
- if (((value[2] >> 1) & 1) == 1) data.alarmState.push('MOS管超温报警');
- if (((value[2] >> 2) & 1) == 1) data.alarmState.push('充电过压报警');
- if (((value[2] >> 3) & 1) == 1) data.alarmState.push('放电欠压报警');
- if (((value[2] >> 4) & 1) == 1) data.alarmState.push('电池超温报警');
- if (((value[2] >> 5) & 1) == 1) data.alarmState.push('充电过流报警');
- if (((value[2] >> 6) & 1) == 1) data.alarmState.push('放电过流报警');
- if (((value[2] >> 7) & 1) == 1) data.alarmState.push('电芯压差报警');
- if (((value[1] >> 0) & 1) == 1) data.alarmState.push('电池箱内超温报警');
- if (((value[1] >> 1) & 1) == 1) data.alarmState.push('电池低温报警');
- if (((value[1] >> 2) & 1) == 1) data.alarmState.push('单体过压报警');
- if (((value[1] >> 3) & 1) == 1) data.alarmState.push('单体欠压报警');
- if (((value[1] >> 4) & 1) == 1) data.alarmState.push('309_A保护');
- if (((value[1] >> 5) & 1) == 1) data.alarmState.push('309_B保护');
- value = value.slice(3, value.length);
- break;
- case 0x8c:
- data.chargeProtectState = (value[2] >> 0) & 1;
- data.dischargeProtectState = (value[2] >> 1) & 1;
- data.equilibrium = (value[2] >> 2) & 1;
- data.disconnectState = (value[2] >> 3) & 1;
- value = value.slice(3, value.length);
- break;
- case 0x8e:
- value = value.slice(3, value.length);
- break;
- case 0x8f:
- value = value.slice(3, value.length);
- break;
- case 0x90:
- value = value.slice(3, value.length);
- break;
- case 0x91:
- case 0x92:
- case 0x93:
- case 0x94:
- case 0x95:
- case 0x96:
- case 0x97:
- case 0x98:
- case 0x99:
- case 0x9a:
- case 0x9b:
- case 0x9c:
- value = value.slice(3, value.length);
- break;
- case 0x9d:
- value = value.slice(2, value.length);
- break;
- case 0x9e:
- case 0x9f:
- case 0xa0:
- case 0xa1:
- case 0xa2:
- case 0xa3:
- case 0xa4:
- case 0xa5:
- case 0xa6:
- case 0xa7:
- case 0xa8:
- value = value.slice(3, value.length);
- break;
- case 0xa9:
- value = value.slice(2, value.length);
- break;
- case 0xaa:
- // 电池容量
- data.capacity = (value[1] << 24) | (value[2] << 16) | (value[3] << 8) | value[4];
- value = value.slice(5, value.length);
- break;
- case 0xab:
- case 0xac:
- value = value.slice(2, value.length);
- break;
- case 0xad:
- value = value.slice(3, value.length);
- break;
- case 0xae:
- case 0xaf:
- value = value.slice(2, value.length);
- break;
- case 0xb0:
- value = value.slice(3, value.length);
- break;
- case 0xb1:
- value = value.slice(2, value.length);
- break;
- case 0xb2:
- value = value.slice(11, value.length);
- break;
- case 0xb3:
- value = value.slice(2, value.length);
- break;
- case 0xb4:
- value = value.slice(9, value.length);
- break;
- case 0xb5:
- value = value.slice(5, value.length);
- break;
- case 0xb6:
- value = value.slice(5, value.length);
- break;
- case 0xb7:
- // 软件版本号 15bit
- data.firmware = '';
- for (let i = 1; i <= 15; i++) {
- data.firmware += String.fromCharCode(value[i]);
- }
- value = value.slice(16, value.length);
- break;
- case 0xb8:
- value = value.slice(2, value.length);
- break;
- case 0xb9:
- value = value.slice(5, value.length);
- break;
- case 0xba:
- value = value.slice(25, value.length);
- break;
- default:
- value = [];
- }
- }
- }
- return data;
- }
- }
- return false;
- }
- function readData(device, value, data) {
- value = Array.from(new Int8Array(value))
- .map((p) => String.fromCharCode(p))
- .join('');
- if (value[value.length - 1] == ')') {
- value = readPart.concat(value);
- readPart = '';
- } else if (value[0] == '(') {
- readPart = value;
- } else {
- readPart = readPart.concat(value);
- }
- if (value[0] == '(' && value[value.length - 1] == ')') {
- value = value.slice(1, value.length - 1);
- if (value.slice(0, 12) == device.mac_id) {
- value = value.slice(12, value.length);
- switch (value.slice(0, 4)) {
- case 'BP00':
- return readDataBP00(value.slice(4, value.length), data);
- case 'BS50':
- return readDataBS50(value.slice(4, value.length), data);
- }
- }
- }
- return false;
- }
- /**
- * cmd: 命令字 02:写
- */
- function BMSCommand(data, cmd, type = 0) {
- // 帧来源: 01
- // 传输类型: 00
- const length = data.length + 18;
- var data = [0x4e, 0x57, parseInt(length / 0x100), parseInt(length % 0x100), 0x00, 0x00, 0x00, 0x00, cmd, 0x01, type].concat(data).concat([0x00, 0x00, 0x00, 0x00, 0x68]);
- const sum = data.reduce((p, c) => p + c);
- data.push(parseInt(sum / 0x1000000));
- data.push(parseInt((sum % 0x1000000) / 0x10000));
- data.push(parseInt((sum % 0x10000) / 0x100));
- data.push(parseInt(sum % 0x100));
- console.log(data);
- return data;
- }
- function BMSRead() {
- return BMSCommand([0x00], 0x06, 0);
- }
- function BMSTurnOn() {
- return BMSCommand([0xac, 1], 0x02, 1);
- }
- function BMSTurnOff() {
- return BMSCommand([0xac, 0], 0x02, 1);
- }
- function bmsChargingMOS(value) {
- return BMSCommand([0xab, value], 0x02, 0);
- }
- function bmsDischargeMOS(value) {
- return BMSCommand([0xac, value], 0x02, 0);
- }
- function sendData(device, cmd, data = []) {
- return (
- '(' +
- device.mac_id +
- cmd +
- data
- .map((p) => ('00' + p.toString(16)).substr(p.toString(16).length))
- .join('')
- .toUpperCase() +
- ')'
- )
- .split('')
- .map((p) => p.charCodeAt(0));
- }
- function sendDataAE00(device, data) {
- return sendData(device, 'AE00', [data.length % 0x100, parseInt(data.length / 0x100)].concat(data));
- }
- function stateUpdate(device, deviceId) {
- return [sendData(device, 'AU20'), sendDataAE00(device, BMSRead())];
- }
- function turnOn(device, deviceId) {
- return [sendDataAE00(device, BMSTurnOn())];
- }
- function turnOff(device, deviceId) {
- return [sendDataAE00(device, BMSTurnOff())];
- }
- function bmsInfo(device, deviceId, info) {
- return false;
- }
- function bmsSet(device, deviceId, name, vars) {
- return false;
- }
- module.exports = {
- readServiceID: readServiceID,
- readID: readID,
- writeServiceID: writeServiceID,
- writeID: writeID,
- acceptDevice: acceptDevice,
- isDevice: isDevice,
- readData: readData,
- stateUpdate: stateUpdate,
- turnOn: turnOn,
- turnOff: turnOff,
- bmsInfo: bmsInfo,
- bmsSet: bmsSet,
- BMSCommand: BMSCommand,
- BMSRead: BMSRead,
- BMSTurnOn: BMSTurnOn,
- BMSTurnOff: BMSTurnOff,
- BMSReply: BMSReply,
- bmsChargingMOS: bmsChargingMOS,
- bmsDischargeMOS: bmsDischargeMOS
- };
|