UNPKG

@constructorfleet/ultimate-govee

Version:

Library for interacting with Govee devices written in Typescript.

191 lines 8.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Decoder = exports.postProcessing = exports.evaluateComparison = void 0; const common_1 = require("../../../../common"); const decoder_constants_1 = require("./decoder.constants"); const device_condition_1 = require("./device.condition"); const property_condition_1 = require("./property.condition"); const common_2 = require("@nestjs/common"); const reverseHexData = (hexData, length) => (0, common_1.chunk)(hexData.slice(0, length).split(''), 2) .reverse() .reduce((acc, value) => `${acc}${value.join('')}`, ''); const valueFromHexString = (hexData, offset, length, reverse, canBeNegative, isFloat) => { const hexValue = hexData.slice(offset, offset + length); const value = reverse === true ? reverseHexData(hexValue, length) : hexValue; const parsedValue = isFloat === true ? parseFloat(value) : parseInt(value, 16); if (canBeNegative === true) { if (length <= 2 && parsedValue > 128) { return parsedValue - 256; } if (length === 4 && parsedValue > 32767) { return parsedValue - 65536; } } return parsedValue; }; const bcfValueFromHexString = (hexData, offset, length, reverse, canBeNegative, isFloat) => { const value = valueFromHexString(hexData, offset, length, reverse, canBeNegative, isFloat); const dValue = ((value >> 8) * 100 + (value & 0xff)) / 100; return dValue; }; const evaluateComparison = (operator, operand, operant) => { switch (operator) { case decoder_constants_1.Equals: return operand === operant; case decoder_constants_1.GreaterThanEqual: return operand >= operant; case decoder_constants_1.GreaterThan: return operand > operant; case decoder_constants_1.LessThanEqual: return operand <= operant; case decoder_constants_1.LessThan: return operand < operant; default: return false; } }; exports.evaluateComparison = evaluateComparison; const postProcessing = (value, operations, calibration) => { if (operations.length === 0) { return value; } if (typeof operations[1] !== 'number' && operations[1] !== decoder_constants_1.Calibration) { throw new Error(`Invalid post processing sequence, expected a number got ${operations[1]}`); } const operant = (operations[1] === decoder_constants_1.Calibration ? calibration : operations[1]) ?? 0; switch (operations[0]) { case decoder_constants_1.GreaterThanEqual: case decoder_constants_1.GreaterThan: case decoder_constants_1.Equals: case decoder_constants_1.LessThanEqual: case decoder_constants_1.LessThan: return (0, exports.evaluateComparison)(operations[0], value, operant) ? (0, exports.postProcessing)(value, operations.slice(2), calibration) : undefined; case decoder_constants_1.BitwiseOr: return (0, exports.postProcessing)(value | operant, operations.slice(2), calibration); case decoder_constants_1.BitwiseAnd: return (0, exports.postProcessing)(value & operant, operations.slice(2), calibration); case decoder_constants_1.MultiplyBy: return (0, exports.postProcessing)(value * operant, operations.slice(2), calibration); case decoder_constants_1.DivideBy: return (0, exports.postProcessing)(value / operant, operations.slice(2), calibration); case decoder_constants_1.Add: return (0, exports.postProcessing)(value + operant, operations.slice(2), calibration); case decoder_constants_1.Substract: return (0, exports.postProcessing)(value - operant, operations.slice(2), calibration); case decoder_constants_1.Modulo: return (0, exports.postProcessing)(value % operant, operations.slice(2), calibration); } }; exports.postProcessing = postProcessing; exports.Decoder = { value_from_hex_string: valueFromHexString, bf_value_from_hex_string: bcfValueFromHexString, matches(device, conditions) { return (0, device_condition_1.deviceMatches)(device, conditions); }, decodeProperties(device, properties) { const logger = new common_2.Logger('Decoder.decodeProperties'); let calibration; return Object.entries(properties) .filter(([_, value]) => value.condition ? (0, property_condition_1.propertyMatches)(device, value.condition) : true) .reduce((decoded, [name, value]) => { logger.debug(`decoding ${name}`); const decodedValue = exports.Decoder.decode(device, value.decoder, value.post_proc, calibration); logger.debug(`decoded ${name} : ${decodedValue}`); if (decodedValue === undefined) { return decoded; } switch (name) { case 'tempc': case '_tempc': decoded.temperature = { ...(decoded.temperature ?? {}), current: decodedValue, calibration: value.post_proc?.includes('.cal') ?? false ? calibration : undefined, }; break; case 'tempc1': case 'tempc2': case 'tempc3': case 'tempc4': case 'tempc5': case 'tempc6': decoded.tempProbes = { ...(decoded.tempProbes ?? {}), ...{ [Number.parseInt(name.slice(-1))]: decodedValue, }, }; break; case 'humidity': decoded.humidity = { current: decodedValue, calibration: value.post_proc?.includes('.cal') ?? false ? calibration : undefined, }; break; case 'battery': decoded.battery = decodedValue; break; case '.cal': calibration = decodedValue; break; case 'hum': decoded.humidity = { ...(decoded.humidity ?? {}), current: decodedValue, calibration: value.post_proc?.includes('.cal') ?? false ? calibration : undefined, }; break; case 'batt': decoded.battery = decodedValue; break; case 'pm25': decoded.pm25 = { ...(decoded.pm25 ?? {}), current: decodedValue, calibration: value.post_proc?.includes('.cal') ?? false ? calibration : undefined, }; break; default: logger.warn(`Unknown property ${name}`); break; } return decoded; }, {}); }, decode(device, decoderArgs, postProcessingOperations, calibation) { let decoder; if (decoderArgs[0].includes('value_from_hex_data')) { if (decoderArgs[0].includes('bf')) { decoder = decoder_constants_1.BCFValueFromHex; } else { decoder = decoder_constants_1.ValueFromHex; } } else { decoder = decoderArgs[0]; } const dataSource = decoderArgs[1]; const args = [ device[dataSource.replace('data', 'Data')], ...decoderArgs.slice(2), ]; const value = exports.Decoder[decoder](args[0], args[1], args[2], args[3], args[4], args[5]); if (postProcessingOperations === undefined) { return value; } return (0, exports.postProcessing)(value, postProcessingOperations, calibation); }, }; //# sourceMappingURL=decoder.js.map