Skip to content

Commit

Permalink
build(update-simulator-data): added simulator update script
Browse files Browse the repository at this point in the history
Closes #151

Signed-off-by: Lukas Mertens <[email protected]>

commit-id:b922e502
  • Loading branch information
lukas-mertens committed Apr 16, 2024
1 parent 111277d commit f55f497
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 7 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ To release a new version, follow these steps:
5. Push the changes and the tag: `git push origin main --follow-tags`. For this you need to have the necessary permissions.
6. The CI will automatically create a GitHub release. Add the changelog to the release description.

### Updating the simulator data

Find a detailed guide on how to update the simulator data [here](src/modules/evbc/simulator-sample-data/README.md).

## Documentation

For more information about EVerest, please consult the
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"vite-plugin-vuetify": "^2.0.1",
"vitest": "^1.5.0",
"vue-eslint-parser": "^9.4.2",
"vue-tsc": "^1.8.0"
"vue-tsc": "^1.8.0",
"ws": "^8.16.0"
}
}
16 changes: 16 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src/modules/evbc/rpc/loopbackRpcIssuer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import {
EverestInterfaceDefinitionList,
EverestModuleDefinitionList
} from "@/modules/evbc";
import SampleManifestList from "@/modules/evbc/sample_module_info";
import SampleInterfaceList from "@/modules/evbc/sample_interfaces_list";
import SampleConfigList from "@/modules/evbc/sample_config_list";
import SampleManifestList from "@/modules/evbc/simulator-sample-data/sample_module_info";
import SampleInterfaceList from "@/modules/evbc/simulator-sample-data/sample_interfaces_list";
import SampleConfigList from "@/modules/evbc/simulator-sample-data/sample_config_list";
import {RpcIssuer} from "@/modules/evbc/rpc/abstractRpcIssuer";

