UNPKG

ojousima.ruuvi_endpoints.ts

Version:
108 lines (107 loc) 4.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.dffeunencrypter = exports.dffeparser = void 0; var aes_js_1 = require("aes-js"); var ruuvitagbroadcast_1 = require("./ruuvitagbroadcast"); var dataFormatStart = 0; var dataFormatEnd = dataFormatStart + 1; var versionStart = dataFormatEnd; var versionEnd = versionStart + 1; var versionInvalid = 255; var addressStart = versionEnd; var addressEnd = addressStart + 6; var addressInvalid = 0xffffffffffff; var humidityStart = addressEnd; var humidityEnd = humidityStart + 1; var humidityInvalid = 255; var temperatureStart = humidityEnd; var temperatureEnd = temperatureStart + 2; var temperatureInvalid = -32768; var pressureStart = temperatureEnd; var pressureEnd = pressureStart + 2; var pressureInvalid = 65535; var batteryStart = pressureEnd; var batteryEnd = batteryStart + 2; var sequenceStart = batteryEnd; var sequenceEnd = sequenceStart + 2; var sequenceInvalid = 0xffff; /* * @brief Parse FE data * * Throws error if header byte is not @c 0xFE or version byte is not @c 0x02 * * @param data complete manufacturer data to be parsed, starting from header byte * @return Ruuvi data payload */ var dffeparser = function (data) { if (data.length < addressEnd - 1 || 0xfe !== data[0]) { throw new Error('Not DF5 data'); } if (0x02 !== data[versionStart]) { throw new Error('Unsupported version ' + data[versionStart].toString(16)); } var robject = new ruuvitagbroadcast_1.RuuviTagBroadcast(); robject.dataFormat = data[dataFormatStart]; var humidity = data[humidityStart]; humidity /= 2; // scale robject.humidityRh = humidity; var temperatureBytes = data.slice(temperatureStart, temperatureEnd); var temperature = temperatureBytes[0]; // Full degrees temperature += temperatureBytes[1] / 100.0; // Decimals if (temperature > 128) { // Ruuvi format, sign bit + value temperature = temperature - 128; temperature = 0 - temperature; } robject.temperatureC = temperature; var pressureBytes = data.slice(pressureStart, pressureEnd); // uint16_t pascals var pressure = pressureBytes[0] * 256 + pressureBytes[1]; pressure += 50000; // Ruuvi format robject.pressurePa = pressure; var batteryBytes = data.slice(batteryStart, batteryEnd); // millivolts var battery = batteryBytes[0] * 256 + batteryBytes[1]; robject.batteryVoltageV = battery / 1000.0; var sequenceBytes = data.slice(sequenceStart, sequenceEnd); var sequence = sequenceBytes[0] * 256 + sequenceBytes[1]; robject.measurementSequence = sequenceInvalid === sequence ? null : sequence; var addressBytes = data.slice(addressStart, addressEnd); // Sorry, but lint says so. var address = addressBytes[0] * 256 * 256 * 256 * 256 * 256 + addressBytes[1] * 256 * 256 * 256 * 256 + addressBytes[2] * 256 * 256 * 256 + addressBytes[3] * 256 * 256 + addressBytes[4] * 256 + addressBytes[5]; robject.mac = addressInvalid === address ? null : address; return robject; }; exports.dffeparser = dffeparser; /* * @brief Unencrypt data with the basepassword and unique password. * * For example data version 2 has default password of "ruuvi.com\0" + device mac. * Convert ASCII (NOT UTF-8!) string of "ruuvi.com\0" to Uint8Array and use it as a basepw * Add device mac as unique pw. Returns complete data in unencrypted form as Uint8Array * * @param data complete manufacturer data to be unencrypted, starting from header byte * @param basepw: Base password used in encryption * @param unitpw: Unit-specific password used in encryption. * @return unencrypted FE data. * @warning Be careful when converting strings to Uint8Array to avoid UTF-8 encoded values. */ var dffeunencrypter = function (data, basepw, unitpw) { if (16 !== basepw.length + unitpw.length) { throw new Error('Invalid base+unit password length. Expected 16, got ' + (basepw.length + unitpw.length).toString()); } var key = new Uint8Array(basepw.length + unitpw.length); key.set(basepw); key.set(unitpw, basepw.length); var aesEcb = new aes_js_1.ModeOfOperation.ecb(key); // All fe data starts with header + version, followed by encrypted 16-byte payload var encryptedBytes = data.subarray(2, 2 + 16); // Since electronic codebook does not store state, we can // reuse the same instance. var decryptedBytes = aesEcb.decrypt(encryptedBytes); return decryptedBytes; }; exports.dffeunencrypter = dffeunencrypter;