@yachteye/signalk-engineroom-plugin
Version:
Get EngineRoom data from the source (database or other) and add it to the SignalK graph.
208 lines (207 loc) • 9.82 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const _1 = require(".");
const mssql_1 = __importDefault(require("mssql"));
const utils = require('@signalk/nmea0183-utilities');
/**
* Access to the BDE database with Engine Data.
*/
class SqlBDE {
constructor(settings, definitions) {
this.pool = null;
this.dataDefinitions = definitions;
this.config = {
server: settings.sqlServer,
database: settings.sqlDb,
user: settings.sqlUser,
password: settings.sqlPassword,
pool: {
max: 10,
min: 0,
idleTimeoutMillis: 30000,
},
options: {
trustServerCertificate: settings.trustServerCertificate,
},
};
if (settings.sqlPort > 0) {
this.config.port = settings.sqlPort;
}
mssql_1.default
.connect(this.config)
.then((pool) => {
pool.on('error', (err) => {
console.error(`[SqlBDE] pool error: ${err}`);
});
pool.on('warn', (warn) => {
console.error(`[SqlBDE] pool warn: ${warn}`);
});
pool.on('info', (info) => {
console.error(`[SqlBDE] pool info: ${info}`);
});
console.log(`[SqlBDE] ctor: connecting=${pool.connecting}, connected=${pool.connected}.`);
this.pool = pool;
this.getIds();
})
.catch((err) => {
console.error('[SqlBDE]', 'Error creating connection pool', err);
});
}
/**
*
*/
disconnect() {
return __awaiter(this, void 0, void 0, function* () {
if (this.pool) {
try {
this.pool.removeAllListeners();
yield this.pool.close();
}
catch (err) {
console.error(`[SqlBDE] disconnect() error: ${err}`);
}
}
});
}
/**
* Get the database [Id] and [Scale] values for the data we need to retrieve.
*/
getIds() {
console.log(`[SqlBDE] getIds()`);
this.dataDefinitions.forEach((dataDef) => {
if (this.pool) {
this.pool
.query(`SELECT [Id], [Scale] from [BDE].[dbo].[T_Tag] WHERE [DisplayName] LIKE '${dataDef.displayNameDb}'`)
.then((r) => {
if (r.recordset.length === 0) {
if (!dataDef.displayNameDb.startsWith('N.A. ')) {
console.warn(`[SqlBDE] getIds() No data found for '${dataDef.displayNameDb}' path='${dataDef.path}' `);
}
}
else {
dataDef.Id = r.recordset[0].Id;
if (r.recordset[0].Scale) {
dataDef.scaleDb = r.recordset[0].Scale;
}
}
})
.catch((reason) => {
console.error(`[SqlBDE] getIds() error for ${dataDef.displayNameDb}: ${reason}`);
});
}
});
}
/**
* Get the specified value from the database table [T_Data]. The SQL Value is specified as bigint or null.
* @param id The database Id to query.
* @returns A Promise.
*/
queryDataById(id) {
return __awaiter(this, void 0, void 0, function* () {
// console.log(`[SqlBDE] queryDataById( ${id} )`);
if (this.pool) {
try {
// const result = await this.pool.request()
// .input('input_parameter', sql.Int, id)
// .output('Value', sql.BigInt)
// .output('Time',sql.DateTime2(7))
// .query('SELECT TOP(1) * FROM [BDE].[dbo].[T_Data] WHERE [Id] = @input_parameter ORDER BY [Time] DESC');
const result = yield this.pool.query(`SELECT TOP(1) [Time], [Value] FROM [BDE].[dbo].[T_Data] WHERE [Id] = ${id} ORDER BY [Time] DESC`);
// console.log('Q', id, JSON.stringify(result));
// {"recordsets":[[{"Time":"2024-06-25T05:44:02.096Z","Value":"0"}]],"recordset":[{"Time":"2024-06-25T05:44:02.096Z","Value":"0"}],"output":{},"rowsAffected":[1]}
const v = result.recordset[0].Value === null ? null : parseInt(result.recordset[0].Value, 10);
return { sqlValue: v, timestamp: result.recordset[0].Time };
}
catch (err) {
console.error(`[SqlBDE] queryDataById( ${id} ) error: ${err}`);
}
}
console.error(`[SqlBDE] queryDataById( ${id} ) No SQL connection pool`);
return null;
});
}
/**
* Get all the required data from the database.
* @returns A Promise with a dictionary with the data (keyed by path).
*/
getData() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
console.log(`[SqlBDE] getData(): connected = ${(_a = this.pool) === null || _a === void 0 ? void 0 : _a.connected} `);
const data = {};
const raw = {};
for (const dataDef of this.dataDefinitions) {
if (dataDef.Id) {
const value = yield this.queryDataById(dataDef.Id);
let dataValue = (value === null) ? null : value.sqlValue;
// console.warn('[SqlBDE] Value for', dataDef.Id, dataDef.displayNameDb, dataValue);
if (dataValue !== null) {
if (dataDef.scaleDb !== undefined && dataDef.scaleDb !== 1) {
dataValue = dataValue / dataDef.scaleDb;
}
if (dataDef.type === _1.IDataType.Ratio) {
if (dataValue > 100 || dataValue < -100) {
console.warn(`[SqlBDE] getData(): unexpected percentage value ${dataValue} for ${JSON.stringify(dataDef)} .`);
}
dataValue /= 100;
}
else if (dataDef.type === 'running_off') {
// Values are not just 0 or 1 as one would expect, so check for 0 and treat everything else as 'running'.
dataValue = dataValue === 0 ? 'off' : 'running';
}
if (dataDef.unit === 'W' && typeof dataValue === 'number') {
dataValue *= 1000; // kW to W.
}
else if (dataDef.unit === 'K' && typeof dataValue === 'number') {
dataValue = utils.transform(dataValue, 'C', 'K');
}
else if (dataDef.unit === 'Pa' && typeof dataValue === 'number') {
dataValue *= 100000; // bar to Pa.
}
else if (dataDef.unit === 'degrees' && dataDef.type === _1.IDataType.Number && typeof dataValue === 'number') {
dataValue = utils.transform(dataValue, 'deg', 'rad');
}
if (dataDef.type === _1.IDataType.Number && typeof dataValue === 'number') {
if (dataDef.min !== undefined && dataValue < dataDef.min) {
console.log(`[SqlBDE] getData(): unexpected value ${dataValue} for ${JSON.stringify(dataDef)} .`);
}
if (dataDef.max !== undefined && dataValue > dataDef.max) {
console.log(`[SqlBDE] getData(): unexpected value ${dataValue} for ${JSON.stringify(dataDef)} .`);
}
}
}
raw[dataDef.path] = {
id: String(dataDef.Id),
value: (value === null) ? null : value.sqlValue,
parsed: dataValue,
path: dataDef.path,
displayNameDb: dataDef.displayNameDb,
lastUpdate: (value === null) ? null : value.timestamp,
};
data[dataDef.path] = dataValue;
}
else if (dataDef.type === _1.IDataType.Fixed) {
data[dataDef.path] = dataDef.fixed === undefined ? 0 : dataDef.fixed;
}
else {
// console.warn('[SqlBDE] getData() no ID for', dataDef.displayNameDb, dataDef.Id);
data[dataDef.path] = null;
}
}
return { data, raw };
});
}
}
exports.default = SqlBDE;