@constructorfleet/ultimate-govee
Version:
Library for interacting with Govee devices written in Typescript.
191 lines • 8.37 kB
JavaScript
;
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