diff --git a/dependencies/ggc/ggc.js b/dependencies/ggc/ggc.js
deleted file mode 100644
index afbeb8d..0000000
--- a/dependencies/ggc/ggc.js
+++ /dev/null
@@ -1,526 +0,0 @@
-/**
- * @file gate.js
- *
- * Permission is hereby granted to any person obtaining a copy of this software
- * and associated documentation files (the "Software"), to use it for personal
- * or non-commercial purposes, with the following restrictions:
- *
- * 1. **No Copying or Redistribution**: The Software or any of its parts may not
- * be copied, merged, distributed, sublicensed, or sold without explicit
- * prior written permission from the author.
- *
- * 2. **Commercial Use**: Any use of the Software for commercial purposes requires
- * a valid license, obtainable only with the explicit consent of the author.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM,
- * OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Ownership of this code remains solely with the original author. Unauthorized
- * use of this Software is strictly prohibited.
- *
- * @summary A class to interact and manipulate machines with a non-euclidian curve
- * @description A class to interact and manipulate machines with a non-euclidian curve
- * @module ggc
- * @exports ggc
- * @version 2.0.0
- * @since 0.1.0
- *
- * Author:
- * - Rene De Ren
- * Email:
- * - rene@thegoldenbasket.nl
- *
-*/
-
-//load local dependencies
-const EventEmitter = require('events');
-const Logger = require('../../../generalFunctions/helper/logger');
-const { MeasurementContainer } = require('../../../generalFunctions/helper/measurements/index');
-const Interpolation = require('../../../predict/dependencies/predict/interpolation');
-//load all config modules
-const defaultConfig = require('./ggcConfig.json');
-const ConfigUtils = require('../../../generalFunctions/helper/configUtils');
-//load registration utility
-const ChildRegistrationUtils = require('../../../generalFunctions/helper/childRegistrationUtils');
-
-class Ggc {
-
-
- /*------------------- Construct and set vars -------------------*/
- constructor(ggcConfig = {}) {
-
- //basic setup
- this.emitter = new EventEmitter(); // Own EventEmitter
- this.configUtils = new ConfigUtils(defaultConfig);
- this.config = this.configUtils.initConfig(ggcConfig);
-
- // Initialize measurements
- this.measurements = new MeasurementContainer();
- this.interpolation = new Interpolation();
- this.child = {}; // object to hold child
- this.actuators = []; // object to hold actuators
- this.abortController = null; // new abort controller for aborting async tasks
-
- // Init after config is set
- this.logger = new Logger(this.config.general.logging.enabled, this.config.general.logging.logLevel, this.config.general.name);
- this.mode = this.config.mode.current;
-
- this.move_delay = this.config.settings.moveDelay ; //define opening delay in seconds between 2 gates
- this.state = "gateGroupClosed"; //define default starting state of the gates
-
- //auto close
- this.autoClose = true;
- this.autoCloseTime = this.config.settings.autoClose;
- this.autoCloseCnt = 0;
-
- //protection sensor
- this.safetySensor = false;
- this.retryDelay = this.config.settings.retryDelay; // in seconds
- this.closeAttempt = 0;
- this.maxCloseAttempts = this.config.settings.maxRetries ;
- this.safetySensorCnt = 0;
-
-
- //ground loop trigger
- this.ground_loop = false;
- this.ground_loop_start = Date.now();
- this.ground_loop_open = 10; //define time in seconds for when the ground loop should trigger a respons
-
- //define if something has gone through the gate
- this.goneThrough = false;
-
- //define if the gate is closed
- this.checkGateClosed = [false, false]; // gate 1 and gate 2
-
- /* time controlled functions*/
- //this.sleep = ms => new Promise(res => setTimeout(res, ms));
-
- this.childRegistrationUtils = new ChildRegistrationUtils(this); // Child registration utility
- }
-
-
- isValidSourceForMode(source, mode) {
- const allowedSourcesSet = this.config.mode.allowedSources[mode] || [];
- return allowedSourcesSet.has(source);
- }
-
- isValidActionForMode(action, mode) {
- const allowedActionsSet = this.config.mode.allowedActions[mode] || [];
- return allowedActionsSet.has(action);
- }
-
- sleep(ms, signal) {
- return new Promise((resolve, reject) => {
- const timer = setTimeout(resolve, ms);
- // only attach abort listener if a valid signal is provided
- if (signal && typeof signal.addEventListener === 'function') {
- signal.addEventListener('abort', () => {
- clearTimeout(timer);
- reject(new Error('aborted'));
- });
- }
- });
- }
-
- // -------- Sequence Handlers -------- //
- async executeSequence(name) {
-
- const sequence = this.config.sequences[name];
- const positions = this.actuators.map(a => a.state.getCurrentPosition());
- const states = this.actuators.map(a => a.state.getCurrentState());
-
- if (!sequence || sequence.size === 0) {
- this.logger.warn(`Sequence '${name}' not defined.`);
- return;
- }
-
- // Abort any prior sequence and start fresh
- this.abortController?.abort();
- this.abortController = new AbortController();
- const { signal } = this.abortController;
-
- if ( states.some(s => s !== "operational") && name !== "stop2gates" ) {
- this.logger.warn(`Actuators not operational, aborting sequence '${name}'.`);
- this.handleInput("parent", "execSequence", "stop2gates");
- this.sleep(1000).then(() => {
- this.handleInput("parent", "execSequence", name);
- });
- return;
- }
-
- try {
- for (const action of sequence) {
-
- this.transitionToSequence(action);
-
- //If someone has already called abort(), skip the delay
- if (signal.aborted) {
- continue;
- }
-
- //otherwise, wait for the delay
- await this.sleep(this.move_delay * 1000, signal);
- }
- } catch (err) {
- if (err.message === 'aborted') {
- this.logger.debug(`Sequence '${name}' aborted mid-delay.`);
- } else {
- this.logger.error(`Error in sequence '${name}': ${err.stack}`);
- }
- } finally {
- // Clean up so we know no sequence is running
- this.abortController = null;
- }
-
- }
-
-
- async transitionToSequence(action) {
- this.logger.debug(`Executing action: ${action}`);
- const positions = this.actuators.map(a => a.state.getCurrentPosition());
- const states = this.actuators.map(a => a.state.getCurrentState());
-
- // Perform actions based on the state
- switch (action) {
- case "openGate1":
- this.logger.debug("Opening gate 1");
- this.actuators[0].handleInput("parent", "execMovement", 100);
- this.checkGateClosed[0] = false;
- break;
- case "openGate2":
- this.logger.debug("Opening gate 2");
- this.actuators[1].handleInput("parent", "execMovement", 100);
- break;
- case "stopGate1":
- this.logger.debug("Stopping gate 1");
- // abort the delayed sleep, if any
- this.abortController?.abort();
- // immediately stop actuator 1
- this.actuators[0].stop();
- break;
- case "stopGate2":
- this.logger.debug("Stopping gate 2");
- // abort the delayed sleep, if any
- this.abortController?.abort();
- // immediately stop actuator 2
- this.actuators[1].stop();
- break;
- case "closeGate1":
- this.actuators[0].handleInput("parent", "execMovement", 0);
- break;
- case "closeGate2":
- this.actuators[1].handleInput("parent", "execMovement", 0);
- break;
- default:
- this.logger.warn(`Unknown state: ${state}`);
- }
- }
-
- async handleInput(source, action, parameter) {
-
- if (!this.isValidSourceForMode(source, this.mode)) {
- this.logger.warn(`Invalid source ${source} for mode ${this.mode}`);
- return;
- }
-
- if (!this.isValidActionForMode(action, this.mode)) {
- this.logger.warn(`Invalid action ${action} for mode ${this.mode}`);
- return;
- }
-
- switch (action) {
- case 'execSequence':
- this.executeSequence(parameter);
- break;
- case 'setMode':
- this.setMode(parameter);
- break;
- default:
- this.logger.warn(`Unknown action ${action}`);
- }
-
- }
-
- groundLoopAction(){
- if(this.ground_loop){
- //keep track of time
- this.ground_loop_time = Date.now() - this.ground_loop_trigger;
- }
- else{
- this.ground_loop_time = 0;
- }
-
- if(this.ground_loop_time >= ( this.ground_loop_open * 1000) ){
- this.openGates();
- }
- }
-
- updateMeasurement(variant, subType, value, position) {
- this.logger.debug(`---------------------- updating ${subType} ------------------ `);
- switch (subType) {
- case "power":
- // Update power measurement
- this.updatePower(variant, value, position);
- break;
- default:
- this.logger.error(`Type '${type}' not recognized for measured update.`);
- return;
- }
- }
-
- updatePower(variant,value,position) {
- switch (variant) {
- case ("measured"):
- // put value in measurements
- this.measurements.type("power").variant(variant).position("wire").value(value);
- this.eventUpdate();
- this.logger.debug(`Measured: ${value}`);
- break;
-
- default:
- this.logger.warn(`Unrecognized variant '${variant}' for update.`);
- break;
- }
- }
-
- eventUpdate() {
- // Gather raw data in arrays
- const positions = this.actuators.map(a => a.state.getCurrentPosition());
- const states = this.actuators.map(a => a.state.getCurrentState());
- this.logger.debug(`States: ${JSON.stringify(states)}`);
- this.logger.debug(`Positions: ${JSON.stringify(positions)}`);
- const totPower = this.measurements.type("power").variant("measured").position("wire").getCurrentValue();
-
- // Utility flags
- const allOperational = states.every(s => s === "operational");
- const allAtOpen = positions.every(p => p === 100);
- const allAtClosed = positions.every(p => p === 0);
- const allAccelerating = states.every(s => s === "accelerating");
- const allDecelerating = states.every(s => s === "decelerating");
- const allStopped = states.every(s => s === "operational") && positions.every( p => p !== 0 && p != 100);
- const onlyGateOneAccelerating = states[0] === "accelerating" && states[1] === "operational";
- const onlyGateTwoAccelerating = states[1] === "accelerating" && states[0] === "operational";
- const onlyGateOneDecelerating = states[0] === "decelerating" && states[1] === "operational";
- const onlyGateTwoDecelerating = states[1] === "decelerating" && states[0] === "operational";
- const oneOpenOneClosed = allOperational && positions.some(p => p === 0) && positions.some(p => p === 100);
-
- // Threshold for “spike” detection (tune as needed)
- const SPIKE_THRESHOLD_1gate = 50;
- const SPIKE_THRESHOLD_2gates = 100;
- const lowerPositionThreshold = 10; // 10% of the total range
- const upperPositionThreshold = 90; // 90% of the total range
-
- // When something is blocking the gate we need to reopen the gates (True means nothing is blocking)
- if (!this.safetySensor) {
- // always add 1 to the safety sensor counter
- this.safetySensorCnt++;
-
- //add 1 to the autoclose counter to check weither we dont exceedd the max retries
- if(this.autoClose) {
- this.autoCloseCnt++;
- }
- //check if the safety sensor is triggered and the gates are closing
- if( allDecelerating || onlyGateOneDecelerating || onlyGateTwoDecelerating) {
- this.closeAttempt++;
- this.handleInput("parent", "execSequence", "stop2gates");
- this.logger.debug("something is blocking the gate, stopping actuators");
- this.sleep(1000).then(() => {
- this.handleInput("parent", "execSequence", "open2gates");
- });
- }
- }
-
- // Detect if any single gate is decelerating into its stop
- if( onlyGateOneDecelerating ) {
- //check for power spike so we know the gate is closed
- if ( totPower > SPIKE_THRESHOLD_1gate ) {
- this.logger.debug("Gate 1 is decelerating into the stop (power spike)");
- //check flag for knowing if the gate is closed
- this.checkGateClosed[0] = true;
- this.closeAttempt = 0;
- }
- }
-
- if( allDecelerating || allAccelerating) {
- if( totPower > SPIKE_THRESHOLD_2gates && ( positions.some(p => p > lowerPositionThreshold) || positions.some(p => p < upperPositionThreshold) ) ) {
- this.logger.debug("Unexpected power spike detected");
- // stop the actuators
- this.handleInput("parent", "execSequence", "stop2gates");
- }
- }
-
- // Decide group state
- if (allAtOpen && allOperational) {
- this.state = "gateGroupOpened";
- //trigger auto close if count is smaller than max
- if( this.autoClose && this.autoCloseCnt < this.maxCloseAttempts && this.safetySensorCnt > 0) {
- this.sleep(this.autoCloseTime * 1000).then(() => {
- this.handleInput("parent", "execSequence", "close2gates");
- //reset the safetySensor count because we are automatically closing the gates and if its bigger than 0 it means some1 passed through it
- this.safetySensorCnt = 0;
- });
- }
- this.logger.debug("Gates are open");
- }
- else if (allAtClosed && allOperational) {
- this.state = "gateGroupClosed";
- //after everything was closed and the auto close is enabled we need to reset the auto close count
- if(this.autoClose) {
- this.autoCloseCnt = 0;
- };
- this.logger.debug("Gates are closed");
- }
- else if (oneOpenOneClosed) {
- this.state = "oneGateOpenOneGateClosed";
- this.logger.debug("One gate open, one gate closed");
- }
- else if (allAccelerating) {
- this.state = "gateGroupAccelerating";
- this.logger.debug("Gates are accelerating");
- }
- else if (onlyGateOneAccelerating) {
- this.state = "gateOneAccelerating";
- this.logger.debug("Only gate 1 is accelerating");
- }
- else if (onlyGateTwoAccelerating) {
- this.state = "gateTwoAccelerating";
- this.logger.debug("Only gate 2 is accelerating");
- }
- else if (allDecelerating) {
- this.state = "gateGroupDecelerating";
- this.logger.debug("Gates are decelerating");
- }
- else if (onlyGateOneDecelerating) {
- this.state = "gateOneDecelerating";
- this.logger.debug("Only gate 1 is decelerating");
- }
- else if (onlyGateTwoDecelerating) {
- this.state = "gateTwoDecelerating";
- this.logger.debug("Only gate 2 is decelerating");
- }
- else if (allStopped) {
- this.state = "gateGroupStopped";
- this.logger.debug("Gates are stopped");
- }
- else {
- this.state = "unknown";
- this.logger.warn(`Unhandled combination: positions=${positions}, states=${states}`);
- }
-
- // if the gates are operational and close but we dont see the truely closed state then we need to nudge the gate to force the close
-
- }
-
- getOutput() {
-
- // Improved output object generation
- const output = {};
-
- //build the output object
- this.measurements.getTypes().forEach(type => {
- this.measurements.getVariants(type).forEach(variant => {
-
- const downstreamVal = this.measurements.type(type).variant(variant).position("downstream").getCurrentValue();
- const upstreamVal = this.measurements.type(type).variant(variant).position("upstream").getCurrentValue();
-
- if (downstreamVal != null) {
- output[`downstream_${variant}_${type}`] = downstreamVal;
- }
- if (upstreamVal != null) {
- output[`upstream_${variant}_${type}`] = upstreamVal;
- }
- if (downstreamVal != null && upstreamVal != null) {
- const diffVal = this.measurements.type(type).variant(variant).difference().value;
- output[`differential_${variant}_${type}`] = diffVal;
- }
- });
- });
-
- //fill in the rest of the output object
- output["mode"] = this.mode;
- output["totPower"] = this.power;
- //this.logger.debug(`Output: ${JSON.stringify(output)}`);
-
- return output;
- }
-
-} // end of class
-
-module.exports = Ggc;
-
-/*
-const ggcConfig = {
- general: {
- name: "TestGGC",
- logging: {
- enabled: true,
- logLevel: "debug"
- }
- },
- settings: {
- moveDelay: 3,
- autoClose: 5,
- retryDelay: 10,
- maxRetries: 5
- }
-};
-
-const ggc = new Ggc(ggcConfig);
-const linearActuator = require('../../../linearActuator/dependencies/linearActuator/linearActuator');
-const linActConfig =
-{
- general: {
- logging: {
- enabled: true,
- logLevel: "debug",
- }
- },
- settings: {
- moveDelay: 3,
- autoClose: 5,
- retryDelay: 10,
- maxRetries: 5
- }
-};
-const stateConfig = {
- general: {
- logging: {
- enabled: true,
- logLevel: "debug"
- }
- },
- movement: {
- speed: 0.1,
- mode: "staticspeed"
- },
- time: {
- starting: 0,
- warmingup: 0,
- stopping: 0,
- coolingdown: 0
- }
-};
-
-const gate1 = new linearActuator(linActConfig,stateConfig);
-const gate2 = new linearActuator(linActConfig,stateConfig);
-
-ggc.childRegistrationUtils.registerChild(gate1,"upstream");
-ggc.childRegistrationUtils.registerChild(gate2,"downstream");
-
-
-//open completely 2 gates inside an async IIFE
-(async () => {
- await ggc.actuators[0].handleInput("parent","execSequence","startup");
- await ggc.actuators[1].handleInput("parent","execSequence","startup");
-
- ggc.handleInput("parent","execSequence","open2gates");
- await ggc.sleep(5000);
- ggc.handleInput("parent","execSequence","stop2gates");
-
-})();
-//*/
diff --git a/dependencies/ggc/ggcConfig.json b/dependencies/ggc/ggcConfig.json
deleted file mode 100644
index 430fd4e..0000000
--- a/dependencies/ggc/ggcConfig.json
+++ /dev/null
@@ -1,297 +0,0 @@
-{
- "general": {
- "name": {
- "default": "gate group control Machine",
- "rules": {
- "type": "string",
- "description": "A human-readable name or label for this machine configuration."
- }
- },
- "id": {
- "default": null,
- "rules": {
- "type": "string",
- "nullable": true,
- "description": "A unique identifier for this configuration. If not provided, defaults to null."
- }
- },
- "unit": {
- "default": "m3/h",
- "rules": {
- "type": "string",
- "description": "The default measurement unit for this configuration (e.g., 'meters', 'seconds', 'unitless')."
- }
- },
- "logging": {
- "logLevel": {
- "default": "info",
- "rules": {
- "type": "enum",
- "values": [
- {
- "value": "debug",
- "description": "Log messages are printed for debugging purposes."
- },
- {
- "value": "info",
- "description": "Informational messages are printed."
- },
- {
- "value": "warn",
- "description": "Warning messages are printed."
- },
- {
- "value": "error",
- "description": "Error messages are printed."
- }
- ]
- }
- },
- "enabled": {
- "default": true,
- "rules": {
- "type": "boolean",
- "description": "Indicates whether logging is active. If true, log messages will be generated."
- }
- }
- }
- },
- "functionality": {
- "softwareType": {
- "default": "gateGroupControl",
- "rules": {
- "type": "string",
- "description": "Specified software type for this configuration."
- }
- },
- "role": {
- "default": "gate controller",
- "rules": {
- "type": "string",
- "description": "Indicates the role this configuration plays within the system."
- }
- }
- },
- "asset": {
- "uuid": {
- "default": null,
- "rules": {
- "type": "string",
- "nullable": true,
- "description": "A universally unique identifier for this asset. May be null if not assigned."
- }
- },
- "geoLocation": {
- "default": {},
- "rules": {
- "type": "object",
- "description": "An object representing the asset's physical coordinates or location.",
- "schema": {
- "x": {
- "default": 0,
- "rules": {
- "type": "number",
- "description": "X coordinate of the asset's location."
- }
- },
- "y": {
- "default": 0,
- "rules": {
- "type": "number",
- "description": "Y coordinate of the asset's location."
- }
- },
- "z": {
- "default": 0,
- "rules": {
- "type": "number",
- "description": "Z coordinate of the asset's location."
- }
- }
- }
- }
- }
- },
- "mode": {
- "current": {
- "default": "auto",
- "rules": {
- "type": "enum",
- "values": [
- {
- "value": "auto",
- "description": "Machine accepts setpoints from a parent controller and runs autonomously."
- },
- {
- "value": "virtualControl",
- "description": "Controlled via GUI setpoints; ignores parent commands."
- },
- {
- "value": "fysicalControl",
- "description": "Controlled via physical buttons or switches; ignores external automated commands."
- },
- {
- "value": "maintenance",
- "description": "No active control from auto, virtual, or fysical sources."
- }
- ],
- "description": "The operational mode of the machine."
- }
- },
- "allowedActions":{
- "default":{},
- "rules": {
- "type": "object",
- "schema":{
- "auto": {
- "default": ["statusCheck", "execMovement", "execSequence", "emergencyStop"],
- "rules": {
- "type": "set",
- "itemType": "string",
- "description": "Actions allowed in auto mode."
- }
- },
- "virtualControl": {
- "default": ["statusCheck", "execMovement", "execSequence", "emergencyStop"],
- "rules": {
- "type": "set",
- "itemType": "string",
- "description": "Actions allowed in virtualControl mode."
- }
- },
- "fysicalControl": {
- "default": ["statusCheck", "emergencyStop"],
- "rules": {
- "type": "set",
- "itemType": "string",
- "description": "Actions allowed in fysicalControl mode."
- }
- },
- "maintenance": {
- "default": ["statusCheck"],
- "rules": {
- "type": "set",
- "itemType": "string",
- "description": "Actions allowed in maintenance mode."
- }
- }
- },
- "description": "Information about valid command sources recognized by the machine."
- }
- },
- "allowedSources":{
- "default": {},
- "rules": {
- "type": "object",
- "schema":{
- "auto": {
- "default": ["parent", "GUI", "fysical"],
- "rules": {
- "type": "set",
- "itemType": "string",
- "description": "Sources allowed in auto mode."
- }
- },
- "virtualControl": {
- "default": ["GUI", "fysical"],
- "rules": {
- "type": "set",
- "itemType": "string",
- "description": "Sources allowed in virtualControl mode."
- }
- },
- "fysicalControl": {
- "default": ["fysical"],
- "rules": {
- "type": "set",
- "itemType": "string",
- "description": "Sources allowed in fysicalControl mode."
- }
- }
- },
- "description": "Information about valid command sources recognized by the machine."
- }
- }
- },
- "sequences":{
- "default":{},
- "rules": {
- "type": "object",
- "schema": {
- "open2gates": {
- "default": ["openGate1","openGate2"],
- "rules": {
- "type": "set",
- "itemType": "string",
- "description": "Sequence of states for starting up the machine."
- }
- },
- "open1gate": {
- "default": ["openGate1"],
- "rules": {
- "type": "set",
- "itemType": "string",
- "description": "Sequence of states for shutting down the machine."
- }
- },
- "stop2gates": {
- "default": ["stopGate1","stopGate2"],
- "rules": {
- "type": "set",
- "itemType": "string",
- "description": "Sequence of states for stopping the machine."
- }
- },
- "close2gates": {
- "default": ["closeGate2","closeGate1"],
- "rules": {
- "type": "set",
- "itemType": "string",
- "description": "Sequence of states for closing the gates."
- }
- }
- }
- },
- "description": "Predefined sequences of states for the machine."
-
- },
- "settings": {
- "moveDelay": {
- "default": 3,
- "rules": {
- "type": "number",
- "description": "delay between opening first and second linear actuator in seconds"
- }
- },
- "autoClose": {
- "default": 30,
- "rules": {
- "type": "number",
- "description": "When auto close is enabled, the gate will close automatically after this time in seconds"
- }
- },
- "retryDelay": {
- "default": 5,
- "rules": {
- "type": "number",
- "description": "Delay in seconds before retrying a failed command."
- }
- },
- "maxRetries": {
- "default": 5,
- "rules": {
- "type": "number",
- "description": "Maximum number of retries for a failed command."
- }
- },
- "groundLoopOpen": {
- "default": 10,
- "rules": {
- "type": "number",
- "description": "Time before ground loop triggers opening of the gate in seconds"
- }
- }
-
- }
- }
-
\ No newline at end of file
diff --git a/ggc.html b/ggc.html
deleted file mode 100644
index 3a7a864..0000000
--- a/ggc.html
+++ /dev/null
@@ -1,284 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ggc.js b/ggc.js
deleted file mode 100644
index c2ad8fd..0000000
--- a/ggc.js
+++ /dev/null
@@ -1,223 +0,0 @@
-module.exports = function (RED) {
- function ggc(config) {
- RED.nodes.createNode(this, config);
- var node = this;
-
- try {
- // Load Machine class and curve data
- const Ggc = require("./dependencies/ggc/ggc");
- const OutputUtils = require("../generalFunctions/helper/outputUtils");
-
- const ggcConfig = {
- general: {
- name: config.name || "Unknown",
- id: node.id,
- logging: {
- enabled: config.eneableLog,
- logLevel: config.logLevel
- }
- },
- asset: {
- supplier: config.supplier || "Unknown",
- type: config.machineType || "generic",
- subType: config.subType || "generic",
- model: config.model || "generic",
- }
- };
-
- const stateConfig = {
- general: {
- logging: {
- enabled: config.eneableLog,
- logLevel: config.logLevel
- }
- },
- movement: {
- speed: Number(config.speed)
- },
- time: {
- starting: Number(config.startup),
- warmingup: Number(config.warmup),
- stopping: Number(config.shutdown),
- coolingdown: Number(config.cooldown)
- }
- };
-
- // Create machine instance
- const ggc = new Ggc(ggcConfig, stateConfig);
-
- // put m on node memory as source
- node.source = ggc;
-
- //load output utils
- const output = new OutputUtils();
-
- function updateNodeStatus() {
- try {
- const mode = "auto";//ggc.currentMode;
- const state = ggc.state;
- const totPower = Math.round(ggc.measurements.type("power").variant("measured").position('wire').getCurrentValue()) || 0;
-
- const SYMBOL_MAP = {
- gateGroupClosed: "G1🔴 & G2🔴",
- gateGroupOpened: "G1🟢 & G2🟢",
- gateGroupStopped: "G1🟥 & G2🟥",
- gateGroupAccelerating: "G1🟡 & G2🟡",
- gateGroupDecelerating: "G1🟠 & G2🟠",
- gateOneAccelerating: "G1🟡 & G2🟢",
- gateTwoAccelerating: "G1🟢 & G2🟡",
- gateOneDecelerating: "G1🟠 & G2🟢",
- gateTwoDecelerating: "G1🟢 & G2🟠",
- oneGateOpenOneGateClosed: "G1🟢 & G2🔴",
- gatePushingStop: "G1⚡ & G2⚡",
- unknown: "❓ & ❓",
- };
-
- symbolState = SYMBOL_MAP[state] || "Unknown";
-
- const position = "" ; //ggc.getGatePositions();
- const roundedPosition = Math.round(position * 100) / 100;
-
- let status;
- switch (state) {
- // —— gateGroup states first ——
- case "gateGroupClosed":
- status = {
- fill: "red",
- shape: "dot",
- text: `${mode}: ${symbolState}`
- };
- break;
- case "gateGroupOpened":
- status = {
- fill: "green",
- shape: "dot",
- text: `${mode}: ${symbolState}`
- };
- break;
- case "gateGroupStopped":
- status = {
- fill: "red",
- shape: "dot",
- text: `${mode}: ${symbolState}`
- };
- break;
- case "oneGateOpenOneGateClosed":
- status = {
- fill: "green",
- shape: "dot",
- text: `${mode}: ${symbolState}`
- };
- break;
- default:
- status = { fill: "grey", shape: "dot", text: `${mode}: ${symbolState}` };
- }
- return status;
- } catch (error) {
- node.error("Error in updateNodeStatus: " + error.message);
- return { fill: "red", shape: "ring", text: "Status Error" };
- }
- }
-
- function tick() {
- try {
- const status = updateNodeStatus();
- node.status(status);
-
- //get output
- const classOutput = ggc.getOutput();
- const dbOutput = output.formatMsg(classOutput, ggc.config, "influxdb");
- const pOutput = output.formatMsg(classOutput, ggc.config, "process");
-
- //console.log(pOutput);
-
- //only send output on values that changed
- let msgs = [];
- msgs[0] = pOutput;
- msgs[1] = dbOutput;
-
- node.send(msgs);
-
- } catch (error) {
- node.error("Error in tick function: " + error);
- node.status({ fill: "red", shape: "ring", text: "Tick Error" });
- }
- }
-
- // register child on first output this timeout is needed because of node - red stuff
- setTimeout(
- () => {
-
- /*---execute code on first start----*/
- let msgs = [];
-
- msgs[2] = { topic : "registerChild" , payload: node.id, positionVsParent: "upstream" };
- msgs[3] = { topic : "registerChild" , payload: node.id, positionVsParent: "downstream" };
-
- //send msg
- this.send(msgs);
- },
- 100
- );
-
- //declare refresh interval internal node
-
- setTimeout(
- () => {
- //---execute code on first start----
- this.interval_id = setInterval(function(){ tick() },1000)
- },
- 1000
- );
-
- node.on("input", function(msg, send, done) {
- try {
-
- /* Update to complete event based node by putting the tick function after an input event */
- switch(msg.topic) {
- case 'registerChild':
- const childId = msg.payload;
- const childObj = RED.nodes.getNode(childId);
- ggc.childRegistrationUtils.registerChild(childObj.source ,msg.positionVsParent);
- break;
- case 'setMode':
- ggc.setMode(msg.payload);
- break;
- case 'execSequence':
- const { source, action, parameter } = msg.payload;
- ggc.handleInput(source, action, parameter);
- break;
- case 'emergencystop':
- const { source: esSource, action: esAction } = msg.payload;
- ggc.handleInput(esSource, esAction);
- break;
- case 'safetySensor':
- if(typeof msg.payload === "boolean") {
- const safetySensor = msg.payload;
- ggc.safetySensor = safetySensor;
- }
-
- break;
- }
-
- if (done) done();
- } catch (error) {
- node.error("Error processing input: " + error.message);
- if (done) done(error);
- }
- });
-
- node.on('close', function(done) {
- if (node.interval_id) clearTimeout(node.interval_id);
- if (node.tick_interval) clearInterval(node.tick_interval);
- if (done) done();
- });
-
- } catch (error) {
- node.error("Fatal error in node initialization: " + error.stack);
- node.status({fill: "red", shape: "ring", text: "Fatal Error"});
- }
- }
-
- RED.nodes.registerType("ggc", ggc);
-};
\ No newline at end of file
diff --git a/mgc.js b/mgc.js
index a553f2c..b260289 100644
--- a/mgc.js
+++ b/mgc.js
@@ -149,7 +149,6 @@ module.exports = function (RED) {
};
try{
-
await mg.handleInput(source,Qd);
msg.topic = mg.config.general.name;
msg.payload = "done";