@mindconnect/mindconnect-nodejs
Version:
NodeJS Library for Siemens Insights Hub Connectivity - TypeScript SDK for Insights Hub and Industrial IoT - Command Line Interface - Insights Hub Development Proxy (Siemens Insights Hub was formerly known as MindSphere)
251 lines • 13.2 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-classic");
let color = (0, command_utils_1.getColor)("magenta");
const yellow = (0, 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>", "mindsphere asset id ")
.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 sdk = (0, command_utils_1.getSdk)(options);
color = (0, command_utils_1.adjustColor)(color, options);
(0, command_utils_1.homeDirLog)(options.verbose, color);
(0, command_utils_1.proxyLog)(options.verbose, color);
const path = makeCsvAndJsonDir(options);
const { root, asset, aspects } = yield getAssetAndAspects(sdk, 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.");
(0, 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) {
(0, command_utils_1.errorLog)(err, options.verbose);
}
}))();
})
.on("--help", () => {
(0, console_1.log)("\n Examples:\n");
(0, console_1.log)(` mdsp prepare-bulk --typeid castidev.Engine \t this creates a directory called ${color("bulkimport")} for new asset of type castidev.Engine`);
(0, console_1.log)(` mdsp pb --dir asset1 -i 123456...abc \t\t this creates a directory called ${color("asset1")} for existing asset`);
(0, console_1.log)(` mdsp pb -of 3 -t castidev.Engine \t\t start data creation template 3 days before now`);
(0, console_1.log)(`\n\tuse --mode ${color("performance")} for standard data generation or --mode ${color("simulation")} for high frequency data generation `);
(0, 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(sdk, options) {
return __awaiter(this, void 0, void 0, function* () {
const assetMgmt = sdk.GetAssetManagementClient();
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" &&
(0, utils_1.throwError)("you have to specify the twin type performance or simulation");
!options.typeid && !options.assetid && (0, utils_1.throwError)("You have to specify either a typeid or assetid");
!!options.typeid === !!options.assetid && (0, utils_1.throwError)("You can't specify typeid and assetid at the same time");
(0, command_utils_1.verboseLog)(`creating directory template for: ${color(options.typeid || options.assetid)}`, options.verbose);
options.assetid && (0, utils_1.checkAssetId)(options.assetid);
(0, command_utils_1.verboseLog)(`creating directory: ${color(options.dir)}`, options.verbose);
fs.existsSync(options.dir) && (0, utils_1.throwError)(`the directory ${color(options.dir)} already exists`);
}
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(_a, spinner_1) {
return __awaiter(this, arguments, void 0, function* ({ name, variables, options, path, mode, }, spinner) {
(0, command_utils_1.verboseLog)(`Generating ${options.size} entries for ${name}`, options.verbose, spinner);
(0, 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`;
(0, 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
? (0, command_utils_1.subtractSecond)(date, (86400 / options.size) * index)
: (0, 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`;
(0, 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}`;
(0, command_utils_1.verboseLog)(`creating directory: ${color(csvDir)}`, options.verbose);
fs.mkdirSync(csvDir);
const jsonDir = `${path}/json/${element.name}`;
(0, 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 &&
(0, utils_1.throwError)(`You can't use the twintype mode ${color(options.twintype)} for ${asset.twinType} asset`);
}
//# sourceMappingURL=iot-prepare-bulk-dir.js.map