1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/web/ synced 2025-03-09 00:00:01 +01:00

merge branch signal-auto-config into new-ic-data-model

This commit is contained in:
Laura Fuentes Grau 2020-11-09 17:24:10 +01:00
commit 097b44e2c5
5 changed files with 230 additions and 2 deletions

View file

@ -31,6 +31,7 @@ class EditICDialog extends React.Component {
this.state = {
name: '',
host: '',
apihost: '',
type: '',
category: '',
managedexternally: false,
@ -51,6 +52,10 @@ class EditICDialog extends React.Component {
data.host = this.state.host;
}
if (this.state.apihost != null && this.state.apihost !== "" && this.state.apihost !== "http://" && this.state.apihost !== this.props.ic.apihost) {
data.apihost = this.state.apihost;
}
if (this.state.type != null && this.state.type !== "" && this.state.type !== this.props.ic.type) {
data.type = this.state.type;
}
@ -91,6 +96,7 @@ class EditICDialog extends React.Component {
this.setState({
name: this.props.ic.name,
host: this.props.ic.host,
apihost: this.props.ic.apihost,
type: this.props.ic.type,
category: this.props.ic.category,
managedexternally: false,
@ -148,6 +154,11 @@ class EditICDialog extends React.Component {
<FormControl type="text" placeholder={this.props.ic.host} value={this.state.host || 'http://' } onChange={(e) => this.handleChange(e)} />
<FormControl.Feedback />
</FormGroup>
<FormGroup controlId="apihost">
<FormLabel column={false}>API Host</FormLabel>
<FormControl type="text" placeholder={this.props.ic.apihost} value={this.state.apihost || 'http://' } onChange={(e) => this.handleChange(e)} />
<FormControl.Feedback />
</FormGroup>
<FormGroup controlId="category">
<FormLabel column={false}>Category</FormLabel>
<FormControl as="select" value={this.state.category} onChange={(e) => this.handleChange(e)}>

View file

@ -337,6 +337,7 @@ class InfrastructureComponents extends Component {
<TableColumn title='Location' dataKeys={['properties.location', 'rawProperties.location']} />
{/* <TableColumn title='Realm' dataKeys={['properties.realm', 'rawProperties.realm']} /> */}
<TableColumn title='WebSocket Endpoint' dataKey='host' />
<TableColumn title='API Host' dataKey='apihost' />
<TableColumn title='Last Update' dataKey='stateUpdateAt' modifier={(stateUpdateAt) => this.stateUpdateModifier(stateUpdateAt)} />
{this.state.currentUser.role === "Admin" ?
<TableColumn

View file

@ -44,6 +44,7 @@ import EditSignalMapping from "../signal/edit-signal-mapping";
import FileStore from "../file/file-store"
import WidgetStore from "../widget/widget-store";
import { Redirect } from 'react-router-dom';
import NotificationsDataManager from "../common/data-managers/notifications-data-manager";
class Scenario extends React.Component {
@ -460,6 +461,47 @@ class Scenario extends React.Component {
// TODO do we need this if the dispatches happen in the dialog?
}
signalsAutoConf(index){
let componentConfig = this.state.configs[index];
// determine host of infrastructure component
let ic = this.state.ics.find(ic => ic.id === componentConfig.icID)
if(!ic.type.includes("VILLASnode") && !ic.type.includes("villasnode") && !ic.type.includes("VILLASNODE")){
let message = "Cannot autoconfigure signals for IC type " + ic.type + " of category " + ic.category + ". This is only possible for gateway ICs of type 'VILLASnode'."
console.warn(message);
const SIGNAL_AUTOCONF_WARN_NOTIFICATION = {
title: 'Failed to load signal config for IC ' + ic.name,
message: message,
level: 'warning'
};
NotificationsDataManager.addNotification(SIGNAL_AUTOCONF_WARN_NOTIFICATION);
return;
}
let splitHost = ic.host.split("/")
let request = {};
request["id"] = this.uuidv4();
request["action"] = "nodes"
AppDispatcher.dispatch({
type: 'signals/start-autoconfig',
data: request,
url: ic.apihost,
socketname: splitHost[splitHost.length -1],
token: this.state.sessionToken,
configID: componentConfig.id
});
}
uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
// eslint-disable-next-line
var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
/* ##############################################
* File modification methods
############################################## */
@ -587,6 +629,11 @@ class Scenario extends React.Component {
editButton
onEdit={index => this.setState({ editInputSignalsModal: true, modalConfigData: this.state.configs[index], modalConfigIndex: index })}
/>
<TableColumn
title='Signal AutoConf'
exportButton
onExport={(index) => this.signalsAutoConf(index)}
/>
<TableColumn title='Infrastructure Component' dataKey='icID' modifier={(icID) => this.getICName(icID)} />
<TableColumn
title=''

View file

@ -17,6 +17,7 @@
import ArrayStore from '../common/array-store';
import SignalsDataManager from './signals-data-manager'
import NotificationsDataManager from "../common/data-managers/notifications-data-manager";
class SignalStore extends ArrayStore{
constructor() {
@ -26,10 +27,34 @@ class SignalStore extends ArrayStore{
reduce(state, action) {
switch (action.type) {
case 'signals/added':
SignalsDataManager.reloadConfig(action.token, action.data);
this.dataManager.reloadConfig(action.token, action.data);
return super.reduce(state, action);
case 'signals/removed':
SignalsDataManager.reloadConfig(action.token, action.data);
this.dataManager.reloadConfig(action.token, action.data);
return super.reduce(state, action);
case 'signals/start-autoconfig':
this.dataManager.startAutoConfig(action.data, action.url, action.socketname, action.token, action.configID)
return super.reduce(state, action);
case 'signals/autoconfig-loaded':
console.log("AutoConfig Loaded: ", action.data)
// TODO save signal config contained in action.data
this.dataManager.saveSignals(action.data, action.token, action.configID, action.socketname);
return super.reduce(state, action);
case 'signals/autoconfig-error':
if (action.error && !action.error.handled && action.error.response) {
const SIGNAL_AUTOCONF_ERROR_NOTIFICATION = {
title: 'Failed to load signal config ',
message: action.error.response.body.message,
level: 'error'
};
NotificationsDataManager.addNotification(SIGNAL_AUTOCONF_ERROR_NOTIFICATION);
}
return super.reduce(state, action);
default:

View file

@ -18,6 +18,7 @@
import RestDataManager from '../common/data-managers/rest-data-manager';
import RestAPI from "../common/api/rest-api";
import AppDispatcher from "../common/app-dispatcher";
import NotificationsDataManager from "../common/data-managers/notifications-data-manager";
class SignalsDataManager extends RestDataManager{
@ -36,6 +37,149 @@ class SignalsDataManager extends RestDataManager{
}
startAutoConfig(data, url, socketname, token, configID){
// This function queries the VILLASnode API to obtain the configuration of the VILLASnode located at url
// Endpoint: http[s]://server:port/api/v1 (to be generated based on IC host, port 4000)
// data contains the request data: { action, id, (request)}
// See documentation of VILLASnode API: https://villas.fein-aachen.org/doc/node-dev-api-node.html
RestAPI.post(url, data).then(response => {
AppDispatcher.dispatch({
type: 'signals/autoconfig-loaded',
data: response,
token: token,
socketname: socketname,
configID: configID
});
}).catch(error => {
AppDispatcher.dispatch({
type: 'signals/autoconfig-error',
error: error
})
})
}
saveSignals(data, token, configID, socketname){
// data.response contains the response from the VILLASnode API, an array of node configurations
if(!data.hasOwnProperty("response")){
const SIGNAL_AUTOCONF_ERROR_NOTIFICATION = {
title: 'Failed to load signal config ',
message: 'VILLASnode returned no response field.',
level: 'error'
};
NotificationsDataManager.addNotification(SIGNAL_AUTOCONF_ERROR_NOTIFICATION);
return;
}
let configured = false;
let error = false;
for(let nodeConfig of data.response){
if(!nodeConfig.hasOwnProperty("name")){
console.warn("Could not parse the following node config because it lacks a name parameter:", nodeConfig);
} else if(nodeConfig.name === socketname){
if(configured){
const SIGNAL_AUTOCONF_WARNING_NOTIFICATION = {
title: 'There might be a problem with the signal auto-config',
message: 'VILLASnode returned multiple node configurations for the websocket ' + socketname + '. This is a problem of the VILLASnode.',
level: 'warning'
};
NotificationsDataManager.addNotification(SIGNAL_AUTOCONF_WARNING_NOTIFICATION);
continue;
}
// signals are not yet configured:
console.log("Adding signals of websocket: ", nodeConfig);
let index_in = 1
let index_out = 1
if(!nodeConfig.in.hasOwnProperty("signals")){
const SIGNAL_AUTOCONF_ERROR_NOTIFICATION = {
title: 'Failed to load in signal config ',
message: 'No field for in signals contained in response.',
level: 'error'
};
NotificationsDataManager.addNotification(SIGNAL_AUTOCONF_ERROR_NOTIFICATION);
error = true;
} else{
// add all in signals
for(let inSig of nodeConfig.in.signals) {
console.log("adding input signal:", inSig);
if (inSig.enabled) {
let newSignal = {
configID: configID,
direction: 'in',
name: inSig.hasOwnProperty("name") ? inSig.name : "in_" + String(index_in),
unit: inSig.hasOwnProperty("unit") ? inSig.unit : '-',
index: index_in,
scalingFactor: 1.0
};
AppDispatcher.dispatch({
type: 'signals/start-add',
data: newSignal,
token: token
});
index_in++;
}
}
}
if(!nodeConfig.out.hasOwnProperty("signals")){
const SIGNAL_AUTOCONF_ERROR_NOTIFICATION = {
title: 'Failed to load out signal config ',
message: 'No field for out signals contained in response.',
level: 'error'
};
NotificationsDataManager.addNotification(SIGNAL_AUTOCONF_ERROR_NOTIFICATION);
error=true;
}else {
// add all out signals
for (let outSig of nodeConfig.out.signals) {
console.log("adding output signal:", outSig);
if (outSig.enabled) {
let newSignal = {
configID: configID,
direction: 'out',
name: outSig.hasOwnProperty("name") ? outSig.name : "out_" + String(index_out),
unit: outSig.hasOwnProperty("unit") ? outSig.unit : '-',
index: index_out,
scalingFactor: 1.0
};
AppDispatcher.dispatch({
type: 'signals/start-add',
data: newSignal,
token: token
});
index_out++;
}
}
}
console.log("Configured", index_in-1, "input signals and", index_out-1, "output signals");
configured=true;
}
}
if(!error) {
const SIGNAL_AUTOCONF_INFO_NOTIFICATION = {
title: 'Signal configuration loaded successfully.',
message: '',
level: 'info'
};
NotificationsDataManager.addNotification(SIGNAL_AUTOCONF_INFO_NOTIFICATION);
}
}
}
export default new SignalsDataManager()