/**
Expand Down
28 changes: 28 additions & 0 deletions src/modules/evbc/simulator-sample-data/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# EVerest Simulator Data Updater

## Overview

This directory contains a Node.js script (`update-simulator-data.js`) designed to update the dummy data directly from a
running EVerest instance. The script interfaces with the EVerest WebSocket API to fetch and refresh module and interface
data and converts the sample-configs in `./sample-configs` in a config list ensuring that the TypeScript files here
reflect the latest system definitions.

## Files

- `update-simulator-data.js`: The main script responsible for fetching data from the EVerest WebSocket API and updating
the TypeScript files.
- `sample_module_info.ts`: Updated to contain module information as EverestModuleDefinitionList.
- `sample_interfaces_list.ts`: Updated to contain interface definitions as EverestInterfaceDefinitionList.
- `sample_config_list.ts`: Updated to contain a few sample configs as EverestConfigList.

## Usage

Run the script using the following command:

```bash
node update-simulator-data.js [--url=<custom-ws-url>]
```

Options:
`--url=<custom-ws-url>`: Use this option to specify a custom WebSocket URL if your EVerest instance is not running on
the default ws://localhost:8849.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest

import { EverestConfigList } from ".";
import {EverestConfigList} from "../index";

export default {
"sample-config-sil": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest

import { EverestInterfaceDefinitionList } from ".";
import {EverestInterfaceDefinitionList} from "../index";

export default {
ISO15118_ac_charger: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest

import { EverestModuleDefinitionList } from ".";
import {EverestModuleDefinitionList} from "../index";

export default {
EnergyManager: {
Expand Down
127 changes: 127 additions & 0 deletions src/modules/evbc/simulator-sample-data/update-simulator-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env node
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest
import WebSocket from 'ws';
import fs from 'fs';
import path, {dirname} from 'path';
import process from 'process';
import {fileURLToPath} from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// Default URL of the EVerest WebSocket instance
const defaultUrl = 'ws://localhost:8849';
const args = process.argv.slice(2);
const url = args.find(arg => arg.startsWith('--url='))?.split('=')[1] || defaultUrl;

const help = `
Usage: node update-simulator-data.js [options]
Options:
--url=<ws-url> Specify the WebSocket URL of the EVerest instance (default: ${defaultUrl})
--help Show this help message
`;

if (args.includes('--help')) {
console.log(help);
process.exit(0);
}

const ws = new WebSocket(url);

const resolvers = {};

// Handler to manage both module and interface requests
ws.on('open', async () => {
console.log('Connected to EVerest WebSocket');
await Promise.all([
new Promise((resolve) => {
resolvers[1] = resolve;
sendRequest('get_modules', 1);
}),
new Promise((resolve) => {
resolvers[2] = resolve;
sendRequest('get_interfaces', 2);
}),
new Promise((resolve) => {
compileConfigFiles();
resolve();
})
])
ws.close();
console.log('Disconnected from EVerest WebSocket');
});

ws.on('message', function incoming(data) {
const response = JSON.parse(data);
if (response.id === 1 && response.result) {
updateFiles(response.result, 'sample_module_info.ts', 'EverestModuleDefinitionList');
} else if (response.id === 2 && response.result) {
updateFiles(response.result, 'sample_interfaces_list.ts', 'EverestInterfaceDefinitionList');
} else {
throw new Error("Invalid response received from EVerest WebSocket");
}
resolvers[response.id]();
});

ws.on('error', function error(e) {
console.error('Failed to connect to EVerest WebSocket:', e.message);
process.exit(1);
});

function sendRequest(method, id) {
const request = {
method: method,
params: null,
id: id
};
ws.send(JSON.stringify(request));

Check warning on line 78 in src/modules/evbc/simulator-sample-data/update-simulator-data.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/modules/evbc/simulator-sample-data/update-simulator-data.js#L78

This application accepts user input directly from the client side without validation.
}

function updateFiles(data, filename, typecast) {
const content = generateContent(data, typecast);
writeToFile(filename, content);
}

function generateContent(data, typecast) {
let content = licenseHeader();
content += `import {${typecast}} from "../index";\n\n`;
content += `export default ${JSON.stringify(data, null, 2)} as ${typecast};\n`;
return content;
}

function licenseHeader() {
return `// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - ${new Date().getFullYear()} Pionix GmbH and Contributors to EVerest\n\n`;
}

function writeToFile(filename, content) {
const filePath = path.join(__dirname, filename);

Check warning on line 99 in src/modules/evbc/simulator-sample-data/update-simulator-data.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/modules/evbc/simulator-sample-data/update-simulator-data.js#L99

Detected possible user input going into a `path.join` or `path.resolve` function.
try {
fs.writeFileSync(filePath, content);

Check warning on line 101 in src/modules/evbc/simulator-sample-data/update-simulator-data.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/modules/evbc/simulator-sample-data/update-simulator-data.js#L101

The application dynamically constructs file or path information.
console.log(`${filename} updated successfully!`);
} catch (err) {
console.error(`Failed to write data to ${filename}:`, err);

Check notice on line 104 in src/modules/evbc/simulator-sample-data/update-simulator-data.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/modules/evbc/simulator-sample-data/update-simulator-data.js#L104

Detected string concatenation with a non-literal variable in a util.format / console.log function.
}
}

function compileConfigFiles() {
const configDirPath = path.join(__dirname, 'sample-configs');
const configFiles = fs.readdirSync(configDirPath);

Check warning on line 110 in src/modules/evbc/simulator-sample-data/update-simulator-data.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/modules/evbc/simulator-sample-data/update-simulator-data.js#L110

The application dynamically constructs file or path information.

let configs = {};

configFiles.forEach(file => {
if (path.extname(file) === '.json') {
const configName = path.basename(file, '.json');
const filePath = path.join(configDirPath, file);

Check warning on line 117 in src/modules/evbc/simulator-sample-data/update-simulator-data.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/modules/evbc/simulator-sample-data/update-simulator-data.js#L117

Detected possible user input going into a `path.join` or `path.resolve` function.
const fileContent = fs.readFileSync(filePath, 'utf8');

Check warning on line 118 in src/modules/evbc/simulator-sample-data/update-simulator-data.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/modules/evbc/simulator-sample-data/update-simulator-data.js#L118

The application dynamically constructs file or path information.
configs[`${configName}`] = JSON.parse(fileContent);
} else {
console.warn(`Ignoring file ${file} as it is not a JSON file.`);
}
});

const content = generateContent(configs, 'EverestConfigList');
writeToFile('sample_config_list.ts', content);
}

0 comments on commit f55f497

Please sign in to comment.