UNPKG

n8n-nodes-modbus-fccomplete

Version:

n8n nodes for industrial automation with complete Modbus support (FC1-FC4) and intuitive data conversion with scaling options

232 lines 9.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataConversionUtils = void 0; class DataConversionUtils { static convertData(registers, rule) { var _a; try { const result = { name: rule.name, value: null, originalValue: null, dataType: rule.dataType, valid: false, metadata: { byteOrder: rule.byteOrder, scaleFactor: rule.scaleFactor, offset: rule.offset, unitConversion: rule.unitConversion ? `${rule.unitConversion.from} to ${rule.unitConversion.to}` : undefined, }, }; const requiredRegisters = this.getRequiredRegisters(rule.dataType); if (registers.length < rule.startRegister + requiredRegisters) { result.error = `Not enough registers available. Required: ${requiredRegisters}, Available: ${registers.length - rule.startRegister}`; return result; } const dataRegisters = registers.slice(rule.startRegister, rule.startRegister + requiredRegisters); result.originalValue = dataRegisters.length === 1 ? dataRegisters[0] : dataRegisters; switch (rule.dataType) { case 'int16': result.value = this.convertInt16(dataRegisters[0], rule.byteOrder); break; case 'uint16': result.value = this.convertUint16(dataRegisters[0], rule.byteOrder); break; case 'int32': result.value = this.convertInt32(dataRegisters, rule.byteOrder, rule.wordSwap); break; case 'uint32': result.value = this.convertUint32(dataRegisters, rule.byteOrder, rule.wordSwap); break; case 'float32': result.value = this.convertFloat32(dataRegisters, rule.byteOrder, rule.wordSwap); break; case 'scaled': result.value = this.convertScaled(dataRegisters[0], rule); break; case 'bitfield': result.value = this.convertBitfield(dataRegisters[0], rule); break; case 'bcd': result.value = this.convertBCD(dataRegisters[0], rule.byteOrder); break; default: result.error = `Unsupported data type: ${rule.dataType}`; return result; } if (rule.unitConversion && typeof result.value === 'number') { result.value = this.applyUnitConversion(result.value, rule.unitConversion); } if (rule.decimalPlaces !== undefined && typeof result.value === 'number') { result.value = Number(result.value.toFixed(rule.decimalPlaces)); } if ((_a = rule.validation) === null || _a === void 0 ? void 0 : _a.enabled) { const validation = this.validateValue(result.value, rule.validation); result.valid = validation.valid; if (!validation.valid) { result.error = validation.error; } } else { result.valid = true; } return result; } catch (error) { return { name: rule.name, value: null, originalValue: null, dataType: rule.dataType, valid: false, error: error instanceof Error ? error.message : 'Unknown conversion error', metadata: { byteOrder: rule.byteOrder, }, }; } } static getRequiredRegisters(dataType) { switch (dataType) { case 'int16': case 'uint16': case 'scaled': case 'bitfield': case 'bcd': return 1; case 'int32': case 'uint32': case 'float32': return 2; default: return 1; } } static convertInt16(register, byteOrder) { if (register > 32767) { return register - 65536; } return register; } static convertUint16(register, byteOrder) { return register & 0xFFFF; } static convertInt32(registers, byteOrder, wordSwap = false) { const reg0 = wordSwap ? registers[1] : registers[0]; const reg1 = wordSwap ? registers[0] : registers[1]; let value; if (byteOrder === 'big_endian') { value = (reg0 << 16) | (reg1 & 0xFFFF); } else { value = (reg1 << 16) | (reg0 & 0xFFFF); } if (value > 2147483647) { return value - 4294967296; } return value; } static convertUint32(registers, byteOrder, wordSwap = false) { const reg0 = wordSwap ? registers[1] : registers[0]; const reg1 = wordSwap ? registers[0] : registers[1]; if (byteOrder === 'big_endian') { return ((reg0 << 16) | (reg1 & 0xFFFF)) >>> 0; } else { return ((reg1 << 16) | (reg0 & 0xFFFF)) >>> 0; } } static convertFloat32(registers, byteOrder, wordSwap = false) { const buffer = new ArrayBuffer(4); const view = new DataView(buffer); const reg0 = wordSwap ? registers[1] : registers[0]; const reg1 = wordSwap ? registers[0] : registers[1]; if (byteOrder === 'big_endian') { view.setUint16(0, reg0, false); view.setUint16(2, reg1, false); } else { view.setUint16(0, reg1, false); view.setUint16(2, reg0, false); } return view.getFloat32(0, false); } static convertScaled(register, rule) { let value = register; if (rule.scaleFactor !== undefined) { value *= rule.scaleFactor; } if (rule.offset !== undefined) { value += rule.offset; } return value; } static convertBitfield(register, rule) { if (rule.bitMask !== undefined) { const result = register & rule.bitMask; return result; } else if (rule.bitPosition !== undefined) { const bitLength = rule.bitLength || 1; const mask = (1 << bitLength) - 1; const result = (register >> rule.bitPosition) & mask; if (bitLength === 1) { return Boolean(result); } return result; } return register; } static convertBCD(register, byteOrder) { const high = (register >> 8) & 0xFF; const low = register & 0xFF; const highDecimal = ((high >> 4) & 0x0F) * 10 + (high & 0x0F); const lowDecimal = ((low >> 4) & 0x0F) * 10 + (low & 0x0F); return highDecimal * 100 + lowDecimal; } static applyUnitConversion(value, conversion) { const conversionMap = { 'celsius_to_fahrenheit': (val) => (val * 9 / 5) + 32, 'fahrenheit_to_celsius': (val) => (val - 32) * 5 / 9, 'celsius_to_kelvin': (val) => val + 273.15, 'kelvin_to_celsius': (val) => val - 273.15, 'psi_to_bar': (val) => val * 0.0689476, 'bar_to_psi': (val) => val * 14.5038, 'pascal_to_bar': (val) => val * 0.00001, 'bar_to_pascal': (val) => val * 100000, 'gpm_to_lpm': (val) => val * 3.78541, 'lpm_to_gpm': (val) => val * 0.264172, 'cfm_to_cmh': (val) => val * 1.69901, 'cmh_to_cfm': (val) => val * 0.588578, 'hp_to_kw': (val) => val * 0.745699, 'kw_to_hp': (val) => val * 1.34102, 'btu_to_kw': (val) => val * 0.000293071, 'kw_to_btu': (val) => val * 3412.14, }; const conversionKey = `${conversion.from}_to_${conversion.to}`; const converter = conversionMap[conversionKey]; if (converter) { return converter(value); } return value; } static validateValue(value, validation) { if (typeof value === 'number') { if (isNaN(value) && !validation.allowNaN) { return { valid: false, error: 'Value is NaN' }; } if (validation.min !== undefined && value < validation.min) { return { valid: false, error: `Value ${value} is below minimum ${validation.min}` }; } if (validation.max !== undefined && value > validation.max) { return { valid: false, error: `Value ${value} is above maximum ${validation.max}` }; } } return { valid: true }; } static convertMultiple(registers, rules) { return rules.map(rule => this.convertData(registers, rule)); } } exports.DataConversionUtils = DataConversionUtils; //# sourceMappingURL=DataConversionUtils.js.map