UNPKG

@yachteye/signalk-engineroom-plugin

Version:

Get EngineRoom data from the source (database or other) and add it to the SignalK graph.

556 lines 91.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.IDataType = void 0; const simulator_1 = __importDefault(require("./simulator")); const sql_1 = __importDefault(require("./sql")); const tcp_1 = __importDefault(require("./tcp")); const utils = require('@signalk/nmea0183-utilities'); var IDataType; (function (IDataType) { /** Floating point number. */ IDataType["Number"] = "number"; /** Value between 0 (0%) and 1 (100%) unless specified otherwise. */ IDataType["Ratio"] = "ratio"; /** values 'Running' or 'Off'. */ IDataType["RunningOff"] = "running_off"; /** Fixed value. */ IDataType["Fixed"] = "fixed-value"; /** Integer number. */ IDataType["IntegerNumber"] = "integer-number"; /** Floating point number that gradually decreases. */ IDataType["NumberDecreasing"] = "number-decreasing"; /** Integer status value that should rotate through the values between min/max slowly. */ IDataType["IntegerStatus"] = "integer-status"; /** To be used for complex derived/calculated data. */ IDataType["Other"] = "other"; })(IDataType || (exports.IDataType = IDataType = {})); /** The type of Engine Room to handle. */ var IEngineRoomType; (function (IEngineRoomType) { /** TRON */ IEngineRoomType["Type13758"] = "13758"; /** Alibaba */ IEngineRoomType["Type13774"] = "13774"; })(IEngineRoomType || (IEngineRoomType = {})); /** The propulsion mode (for Type13774) as used in the YE GUI. */ var PropulsionMode; (function (PropulsionMode) { PropulsionMode[PropulsionMode["inactive"] = 0] = "inactive"; PropulsionMode[PropulsionMode["topSpeed"] = 1] = "topSpeed"; PropulsionMode[PropulsionMode["fullDieselElectricCruise"] = 2] = "fullDieselElectricCruise"; PropulsionMode[PropulsionMode["crewSeaTransit"] = 3] = "crewSeaTransit"; PropulsionMode[PropulsionMode["podSlowSpeedCruise"] = 4] = "podSlowSpeedCruise"; PropulsionMode[PropulsionMode["seaMode"] = 5] = "seaMode"; PropulsionMode[PropulsionMode["unknown"] = 999] = "unknown"; })(PropulsionMode || (PropulsionMode = {})); /** * YachtEye Engine Room Plugin. * @param {*} app The SignalK app. * @returns The plugin object. */ module.exports = (app) => { const plugin = { id: 'signalk-engineroom-plugin', name: 'YachtEye EngineRoom plugin', restartPlugin: null, intervalTimer: null, simulator: null, unsubscribes: [], valueHistory: {}, sqlDB: null, amcs: null, lastRawData: { date: -1, data: {}, }, dataDefinitions: [ // GENSET: port, starboard, midship // yachteye.genset.[id].rpm → Hz // Sean Feehan - Chief Engineer - M/Y KISMET: The Generator permanently runs at 1500RPM, so I think a Max of 2000RPM would display a bit better. // @todo: decide what we want to show for RPM (e.g. average?). { path: 'yachteye.genset.port.rpm', type: 'number', unit: 'Hz', min: 0, max: 2000, fractionDigits: 0, displayNameDb: 'GENSET PS ENGINE SPEED' }, { path: 'yachteye.genset.starboard.rpm', type: 'number', unit: 'Hz', min: 0, max: 2000, fractionDigits: 0, displayNameDb: 'GENSET SB ENGINE SPEED' }, { path: 'yachteye.genset.midship.rpm', type: 'number', unit: 'Hz', min: 0, max: 2000, fractionDigits: 0, displayNameDb: 'GENSET CT ENGINE SPEED' }, { path: 'yachteye.genset.rpm', type: 'number', unit: 'Hz', min: 0, max: 2000, fractionDigits: 0, displayNameDb: 'N.A. AVG' }, // yachteye.genset.[id].wattage // Sean Feehan - Chief Engineer - M/Y KISMET: Maximum will be 724kw, so a Max of 775/800kW would be good for the display. { path: 'yachteye.genset.port.wattage', type: 'number', unit: 'W', min: 0, max: 800 * 1000, fractionDigits: 0, displayNameDb: 'PMS GENSET PS GENERATOR POWER' }, { path: 'yachteye.genset.starboard.wattage', type: 'number', unit: 'W', min: 0, max: 800 * 1000, fractionDigits: 0, displayNameDb: 'PMS GENSET SB GENERATOR POWER' }, { path: 'yachteye.genset.midship.wattage', type: 'number', unit: 'W', min: 0, max: 800 * 1000, fractionDigits: 0, displayNameDb: 'PMS GENSET CT GENERATOR POWER' }, { path: 'yachteye.genset.wattage', type: 'number', unit: 'W', min: 0, max: 3 * 800 * 1000, fractionDigits: 0, displayNameDb: 'N.A. SUM' }, // yachteye.genset.[id].state → “running” or “off” // Derived from the RPM value. { path: 'yachteye.genset.port.state', type: 'running_off', displayNameDb: 'N.A. DERIVED' }, { path: 'yachteye.genset.starboard.state', type: 'running_off', displayNameDb: 'N.A. DERIVED' }, { path: 'yachteye.genset.midship.state', type: 'running_off', displayNameDb: 'N.A. DERIVED' }, // Save the DB info too for now. // { path: 'yachteye.genset.port.running', type: 'running_off', displayNameDb: 'GENSET PS ENGINE RUNNING' }, // { path: 'yachteye.genset.starboard.running', type: 'running_off', displayNameDb: 'GENSET SB ENGINE RUNNING' }, // { path: 'yachteye.genset.midship.running', type: 'running_off', displayNameDb: 'GENSET CT ENGINE RUNNING' }, // yachteye.genset.[id].voltage → V { path: 'yachteye.genset.port.voltage', type: 'number', unit: 'V', min: 0, max: 500, fractionDigits: 0, displayNameDb: 'PMS GENSET PS GENERATOR VOLTAGE' }, { path: 'yachteye.genset.starboard.voltage', type: 'number', unit: 'V', min: 0, max: 500, fractionDigits: 0, displayNameDb: 'PMS GENSET SB GENERATOR VOLTAGE' }, { path: 'yachteye.genset.midship.voltage', type: 'number', unit: 'V', min: 0, max: 500, fractionDigits: 0, displayNameDb: 'PMS GENSET CT GENERATOR VOLTAGE' }, { path: 'yachteye.genset.voltage', type: 'number', unit: 'V', min: 0, max: 500, fractionDigits: 0, displayNameDb: 'N.A. AVG' }, // yachteye.genset.[id].current → A // Note: we also have L2 and L3 values. // Tim Schroeder (Luerssen): L1, L2 and L3 are pretty much the same. But not sure if this is on any interest as I think the total current might be the best? // Sean Feehan - Chief Engineer - M/Y KISMET: 1000A would be a more sensible maximum here. { path: 'yachteye.genset.port.current', type: 'number', unit: 'A', min: 0, max: 1000, fractionDigits: 0, displayNameDb: 'PMS GENSET PS GENERATOR CURRENT L1' }, { path: 'yachteye.genset.starboard.current', type: 'number', unit: 'A', min: 0, max: 1000, fractionDigits: 0, displayNameDb: 'PMS GENSET SB GENERATOR CURRENT L1' }, { path: 'yachteye.genset.midship.current', type: 'number', unit: 'A', min: 0, max: 1000, fractionDigits: 0, displayNameDb: 'PMS GENSET CT GENERATOR CURRENT L1' }, { path: 'yachteye.genset.current', type: 'number', unit: 'A', min: 0, max: 3 * 1000, fractionDigits: 0, displayNameDb: 'N.A. SUM' }, // yachteye.genset.[id].sineWaveFrequency → Hz // Sean Feehan - Chief Engineer - M/Y KISMET: 50Hz is the permanent frequency here. A 55Hz maximum should display quite nicely. { path: 'yachteye.genset.port.sineWaveFrequency', type: 'number', unit: 'Hz', min: 0, max: 55, fractionDigits: 2, displayNameDb: 'PMS GENSET PS GENERATOR FREQUENCY' }, { path: 'yachteye.genset.starboard.sineWaveFrequency', type: 'number', unit: 'Hz', min: 0, max: 55, fractionDigits: 2, displayNameDb: 'PMS GENSET SB GENERATOR FREQUENCY' }, { path: 'yachteye.genset.midship.sineWaveFrequency', type: 'number', unit: 'Hz', min: 0, max: 55, fractionDigits: 2, displayNameDb: 'PMS GENSET CT GENERATOR FREQUENCY' }, { path: 'yachteye.genset.sineWaveFrequency', type: 'number', unit: 'Hz', min: 0, max: 55, fractionDigits: 2, displayNameDb: 'N.A. AVG' }, // yachteye.genset.[id].wasteHeatRecoveryTemperature → K // @todo: Not found in the database. // { path: 'yachteye.genset.port.wasteHeatRecoveryTemperature', type: 'number', unit: 'K', min: utils.transform(40, 'C', 'K'), max: utils.transform(85, 'C', 'K'), fractionDigits: 1, displayNameDb: 'TODO' }, // { path: 'yachteye.genset.starboard.wasteHeatRecoveryTemperature', type: 'number', unit: 'K', min: utils.transform(40, 'C', 'K'), max: utils.transform(85, 'C', 'K'), fractionDigits: 1, displayNameDb: 'TODO' }, // { path: 'yachteye.genset.midship.wasteHeatRecoveryTemperature', type: 'number', unit: 'K', min: utils.transform(40, 'C', 'K'), max: utils.transform(85, 'C', 'K'), fractionDigits: 1, displayNameDb: 'TODO' }, // ENGINE: port, starboard // yachteye.engine.[id].state → “running” or “off” { path: 'yachteye.engine.port.state', type: 'running_off', displayNameDb: 'M/E PS RUNNING' }, { path: 'yachteye.engine.starboard.state', type: 'running_off', displayNameDb: 'M/E SB RUNNING' }, // yachteye.engine.[id].rpm → Hz // Sean Feehan - Chief Engineer - M/Y KISMET: A Max of 2000RPM would display a bit better. Typical Main Engine RPM is 950-1500RPM. { path: 'yachteye.engine.port.rpm', type: 'number', unit: 'Hz', min: 0, max: 2000, fractionDigits: 0, displayNameDb: 'M/E PS ENGINE SPEED' }, { path: 'yachteye.engine.starboard.rpm', type: 'number', unit: 'Hz', min: 0, max: 2000, fractionDigits: 0, displayNameDb: 'M/E SB ENGINE SPEED' }, // yachteye.engine.[id].load → ratio (%) { path: 'yachteye.engine.port.load', type: 'ratio', unit: '%', displayNameDb: 'M/E PS ENGINE LOAD' }, { path: 'yachteye.engine.starboard.load', type: 'ratio', unit: '%', displayNameDb: 'M/E SB ENGINE LOAD' }, // yachteye.engine.[id].coolantTemperature → K // Sean Feehan - Chief Engineer - M/Y KISMET: 105/110°C would be a more sensible maximum here. { path: 'yachteye.engine.port.coolantTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(105, 'C', 'K'), fractionDigits: 1, displayNameDb: 'M/E PS COOLANT TEMP' }, { path: 'yachteye.engine.starboard.coolantTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(105, 'C', 'K'), fractionDigits: 1, displayNameDb: 'M/E SB COOLANT TEMP' }, // yachteye.engine.[id].exhaustTemperature → K // Sean Feehan - Chief Engineer - M/Y KISMET: There is one Average Field for each main engine that gives an Average Exhaust Temperature Value. Please use that reading. The displayed maximum for this should be somewhere around 700°C. { path: 'yachteye.engine.port.exhaustTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(700, 'C', 'K'), fractionDigits: 1, displayNameDb: 'M/E PS EXHAUST AVERAGE TEMP' }, { path: 'yachteye.engine.starboard.exhaustTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(700, 'C', 'K'), fractionDigits: 1, displayNameDb: 'M/E SB EXHAUST AVERAGE TEMP' }, // ESS (Energy Storage System). // The 'yachteye.ess.wattage' will be calculated from Voltage and Current values. { path: 'yachteye.ess.wattage', type: IDataType.Number, unit: 'W', min: 600 * 6 * -80, max: 700 * 6 * 150, displayNameDb: 'N.A. PRODUCT' }, // Not found in the database, we will use a fixed value. // Sean Feehan - Chief Engineer - M/Y KISMET: Total Capacity is ~500kWh. { path: 'yachteye.ess.capacity', type: IDataType.Fixed, unit: 'Wh', fixed: 500 * 1000, displayNameDb: 'N.A. FIXED' }, // @todo: there are 34 ESS voltage value, which one? (WHERE CONVERT(VARCHAR(MAX), [DisplayName]) LIKE '% ESS %' AND [Unit] = 'V'). // Sean Feehan - Chief Engineer - M/Y KISMET: You can put 600-700V as the range for this. It might also be worth noting that this is DC voltage as opposed to AC. So e.g. could read: 650V DC. { path: 'yachteye.ess.port.1.voltage', type: 'number', unit: 'V', min: 600, max: 700, fractionDigits: 0, displayNameDb: 'MD CONVERTER 2 PS ESS PACK 1 PACK VOLTAGE' }, { path: 'yachteye.ess.port.2.voltage', type: 'number', unit: 'V', min: 600, max: 700, fractionDigits: 0, displayNameDb: 'MD CONVERTER 2 PS ESS PACK 2 PACK VOLTAGE' }, { path: 'yachteye.ess.port.3.voltage', type: 'number', unit: 'V', min: 600, max: 700, fractionDigits: 0, displayNameDb: 'MD CONVERTER 2 PS ESS PACK 3 PACK VOLTAGE' }, { path: 'yachteye.ess.starboard.1.voltage', type: 'number', unit: 'V', min: 600, max: 700, fractionDigits: 0, displayNameDb: 'MD CONVERTER 1 SB ESS PACK 1 PACK VOLTAGE' }, { path: 'yachteye.ess.starboard.2.voltage', type: 'number', unit: 'V', min: 600, max: 700, fractionDigits: 0, displayNameDb: 'MD CONVERTER 1 SB ESS PACK 2 PACK VOLTAGE' }, { path: 'yachteye.ess.starboard.3.voltage', type: 'number', unit: 'V', min: 600, max: 700, fractionDigits: 0, displayNameDb: 'MD CONVERTER 1 SB ESS PACK 3 PACK VOLTAGE' }, { path: 'yachteye.ess.voltage', type: 'number', unit: 'V', min: 600, max: 700, fractionDigits: 0, displayNameDb: 'N.A. AVG' }, // @todo: we also have STATE OF CHARGE for each PACK (1-3), assume the SB and PS values are ok to use. { path: 'yachteye.ess.port.stateOfCharge', type: 'ratio', unit: '%', min: 0, max: 1.0, displayNameDb: 'MD CONVERTER 2 PS ESS STATE OF CHARGE' }, { path: 'yachteye.ess.starboard.stateOfCharge', type: 'ratio', unit: '%', min: 0, max: 1.0, displayNameDb: 'MD CONVERTER 1 SB ESS STATE OF CHARGE' }, { path: 'yachteye.ess.stateOfCharge', type: 'ratio', unit: '%', min: 0, max: 1.0, displayNameDb: 'N.A. AVG' }, // yachteye.ess.chargeDischargeRate → "C". // E.g. C/2 = fully charged in two hours, can also be written as 0.5C. For now assume we use the 'C/x' format and store the value of x. // Assume Lithium with value 2. // Sean Feehan - Chief Engineer - M/Y KISMET: // The C Rate runs between -2.20C to +2.20C. // C is a symbol to measure how fast the batteries are charging/discharging relative to their official rate. A negative C reading means the batteries are being discharged. A positive means they are charging. // If the min and max are set at -2.5C to 2.5C that would be ideal." { path: 'yachteye.ess.port.chargeDischargeRate', type: IDataType.Number, unit: 'C', min: -2.5, max: 2.5, displayNameDb: 'MD CONVERTER 2 PS ESS C-RATE' }, { path: 'yachteye.ess.starboard.chargeDischargeRate', type: IDataType.Number, unit: 'C', min: -2.5, max: 2.5, displayNameDb: 'MD CONVERTER 1 SB ESS C-RATE' }, { path: 'yachteye.ess.chargeDischargeRate', type: IDataType.Number, unit: 'C', min: -2.5, max: 2.5, displayNameDb: 'N.A. AVG' }, // yachteye.ess.current → A // Sean Feehan - Chief Engineer - M/Y KISMET: For this data field the range should be -80A to +150A // Database dump PS values: -106.4 to +204.2 Ampere. Database dump SB values: -174.6 to +165.7 Ampere. { path: 'yachteye.ess.port.1.current', type: 'number', unit: 'A', min: -80, max: 150, fractionDigits: 1, displayNameDb: 'MD CONVERTER 2 PS ESS PACK 1 CURRENT' }, { path: 'yachteye.ess.port.2.current', type: 'number', unit: 'A', min: -80, max: 150, fractionDigits: 1, displayNameDb: 'MD CONVERTER 2 PS ESS PACK 2 CURRENT' }, { path: 'yachteye.ess.port.3.current', type: 'number', unit: 'A', min: -80, max: 150, fractionDigits: 1, displayNameDb: 'MD CONVERTER 2 PS ESS PACK 3 CURRENT' }, { path: 'yachteye.ess.starboard.1.current', type: 'number', unit: 'A', min: -80, max: 150, fractionDigits: 1, displayNameDb: 'MD CONVERTER 1 SB ESS PACK 1 CURRENT' }, { path: 'yachteye.ess.starboard.2.current', type: 'number', unit: 'A', min: -80, max: 150, fractionDigits: 1, displayNameDb: 'MD CONVERTER 1 SB ESS PACK 2 CURRENT' }, { path: 'yachteye.ess.starboard.3.current', type: 'number', unit: 'A', min: -80, max: 150, fractionDigits: 1, displayNameDb: 'MD CONVERTER 1 SB ESS PACK 3 CURRENT' }, { path: 'yachteye.ess.current', type: 'number', unit: 'A', min: 6 * -80, max: 6 * 150, fractionDigits: 1, displayNameDb: 'N.A. SUM' }, // CHILLER: // Sean Feehan - Chief Engineer - M/Y KISMET: The Range for this should be 0-100°C. // @todo: remove these. { path: 'yachteye.chiller.1.returnTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'HRS HOT WATER HEATER 1 RETURN TEMP' }, { path: 'yachteye.chiller.2.returnTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'HRS HOT WATER HEATER 2 RETURN TEMP' }, { path: 'yachteye.chiller.3.returnTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'HRS HOT WATER HEATER 3 RETURN TEMP' }, { path: 'yachteye.chiller.4.returnTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'HRS HOT WATER HEATER 4 RETURN TEMP' }, { path: 'yachteye.chiller.5.returnTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'HRS HOT WATER HEATER 5 RETURN TEMP' }, { path: 'yachteye.chiller.returnTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'N.A. AVG' }, // Sean Feehan - Chief Engineer - M/Y KISMET: The Range for this should be 0-100°C. { path: 'yachteye.chiller.1.supplyTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'SEAWATER TEMPERATURE COMPRESSOR 1' }, { path: 'yachteye.chiller.2.supplyTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'SEAWATER TEMPERATURE COMPRESSOR 2' }, { path: 'yachteye.chiller.3.supplyTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'SEAWATER TEMPERATURE COMPRESSOR 3' }, { path: 'yachteye.chiller.4.supplyTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'SEAWATER TEMPERATURE COMPRESSOR 4' }, { path: 'yachteye.chiller.5.supplyTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'SEAWATER TEMPERATURE COMPRESSOR 5' }, { path: 'yachteye.chiller.supplyTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(100, 'C', 'K'), fractionDigits: 1, displayNameDb: 'N.A. AVG' }, // Chiller water unit (CWU) pressure (Bar). // From this pressure value we will derive the running/off status. // NOTE: During testing with the ETO (2025-06-27) it was found that the values for 2 & 3 seemed to be swapped, so correct that here. // @todo: it is not known if other chiller data is swapped as well, but a swap of supply temperature will be hard to detect. { path: 'yachteye.chiller.1.pressure', type: 'number', unit: 'Pa', min: 0, max: 4 * 100000, fractionDigits: 0, displayNameDb: 'SEA WATER PUMP 1 CWU PRESSURE' }, { path: 'yachteye.chiller.2.pressure', type: 'number', unit: 'Pa', min: 0, max: 4 * 100000, fractionDigits: 0, displayNameDb: 'SEA WATER PUMP 3 CWU PRESSURE' }, // swapped with 3. { path: 'yachteye.chiller.3.pressure', type: 'number', unit: 'Pa', min: 0, max: 4 * 100000, fractionDigits: 0, displayNameDb: 'SEA WATER PUMP 2 CWU PRESSURE' }, // swapped with 2. { path: 'yachteye.chiller.4.pressure', type: 'number', unit: 'Pa', min: 0, max: 4 * 100000, fractionDigits: 0, displayNameDb: 'SEA WATER PUMP 4 CWU PRESSURE' }, { path: 'yachteye.chiller.5.pressure', type: 'number', unit: 'Pa', min: 0, max: 4 * 100000, fractionDigits: 0, displayNameDb: 'SEA WATER PUMP 5 CWU PRESSURE' }, // yachteye.chiller.compressor.[id].state → “running” or “off”. [1,2,3,4,5] { path: 'yachteye.chiller.compressor.1.state', type: 'running_off', displayNameDb: 'N.A. DERIVED' }, { path: 'yachteye.chiller.compressor.2.state', type: 'running_off', displayNameDb: 'N.A. DERIVED' }, { path: 'yachteye.chiller.compressor.3.state', type: 'running_off', displayNameDb: 'N.A. DERIVED' }, { path: 'yachteye.chiller.compressor.4.state', type: 'running_off', displayNameDb: 'N.A. DERIVED' }, { path: 'yachteye.chiller.compressor.5.state', type: 'running_off', displayNameDb: 'N.A. DERIVED' }, // THRUSTER: stern, bow0, bow1 // yachteye.thruster.[id].thrust → ratio (%) // @todo: Not found in the database. // { path: 'yachteye.thruster.stern.thrust', type: 'ratio', unit: '%', displayNameDb: 'TODO' }, // { path: 'yachteye.thruster.bow0.thrust', type: 'ratio', unit: '%', displayNameDb: 'TODO' }, // { path: 'yachteye.thruster.bow1.thrust', type: 'ratio', unit: '%', displayNameDb: 'TODO' }, // yachteye.thruster.[id].load → ratio (%) // check if max of 120% is correct, for now assume it should be 100%, as suggested by Tim Schroeder (Luerssen). // Sean Feehan - Chief Engineer - M/Y KISMET: Stern load: This should just be 0 - 100%. // Sean Feehan - Chief Engineer - M/Y KISMET: Bow load: Yes the max should be 100%. During heavy maoneuvring it could touch 105%, but this is rare so we shouldn't skew the graphic to account for it. { path: 'yachteye.thruster.stern.load', type: 'ratio', unit: '%', min: 0, max: 1.0, fractionDigits: 3, displayNameDb: 'STERN THRUSTER LOAD IN %' }, { path: 'yachteye.thruster.bow0.load', type: 'ratio', unit: '%', min: 0, max: 1.0, fractionDigits: 3, displayNameDb: 'BOW THRUSTER FWD DRIVE MOTOR LOAD' }, { path: 'yachteye.thruster.bow1.load', type: 'ratio', unit: '%', min: 0, max: 1.0, fractionDigits: 3, displayNameDb: 'BOW THRUSTER AFT DRIVE MOTOR LOAD' }, { path: 'yachteye.thruster.bow.load', type: 'ratio', unit: '%', min: 0, max: 1.0, fractionDigits: 3, displayNameDb: 'N.A. AVG' }, // yachteye.thruster.[id].current → A // Tim Schroeder (Luerssen): There are 2 bow thrusters each are set to 432A. The stern thruster has max 470A. { path: 'yachteye.thruster.stern.current', type: 'number', unit: 'A', min: 0, max: 470, fractionDigits: 1, displayNameDb: 'STERN THRUSTER MOTOR CURRENT' }, { path: 'yachteye.thruster.bow0.current', type: 'number', unit: 'A', min: 0, max: 432, fractionDigits: 0, displayNameDb: 'BOW THRUSTER FWD CURRENT' }, { path: 'yachteye.thruster.bow1.current', type: 'number', unit: 'A', min: 0, max: 432, fractionDigits: 0, displayNameDb: 'BOW THRUSTER AFT CURRENT' }, { path: 'yachteye.thruster.bow.current', type: 'number', unit: 'A', min: 0, max: 432, fractionDigits: 0, displayNameDb: 'N.A. AVG' }, // GEARBOX // Sean Feehan - Chief Engineer - M/Y KISMET: If this is the Gearbox Oil Pressure then 0-4 Bar is a good Range. If it is the gearbox clutch pressure then 0-35Bar is good. // DB values are from 0 to 4.6, so use a range [0, 5]. { path: 'yachteye.gearbox.port.oilPressure', type: 'number', unit: 'Pa', min: 0, max: 5 * 100000, fractionDigits: 0, displayNameDb: 'M/E PS GEAR BOX OIL PRESS' }, { path: 'yachteye.gearbox.starboard.oilPressure', type: 'number', unit: 'Pa', min: 0, max: 5 * 100000, fractionDigits: 0, displayNameDb: 'M/E SB GEAR BOX OIL PRESS' }, { path: 'yachteye.gearbox.oilPressure', type: 'number', unit: 'Pa', min: 0, max: 5 * 100000, fractionDigits: 0, displayNameDb: 'N.A. AVG' }, // Sean Feehan - Chief Engineer - M/Y KISMET: You can put 0-65°C for this one. { path: 'yachteye.gearbox.port.oilTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(65, 'C', 'K'), fractionDigits: 1, displayNameDb: 'M/E PS GEAR BOX OIL TEMP' }, { path: 'yachteye.gearbox.starboard.oilTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(65, 'C', 'K'), fractionDigits: 1, displayNameDb: 'M/E SB GEAR BOX OIL TEMP' }, { path: 'yachteye.gearbox.oilTemperature', type: 'number', unit: 'K', min: utils.transform(0, 'C', 'K'), max: utils.transform(65, 'C', 'K'), fractionDigits: 1, displayNameDb: 'N.A. AVG' }, // MultiDrive Converter: // max is defined as 10000 (to be divided by scale 10). For now assume it should be 100%, as suggested by Tim Schroeder (Luerssen). // Sean Feehan - Chief Engineer - M/Y KISMET: Yes. 0-100%. { path: 'yachteye.multiDriveConverter.port.load', type: 'ratio', unit: '%', fractionDigits: 3, displayNameDb: 'PMS MULTI DRIVE 2 PS LOAD' }, { path: 'yachteye.multiDriveConverter.starboard.load', type: 'ratio', unit: '%', fractionDigits: 3, displayNameDb: 'PMS MULTI DRIVE 1 SB LOAD' }, { path: 'yachteye.multiDriveConverter.load', type: 'ratio', unit: '%', fractionDigits: 3, displayNameDb: 'N.A. AVG' }, // Sean Feehan - Chief Engineer - M/Y KISMET: 0-450V would be a more sensible range. { path: 'yachteye.multiDriveConverter.port.voltage', type: 'number', unit: 'V', min: 0, max: 450, fractionDigits: 0, displayNameDb: 'PMS MULTI DRIVE 2 PS VOLTAGE' }, { path: 'yachteye.multiDriveConverter.starboard.voltage', type: 'number', unit: 'V', min: 0, max: 450, fractionDigits: 0, displayNameDb: 'PMS MULTI DRIVE 1 SB VOLTAGE' }, { path: 'yachteye.multiDriveConverter.voltage', type: 'number', unit: 'V', min: 0, max: 450, fractionDigits: 0, displayNameDb: 'N.A. AVG' }, // Sean Feehan - Chief Engineer - M/Y KISMET: 0-450kW is the correct range. { path: 'yachteye.multiDriveConverter.port.wattage', type: 'number', unit: 'W', min: 0, max: 450 * 1000, fractionDigits: 0, displayNameDb: 'PMS MULTI DRIVE 2 PS POWER' }, { path: 'yachteye.multiDriveConverter.starboard.wattage', type: 'number', unit: 'W', min: 0, max: 450 * 1000, fractionDigits: 0, displayNameDb: 'PMS MULTI DRIVE 1 SB POWER' }, { path: 'yachteye.multiDriveConverter.wattage', type: 'number', unit: 'W', min: 0, max: 2 * 450 * 1000, fractionDigits: 0, displayNameDb: 'N.A. SUM' }, // yachteye.multiDriveConverter.powerFactor → number? // database range says [-1, 1] but data from the database dump values are always positive. // Sean Feehan - Chief Engineer - M/Y KISMET: A good range for this would be from 0.5-1.2 Cos Phi. // Actual data is between 0-1 at the moment. { path: 'yachteye.multiDriveConverter.port.powerFactor', type: 'number', unit: '', min: 0.5, max: 1.2, fractionDigits: 2, displayNameDb: 'PMS MULTI DRIVE 2 PS POWER FACTOR' }, { path: 'yachteye.multiDriveConverter.starboard.powerFactor', type: 'number', unit: '', min: 0.5, max: 1.2, fractionDigits: 2, displayNameDb: 'PMS MULTI DRIVE 1 SB POWER FACTOR' }, { path: 'yachteye.multiDriveConverter.powerFactor', type: 'number', unit: '', min: 0.5, max: 1.2, fractionDigits: 2, displayNameDb: 'N.A. AVG' }, // PTO (Power Take-Off): [port, starboard] // yachteye.pto.[id].wattage → W // @todo: Not found in the database. // Sean Feehan - Chief Engineer - M/Y KISMET: PTO is another name for the shaft generator motor. A good range is 0-700kW. I am not sure where this data feed would be taken from however. // { path: 'yachteye.pto.port.wattage', type: 'number', unit: 'W', min: 0, max: 100, fractionDigits: 0, displayNameDb: 'TODO' }, // { path: 'yachteye.pto.starboard.wattage', type: 'number', unit: 'W', min: 0, max: 100, fractionDigits: 0, displayNameDb: 'TODO' }, // yachteye.pto.[id].current → A // @todo: Not found in the database. // { path: 'yachteye.pto.port.current', type: 'number', unit: 'A', min: 2, max: 4, fractionDigits: 1, displayNameDb: 'TODO' }, // { path: 'yachteye.pto.starboard.current', type: 'number', unit: 'A', min: 2, max: 4, fractionDigits: 1, displayNameDb: 'TODO' }, // STABILISER: forwardPort, forwardStarboard, aftPort, aftStarboard { path: 'yachteye.stabiliser.forwardPort.angle', type: IDataType.Number, unit: 'degrees', min: utils.transform(-45, 'deg', 'rad'), max: utils.transform(45, 'deg', 'rad'), displayNameDb: 'STABILIZER FWD PS FIN ANGLE SENSOR' }, { path: 'yachteye.stabiliser.forwardStarboard.angle', type: IDataType.Number, unit: 'degrees', min: utils.transform(-45, 'deg', 'rad'), max: utils.transform(45, 'deg', 'rad'), displayNameDb: 'STABILIZER FWD SB FIN ANGLE SENSOR' }, { path: 'yachteye.stabiliser.aftPort.angle', type: IDataType.Number, unit: 'degrees', min: utils.transform(-45, 'deg', 'rad'), max: utils.transform(45, 'deg', 'rad'), displayNameDb: 'STABILIZER AFT PS FIN ANGLE SENSOR' }, { path: 'yachteye.stabiliser.aftStarboard.angle', type: IDataType.Number, unit: 'degrees', min: utils.transform(-45, 'deg', 'rad'), max: utils.transform(45, 'deg', 'rad'), displayNameDb: 'STABILIZER AFT SB FIN ANGLE SENSOR' }, // PROPELLER: [port, starboard] // Sean Feehan - Chief Engineer - M/Y KISMET: A Max of 330RPM would display a bit better. Typical Shaft RPM is 150-250RPM. { path: 'yachteye.propellor.port.rpm', type: 'number', unit: 'Hz', min: 0, max: 330, fractionDigits: 0, displayNameDb: 'M/E PS SHAFT SPEED' }, { path: 'yachteye.propellor.starboard.rpm', type: 'number', unit: 'Hz', min: 0, max: 330, fractionDigits: 0, displayNameDb: 'M/E SB SHAFT SPEED' }, // yachteye.propellor.[id].corePitch → ratio (%) { path: 'yachteye.propellor.port.corePitch', type: 'ratio', unit: '%', min: -1, displayNameDb: 'CPP SYSTEM PS PITCH ORDER' }, { path: 'yachteye.propellor.starboard.corePitch', type: 'ratio', unit: '%', min: -1, displayNameDb: 'CPP SYSTEM SB PITCH ORDER' }, // To be determined with @Fabio Pizzella // yachteye.path.[id].direction → Special path used to render the dataflow. See below. ], dataDefinitions_13774: [ // Speed - From the regular NMEA (navigation.speedOverGround). // fuel remaining %. { path: 'yachteye.fuel.currentLevel', type: IDataType.Ratio, unit: '%', fractionDigits: 2, displayNameDb: 'N.A. Calculated' }, // @todo: assume this is calculated. // Total Remaining Fuel (m3). // {Type:2,Unix:1738867084,Key:Total Remaining Fuel,Value:0.0,Unit:m3} { path: 'yachteye.fuel.remaining', type: IDataType.NumberDecreasing, unit: 'm3', min: 0, max: 819.60, displayNameDb: '', startVal: 14 }, // The capacity is derived from a photo of the AMCS sent by the AV/IT, it showed 819.60m3 as Total Fuel Capacity. { path: 'yachteye.fuel.capacity', type: IDataType.Fixed, unit: 'm3', fixed: 819.60, fractionDigits: 3, displayNameDb: '' }, // fuel used in last 24 hrs. @todo: not clear where this data is supposed to come from. { path: 'yachteye.fuel.usage.24h', type: IDataType.Other, unit: 'm3', displayNameDb: 'N.A. Calculated' }, // The average value of 'yachteye.fuel.remaining', calculated to compensate for the noisy data for 'yachteye.fuel.remaining'. { path: 'yachteye.fuel.remainingFuelAverage', type: IDataType.Number, unit: 'm3', min: 0, max: 819.60, displayNameDb: 'N.A. Calculated' }, // Array with the last N 'yachteye.fuel.remaining' values, to calculate the 'yachteye.fuel.remainingFuelAverage'. { path: 'yachteye.fuel.remainingFuelHistory', type: IDataType.Other, unit: 'm3', displayNameDb: 'N.A. Calculated' }, // Mode: Inactive (0), top-speed (1), full-diesel-electric-cruise (2), crew-sea-transit (3), pod-slow-speed-cruise (4), sea-mode (5). // Propulsion Mode (Drive Mode) - Kongsberg. { path: 'yachteye.engineroom.mode', type: IDataType.IntegerStatus, unit: '', min: 0, max: 5, displayNameDb: '', startVal: 0 }, // Top speed. // max speed 24 kn { path: 'yachteye.engineroom.mode.1.max-speed', type: IDataType.Fixed, unit: 'm/s', fixed: (24 * 1852) / 3600, displayNameDb: '' }, // Full diesel electric cruise. // max speed 18 kn { path: 'yachteye.engineroom.mode.2.max-speed', type: IDataType.Fixed, unit: 'm/s', fixed: (18 * 1852) / 3600, displayNameDb: '' }, // Crew sea transit. // max speed 18 kn { path: 'yachteye.engineroom.mode.3.max-speed', type: IDataType.Fixed, unit: 'm/s', fixed: (18 * 1852) / 3600, displayNameDb: '' }, // POD slow speed cruise. // max speed 12 kn { path: 'yachteye.engineroom.mode.4.max-speed', type: IDataType.Fixed, unit: 'm/s', fixed: (12 * 1852) / 3600, displayNameDb: '' }, // Sea mode. // max speed 22 kn according to the ETO and the live data. { path: 'yachteye.engineroom.mode.5.max-speed', type: IDataType.Fixed, unit: 'm/s', fixed: (22 * 1852) / 3600, displayNameDb: '' }, // Generator 1,2,3,4,5: // load % // Max. output power is 1,850kWe { path: 'yachteye.genset.1.load', type: IDataType.Ratio, unit: '%', fractionDigits: 3, displayNameDb: 'N.A. Calculated' }, { path: 'yachteye.genset.2.load', type: IDataType.Ratio, unit: '%', fractionDigits: 3, displayNameDb: 'N.A. Calculated' }, { path: 'yachteye.genset.3.load', type: IDataType.Ratio, unit: '%', fractionDigits: 3, displayNameDb: 'N.A. Calculated' }, { path: 'yachteye.genset.4.load', type: IDataType.Ratio, unit: '%', fractionDigits: 3, displayNameDb: 'N.A. Calculated' }, { path: 'yachteye.genset.5.load', type: IDataType.Ratio, unit: '%', fractionDigits: 3, displayNameDb: 'N.A. Calculated' }, // fuel consumption 0 -300 litre/hour. // { path: 'yachteye.genset.1.fuelRate', type: IDataType.Number, unit: 'm3/s', min: 0, max: 300 / 1000 / 3600, fractionDigits: 8, displayNameDb: '' }, // { path: 'yachteye.genset.2.fuelRate', type: IDataType.Number, unit: 'm3/s', min: 0, max: 300 / 1000 / 3600, fractionDigits: 8, displayNameDb: '' }, // { path: 'yachteye.genset.3.fuelRate', type: IDataType.Number, unit: 'm3/s', min: 0, max: 300 / 1000 / 3600, fractionDigits: 8, displayNameDb: '' }, // { path: 'yachteye.genset.4.fuelRate', type: IDataType.Number, unit: 'm3/s', min: 0, max: 300 / 1000 / 3600, fractionDigits: 8, displayNameDb: '' }, // { path: 'yachteye.genset.5.fuelRate', type: IDataType.Number, unit: 'm3/s', min: 0, max: 300 / 1000 / 3600, fractionDigits: 8, displayNameDb: '' }, // kW output (to MSB) 0 - 2 kW. // Power Genset 1 (Genset SB OUT) // {Type:2,Unix:1738866968,Key:Power Genset 1 (Genset SB OUT),Value:0.0,Unit:kW} { path: 'yachteye.genset.1.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 1850 * 1000, fractionDigits: 0, displayNameDb: '' }, // Power Genset 2 (Genset SB IN) // {Type:2,Unix:1738866974,Key:Power Genset 2 (Genset SB IN),Value:0.0,Unit:kW} { path: 'yachteye.genset.2.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 1850 * 1000, fractionDigits: 0, displayNameDb: '' }, // Power Genset 3 (Genset CNT) // {Type:2,Unix:1738866982,Key:Power Genset 3 (Genset CNT),Value:0.0,Unit:kW} { path: 'yachteye.genset.3.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 1850 * 1000, fractionDigits: 0, displayNameDb: '' }, // Power Genset 4 (Genset PS IN) // {Type:2,Unix:1738866989,Key:Power Genset 4 (Genset PS IN),Value:0.0,Unit:kW} { path: 'yachteye.genset.4.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 1850 * 1000, fractionDigits: 0, displayNameDb: '' }, // Power Genset 5 (Genset PS OUT) // {Type:2,Unix:1738866996,Key:Power Genset 5 (Genset PS OUT),Value:0.0,Unit:kW} { path: 'yachteye.genset.5.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 1850 * 1000, fractionDigits: 0, displayNameDb: '' }, // MSB (Main Storage Bank) 690V AFT. // MSB 690V AFT to MSB 400V AFT // Power Input MSB 400V AFT // {Type:2,Unix:1738867007,Key:Power Input MSB 400V AFT,Value:0.0,Unit:kW} { path: 'yachteye.msb400v.aft.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 823 * 1000, fractionDigits: 0, displayNameDb: '' }, // MSB (Main Storage Bank) 690V FWD // MSB 690V FWD to MSB 400V FWD // Power Input MSB 400V FWD // {Type:2,Unix:1738867015,Key:Power Input MSB 400V FWD,Value:0.0,Unit:kW} { path: 'yachteye.msb400v.fwd.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 823 * 1000, fractionDigits: 0, displayNameDb: '' }, // MSB (Main Storage Bank) 400V AFT // MSB (Main Storage Bank) 400V FWD // MultiDrive AFT // From MSB (Main Storage Bank) 690V AFT to Multidrive AFT. // Power Input Multidrive AFT // {Type:2,Unix:1738866940,Key:Power Input Multidrive AFT,Value:0.0,Unit:kW} { path: 'yachteye.multiDriveConverter.aft.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 3915 * 1000, fractionDigits: 0, displayNameDb: '' }, // MultiDrive FWD // From MSB (Main Storage Bank) 690V FWD to Multidrive FWD. // Power Input Multidrive FWD // {Type:2,Unix:1738866951,Key:Power Input Multidrive FWD,Value:0.0,Unit:kW} { path: 'yachteye.multiDriveConverter.fwd.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 3915 * 1000, fractionDigits: 0, displayNameDb: '' }, // PTI/PTO PS (PTO is another name for the shaft generator motor) // kW input (from MultiDrive AFT) // Power PTI/O PS // {Type:2,Unix:1738866893,Key:Power PTI/O PS,Value:0.0,Unit:kW} { path: 'yachteye.pti_pto.ps.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 2.6 * 1000, fractionDigits: 0, displayNameDb: '' }, // PTI/PTO SB (PTO is another name for the shaft generator motor) // kW input (from MultiDrive FWD) // Power PTI/O SB // {Type:2,Unix:1738866908,Key:Power PTI/O SB,Value:0.0,Unit:kW} { path: 'yachteye.pti_pto.sb.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 2.6 * 1000, fractionDigits: 0, displayNameDb: '' }, // POD - pod drive propulsion in the centre. // kW value of the POD - total. // {Type:2,Unix:1738866874,Key:Power POD (Total),Value:0.0,Unit:kW} { path: 'yachteye.pod.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 17429 * 1000, fractionDigits: 0, displayNameDb: '' }, // kW input (from MultiDrive AFT) // Power Multidrive AFT POD // {Type:2,Unix:1738866914,Key:Power Multidrive AFT POD,Value:0.0,Unit:kW} { path: 'yachteye.pod.aft.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 1637 * 1000, fractionDigits: 0, displayNameDb: '' }, // kW input (from MultiDrive FWD) // Power Multidrive FWD POD // {Type:2,Unix:1738866931,Key:Power Multidrive FWD POD,Value:0.0,Unit:kW} { path: 'yachteye.pod.fwd.wattage', type: IDataType.Number, unit: 'W', min: 0, max: 1637 * 1000, fractionDigits: 0, displayNameDb: '' }, ], fuelUsedIn24Hours: [], /** * Register with the router. * @param router the router to register with. */ registerWithRouter(router) { router.get('/report', (req, res) => { res.set('Content-Type', 'text/html').send(` <html> <head> <title>Engine Room Data</title> </head> <body> <table style="width: 100%;"> <thead> <tr> <th>ID</th> <th>YachtEye Path</th> <th>Database Metric</th> <th>Raw Value</th> <th>Parsed Value</th> <th>Last Update</th> </tr> </thead> <tbody> ${Object.keys(plugin.lastRawData.data) .map((key) => { const data = plugin.lastRawData.data[key]; return ` <tr> <td>${data.id}</td> <td>${data.path}</td> <td>${data.displayNameDb}</td> <td>${data.value}</td> <td>${data.parsed}</td> <td>${data.lastUpdate}</td> </tr> `; }) .join('')} </tbody> </table> </body> </html>`); }); }, /** * Start the plugin. * @param settings the configuration data entered via the Plugin Config screen. * @param restartPlugin a function that can be called by the plugin to restart itself. */ start: (settings, restartPlugin) => { app.debug(`starting...`); plugin.restartPlugin = restartPlugin; const pluginSettings = settings; const dataDefs = pluginSettings.erType === IEngineRoomType.Type13774 ? plugin.dataDefinitions_13774 : plugin.dataDefinitions; try { dataDefs.forEach((v, i) => { plugin.valueHistory[v.path] = []; if (v.type === 'fixed-value' && v.fixed === undefined) { app.error(`Incorrect data definition: ${JSON.stringify(v)}`); } if (v.type === IDataType.NumberDecreasing && v.startVal === undefined) { app.error(`Incorrect data definition: ${JSON.stringify(v)}`); } if (v.type === IDataType.IntegerStatus && v.startVal === undefined) { app.error(`Incorrect data definition: ${JSON.stringify(v)}`); } }); plugin.fuelUsedIn24Hours = [{ hour: 99, fuelUsed: null, remainingValueAtStart: null, remainingValueLast: null }]; if (pluginSettings.simulator === true) { plugin.simulator = new simulator_1.default(dataDefs); } else if (pluginSettings.erType === IEngineRoomType.Type13758) { plugin.sqlDB = new sql_1.default(settings, plugin.dataDefinitions); } else if (pluginSettings.erType === IEngineRoomType.Type13774) { plugin.amcs = new tcp_1.default(app, pluginSettings, '0.0.0.0', pluginSettings.amcsPort, plugin.dataDefinitions_13774); // Set up a subscription for the raw Propulsion-Mode data. const rawDataPath = 'yachteye.engineroom.rawPropulsionMode'; const localSubscription = { context: 'vessels.self', subscribe: [ { path: rawDataPath, // yachteye.engineroom.mode / yachteye.engineroom.rawPropulsionMode format: 'delta', policy: 'instant', // send all changes as fast as they are received, but no faster than minPeriod. // period: 5 * 1000, // milliseconds. minPeriod: 5 * 1000, // milliseconds. } ] }; app.subscriptionmanager.subscribe(localSubscription, plugin.unsubscribes, (subscriptionError) => { app.error('Error:' + subscriptionError); }, (delta) => { delta.updates.forEach((u) => { app.debug(`update for rawPropulsionMode: ${JSON.stringify(u)}`); if ('values' in u) { u.values.forEach((pv) => { if (pv.path === rawDataPath && typeof pv.value === 'number') { let mode = PropulsionMode.unknown; switch (pv.value) { case 1: // Manual case 2: // Maneuver case 8: // PSMRLA case 9: // PSMRLB case 10: // State 10 case 11: case 12: case 13: case 14: case 15: case 16: // State 16 mode = PropulsionMode.inactive; break; case 5: // Full Speed mode = PropulsionMode.topSpeed; break; case 4: // Electric mode mode = PropulsionMode.fullDieselElectricCruise; break; case 6: // PTO mode mode = PropulsionMode.crewSeaTransit; break; case 7: // POD only mode = PropulsionMode.podSlowSpeedCruise; break; case 3: // Sea mode mode = PropulsionMode.seaMode; break; default: app.error(`Invalid raw propulsion mode: ${pv.value}`); break; } const SkValues = [{ path: 'yachteye.engineroom.mode', value: { latest: mode === PropulsionMode.unknown ? null : mode, history: [] } }]; const delta = { context: 'vessels.self', updates: [{ source: { label: plugin.id }, timestamp: u.timestamp, values: SkValues, }], }; app.handleMessage(plugin.id, delta); } }); } else { app.error(`No 'values' in update for rawPropulsionMode: ${JSON.stringify(u)}`); } }); }); // const xx = { // "source": { "label": "xdrParser-plugin", "type": "NMEA0183", "talker": "II", "sentence": "XDR" }, // "$source": "xdrParser-plugin.II", // "timestamp": "2025-07-01T13:22:06.418Z", // "values": [ // { "path": "yachteye.engineroom.mode", "value": 1 } // ] // }; } else { throw new Error(`Invalid Engine Room type: ${pluginSettings.erType}`); } app.handleMessage(plugin.id, plugin.meta()); plugin.intervalTimer = setInterval(plugin.pollData, settings.interval * 1000, settings); const connectedTo = pluginSettings.simulator ? 'simulator' : pluginSettings.erType === IEngineRoomType.Typ