@mindconnect/mindconnect-nodejs
Version:
MindConnect Library for NodeJS (community based)
257 lines • 13.3 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());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const console_1 = require("console");
const fs = require("fs");
const sdk_1 = require("../../api/sdk");
const utils_1 = require("../../api/utils");
const command_utils_1 = require("./command-utils");
const ora = require("ora");
const color = command_utils_1.getColor("magenta");
const yellow = command_utils_1.getColor("yellow");
exports.default = (program) => {
program
.command("prepare-bulk")
.alias("pb")
.option("-d, --dir <directoryname>", "config file with agent configuration", "bulkupload")
.option("-w, --twintype <mode>", "twintype of asset [performance|simulation]")
.option("-i, --assetid <assetid>", "asset id from the mindsphere ")
.option("-t, --typeid <typeid>", "typeid e.g. castidev.Engine ")
.option("-s, --size <size>", "entries per file ", 100)
.option("-f, --files <files>", "generated files ", 2)
.option("-o, --offset <days>", "offset in days from current date ", 0)
.option("-y, --retry <number>", "retry attempts before giving up", 3)
.option("-k, --passkey <passkey>", "passkey")
.option("-v, --verbose", "verbose output")
.description(color("creates a template directory for timeseries (bulk) upload *"))
.action(options => {
(() => __awaiter(void 0, void 0, void 0, function* () {
try {
checkRequiredParamaters(options);
const path = makeCsvAndJsonDir(options);
const auth = utils_1.loadAuth();
const { root, asset, aspects } = yield getAssetAndAspects(auth, options);
checkTwinTypeOfAsset(asset, options);
const spinner = ora("generating data...");
!options.verbose && spinner.start();
for (const aspect of aspects) {
createAspectDirs(path, aspect, options);
// * The variables are stored in different spots depenendet if they come from the type or from the asset.
const variables = aspect.variables || aspect.aspectType.variables || [];
// * The csv generation generates data for every day for performance assets and every hour for simulation assets
yield generateCsv({
name: aspect.name,
variables: variables,
options: options,
path: path,
mode: options.twintype
}, spinner);
}
options.typeid
? writeNewAssetJson(options, root, path, options.twintype)
: fs.writeFileSync(`${path}/asset.json`, JSON.stringify(asset, null, 2));
!options.verbose && spinner.succeed("done.");
command_utils_1.directoryReadyLog({
path: `${path}`,
jobCommand: "check-bulk",
runCommand: "run-bulk"
});
options.twintype === sdk_1.AssetManagementModels.TwinType.Performance &&
options.offset < 7 &&
console.log(`\n${yellow("Warning!")} The data has to be older then 7 days for bulk upload of performance assets.\n`);
}
catch (err) {
command_utils_1.errorLog(err, options.verbose);
}
}))();
})
.on("--help", () => {
console_1.log("\n Examples:\n");
console_1.log(` mc prepare-bulk --typeid castidev.Engine \t this creates a directory called ${color("bulkimport")} for new asset of type castidev.Engine`);
console_1.log(` mc pb --dir asset1 -i 123456...abc \t\t this creates a directory called ${color("asset1")} for existing asset`);
console_1.log(` mc pb -of 3 -t castidev.Engine \t\t start data creation template 3 days before now`);
console_1.log(`\n\tuse --mode ${color("performance")} for standard data generation or --mode ${color("simulation")} for high frequency data generation `);
console_1.log(`\tThe typeid must be derived from ${color("core.basicdevice")} and asset ${color("twintype")} must be ${color("simulation")} for high frequency data upload\n`);
});
};
function getAssetAndAspects(auth, options) {
return __awaiter(this, void 0, void 0, function* () {
const assetMgmt = new sdk_1.AssetManagementClient(auth.gateway, utils_1.decrypt(auth, options.passkey), auth.tenant);
let aspects = [];
let asset;
if (options.assetid) {
asset = yield assetMgmt.GetAsset(options.assetid);
const embAspects = yield assetMgmt.GetAspects(options.assetid);
if (embAspects._embedded && embAspects._embedded.aspects) {
aspects = embAspects._embedded.aspects.filter(x => {
return (x.category ===
sdk_1.AssetManagementModels.AspectResource.CategoryEnum.Dynamic);
});
}
}
if (options.typeid) {
const assetType = yield assetMgmt.GetAssetType(options.typeid, {
exploded: true
});
if (assetType.aspects) {
aspects = assetType.aspects.filter(x => {
return x.aspectType && x.aspectType.category === "dynamic";
});
}
aspects = aspects || [];
}
const root = yield assetMgmt.GetRootAsset();
return { root, asset, aspects };
});
}
function checkRequiredParamaters(options) {
options.twintype !== "performance" &&
options.twintype !== "simulation" &&
utils_1.throwError("you have to specify the twin type performance or simulation");
!options.typeid &&
!options.assetid &&
utils_1.throwError("You have to specify either a typeid or assetid");
!!options.typeid === !!options.assetid &&
utils_1.throwError("You can't specify typeid and assetid at the same time");
command_utils_1.verboseLog(`creating directory template for: ${color(options.typeid || options.assetid)}`, options.verbose);
options.assetid && utils_1.checkAssetId(options.assetid);
command_utils_1.verboseLog(`creating directory: ${color(options.dir)}`, options.verbose);
fs.existsSync(options.dir) &&
utils_1.throwError(`the directory ${color(options.dir)} already exists`);
!options.passkey &&
command_utils_1.errorLog("you have to provide a passkey to get the service token (run mc pb --help for full description)", true);
}
const generateRandom = (() => {
const variables = [];
return (timestamp, type, variableName) => {
!variables.includes(variableName) && variables.push(variableName);
let result;
// multiply the sine curves with factor to have every variable visible
const factor = variables.indexOf(variableName) + 1;
switch (type) {
case sdk_1.AssetManagementModels.VariableDefinition.DataTypeEnum.DOUBLE:
result = (Math.sin(timestamp.getTime()) * factor * 10).toFixed(2) + 20;
break;
case sdk_1.AssetManagementModels.VariableDefinition.DataTypeEnum.INT:
case sdk_1.AssetManagementModels.VariableDefinition.DataTypeEnum.LONG:
result = Math.floor(Math.sin(timestamp.getTime()) * factor * 20) + 40;
break;
case sdk_1.AssetManagementModels.VariableDefinition.DataTypeEnum.BOOLEAN:
result = true;
break;
case sdk_1.AssetManagementModels.VariableDefinition.DataTypeEnum.STRING:
case sdk_1.AssetManagementModels.VariableDefinition.DataTypeEnum.BIGSTRING:
result = `${type}_${Math.random()}`;
break;
default:
throw new Error(`invalid type ${type}`);
}
return result;
};
})();
function generateCsv({ name, variables, options, path, mode }, spinner) {
return __awaiter(this, void 0, void 0, function* () {
command_utils_1.verboseLog(`Generating ${options.size} entries for ${name}`, options.verbose, spinner);
command_utils_1.verboseLog(`Asset TwinType: ${mode}`, options.verbose, spinner);
const startDate = new Date();
startDate.setUTCDate(startDate.getUTCDate() - parseInt(options.offset));
for (let file = options.files; file > 0; file--) {
const date = new Date(startDate);
if (mode === sdk_1.AssetManagementModels.TwinType.Performance) {
// * generate one file per day
date.setUTCDate(date.getUTCDate() - (file - 1));
date.setUTCHours(0, 0, 0, 0);
}
else {
// * generate one file per hour
date.setUTCHours(file - 1, 0, 0, 0);
}
const fileName = `${path}/csv/${name}/${file}.csv`;
command_utils_1.verboseLog(`generating: ${color(fileName)}`, options.verbose, spinner);
const stream = fs.createWriteStream(fileName, {
highWaterMark: 12 * 16384
});
let headers = `_time, `;
variables.forEach(variable => {
headers += variable.name + ", ";
if (variable.qualityCode)
headers += variable.name + "_qc, ";
});
stream.write(headers.trimRight().slice(0, -1) + "\n");
variables.forEach(variable => {
headers += variable.name + ", ";
if (variable.qualityCode)
headers += variable.name + "_qc, ";
});
for (let index = options.size; index > 0; index--) {
const currentDate = mode === sdk_1.AssetManagementModels.TwinType.Performance
? command_utils_1.subtractSecond(date, (86400 / options.size) * index)
: command_utils_1.subtractSecond(date, (3600 / options.size) * index);
let line = currentDate.toISOString() + ", ";
variables.forEach(variable => {
line +=
generateRandom(currentDate, variable.dataType, `${variable.name}`) +
", ";
if (variable.qualityCode)
line += "0, ";
});
const result = stream.write(line.trimRight().slice(0, -1) + "\n");
if (!result) {
yield new Promise(resolve => stream.once("drain", resolve));
}
}
stream.end();
}
});
}
function writeNewAssetJson(options, root, path, twintype) {
const asset = {
name: `${twintype}Asset`,
twinType: twintype === "performance"
? sdk_1.AssetManagementModels.TwinType.Performance
: sdk_1.AssetManagementModels.TwinType.Simulation,
typeId: options.typeid,
parentId: root.assetId,
location: {
country: "Germany",
postalCode: "91052",
region: "Bayern",
streetAddress: "Schuhstr. 60",
locality: "Erlangen",
latitude: 49.59099,
longitude: 11.00783
}
};
const newAssetJson = `${path}/asset.json`;
command_utils_1.verboseLog(`Writing ${color(newAssetJson)}`, options.verbose);
fs.writeFileSync(`${path}/asset.json`, JSON.stringify(asset, null, 2));
}
function createAspectDirs(path, element, options) {
const csvDir = `${path}/csv/${element.name}`;
command_utils_1.verboseLog(`creating directory: ${color(csvDir)}`, options.verbose);
fs.mkdirSync(csvDir);
const jsonDir = `${path}/json/${element.name}`;
command_utils_1.verboseLog(`creating directory: ${color(jsonDir)}`, options.verbose);
fs.mkdirSync(jsonDir);
}
function makeCsvAndJsonDir(options) {
const path = options.dir;
fs.mkdirSync(path);
fs.mkdirSync(`${path}/csv/`);
fs.mkdirSync(`${path}/json/`);
return path;
}
function checkTwinTypeOfAsset(asset, options) {
asset &&
asset.twinType !== options.twintype &&
utils_1.throwError(`You can't use the twintype mode ${color(options.twintype)} for ${asset.twinType} asset`);
}
//# sourceMappingURL=iot-prepare-bulk-dir.js.map