UNPKG

@canboat/visual-analyzer

Version:

NMEA 2000 data visualization utility (requires SK Server >= 2.15)

268 lines 12.8 kB
"use strict"; /* eslint-disable @typescript-eslint/no-explicit-any */ Object.defineProperty(exports, "__esModule", { value: true }); const canboatjs_1 = require("@canboat/canboatjs"); const n2k_signalk_1 = require("@signalk/n2k-signalk"); const server_1 = require("./server"); const recording_service_1 = require("./recording-service"); const PLUGIN_ID = 'canboat-visual-analyzer'; const PLUGIN_NAME = 'Canboat Visual Analyzer'; module.exports = function (app) { let onStop = []; //let dbusSetValue: any let canboatParser; let n2kMapper; let recordingService; const plugin = { id: PLUGIN_ID, name: PLUGIN_NAME, description: 'Canboat Visual Analyzer', schema: () => { return { title: PLUGIN_NAME, type: 'object', properties: {}, }; }, stop: () => { onStop.forEach((f) => f()); onStop = []; }, start: (_options) => { canboatParser = new canboatjs_1.FromPgn({ checkForInvalidFields: true, useCamel: true, // Default value useCamelCompat: false, returnNonMatches: true, createPGNObjects: true, includeInputData: true, includeRawData: true, includeByteMapping: true, }); canboatParser.on('error', (error) => { ; app.debug('Canboat Parser error:', error); }); n2kMapper = new n2k_signalk_1.N2kMapper({}); recordingService = new recording_service_1.RecordingService(`${app.config.configPath}/visual-analyzer`); const anyapp = app; recordingService.on('started', (status) => { console.log('Recording started:', status); anyapp.emit('recording:started', status); }); recordingService.on('stopped', (status) => { console.log('Recording stopped:', status); anyapp.emit('recording:stopped', status); }); recordingService.on('error', (error) => { console.error('Recording error:', error); anyapp.emit('recording:error', { error: error.message, }); }); recordingService.on('progress', (status) => { anyapp.emit('recording:progress', status); }); recordingService.on('error', (error) => { console.error('Recording error:', error); anyapp.emit('recording:error', { error: error.message, }); }); anyapp.on('canboatjs:rawoutput', (output) => { if (recordingService.getStatus().isRecording) { if (recordingService.getStatus().format === 'passthrough') { recordingService.recordMessage(output, undefined); } else { try { const pgn = canboatParser.parse(output); if (pgn) { recordingService.recordMessage(undefined, pgn); } } catch (error) { console.debug('Failed to parse raw NMEA data:', error); } } } }); }, registerWithRouter: (router) => { router.post('/api/send-n2k', (req, res) => { try { const values = req.body.values; if (!values) { return res.status(400).json({ success: false, error: 'Missing required field: values', }); } const pgnDataArray = []; for (const value of values) { // Check if input is a string (NMEA 2000 format) or JSON if (typeof value === 'string') { const lines = value.split(/\r?\n/).filter((line) => line.trim()); if (lines.length === 0) { return res.status(400).json({ success: false, error: 'No valid lines found in input', }); } try { for (const line of lines) { const trimmedLine = line.trim(); if (trimmedLine) { try { const parsed = canboatParser.parseString(trimmedLine); if (parsed) { pgnDataArray.push(parsed); } else { console.warn(`Unable to parse line: ${trimmedLine}`); } } catch (lineParseError) { const errorMessage = lineParseError instanceof Error ? lineParseError.message : 'Unknown error'; console.warn(`Error parsing line "${trimmedLine}": ${errorMessage}`); // Continue processing other lines instead of failing } } } if (pgnDataArray.length === 0) { return res.status(400).json({ success: false, error: 'Unable to parse any NMEA 2000 strings from input', }); } console.log(`Parsed ${pgnDataArray.length} NMEA 2000 messages from ${lines.length} lines using canboatjs`); } catch (canboatParseError) { const errorMessage = canboatParseError instanceof Error ? canboatParseError.message : 'Unknown error'; return res.status(400).json({ success: false, error: 'Error parsing NMEA 2000 strings: ' + errorMessage, }); } } else if (typeof value === 'object') { // Value is already a JSON object pgnDataArray.push(value); } else { return res.status(400).json({ success: false, error: 'Value must be a string (JSON or NMEA 2000 format) or object', }); } } // Process each parsed message const results = []; for (const pgnData of pgnDataArray) { console.log('Processing NMEA 2000 message for transmission:', { pgn: pgnData.pgn, data: pgnData, }); app.emit('nmea2000JsonOut', pgnData); } // Return success response in SignalK format res.json({ success: true, message: `${pgnDataArray.length} message(s) processed successfully`, messagesProcessed: pgnDataArray.length, results: results, // Include detailed results for each message }); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; console.error('Error processing input test request:', error); res.status(500).json({ success: false, error: errorMessage, }); } }); router.post('/api/transform/signalk', (req, res) => { (0, server_1.translateToSignalK)(req, res, canboatParser, n2kMapper); }); // Recording API routes router.get('/api/recording/status', (req, res) => { try { const status = recordingService.getStatus(); res.json({ success: true, result: status }); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; res.status(500).json({ success: false, error: errorMessage }); } }); router.post('/api/recording/start', (req, res) => { try { const { fileName, format } = req.body.value; const result = recordingService.startRecording({ fileName, format }); res.json({ success: true, fileName: result.fileName, message: 'Recording started successfully', }); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; res.status(400).json({ success: false, error: errorMessage }); } }); router.post('/api/recording/stop', (req, res) => { try { const result = recordingService.stopRecording(); res.json({ success: true, message: 'Recording stopped successfully', finalStats: result }); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; res.status(400).json({ success: false, error: errorMessage }); } }); router.get('/api/recording/files', (req, res) => { try { const files = recordingService.getRecordedFiles(); res.json({ success: true, results: files, // Include detailed results for each message }); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; res.status(500).json({ success: false, error: errorMessage }); } }); router.delete('/api/recording/files/:fileName', (req, res) => { try { recordingService.deleteRecordedFile(req.params.fileName); res.json({ success: true, message: 'File deleted successfully' }); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; res.status(400).json({ success: false, error: errorMessage }); } }); router.get('/api/recording/files/:fileName/download', (req, res) => { try { const filePath = recordingService.getRecordedFilePath(req.params.fileName); res.download(filePath, req.params.fileName, (err) => { if (err) { console.error('Download error:', err); if (!res.headersSent) { res.status(500).json({ success: false, error: 'Download failed' }); } } }); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; res.status(404).json({ success: false, error: errorMessage }); } }); }, }; return plugin; }; //# sourceMappingURL=plugin.js.map