Timv505

Data Collection and Display

9 posts in this topic

Currently I am using DDE links in Excel to run a live "dashboard" with our cycle times and faults/downtime. I was wondering what the best solution would be if I wanted to display a dashboard with this information on a TV within the plant but I only have 1 license of RSLinx Gateway. OPC perhaps? SQL? I attached a picture describing what I need

Capture.PNG

Edited by Timv505

Share this post


Link to post
Share on other sites

Tim - best is in the mind and eye of the designer/user.  Unless your PLC logic archives data for a period of time you might want to look at some form of data historian and display HMI.  The two favorites I've worked with are OSISoft PI / PI Vision and Archestra Wonderware with InSQL Historian.  That said Ignition and GE-IFIX also offer excellent potential.  The questions you need to ask up front are Cost, Scalability and User Base Size.  Both now and into the next five years.

Share this post


Link to post
Share on other sites

Tim,

There are several ways to tackle this and way to many options. It all boils down to budget and how reliable you want the system to be, how often does it need to update, etc.).

The easiest way and easiest for upkeep is an HMI that is somewhere stashed away, that you know off, that is pulling the data from your plc (PLC is keeping track) - create a webbrowser  (me panelviews have viewpoint) and point the tv with a pc to that website. If more tv's need to be added in the future, you point all those TV's to the same HMI address.

You can create an VB or excel application on a pc and rslinx that goes and pulls the data from the PLC. PC is connected to the TV. AdvancedHMI is another option as well in that category. 

A historian like Bob mentions - in a lot of flavors as well... 

Depending on the PLC, you can add an webpage card to the PLC. (1786-EWEB for example,...) 

 

 

Share this post


Link to post
Share on other sites

I think buying another software is out of the question. I need to come up with a solution using excel and/or RSLinx Gateway. I have a file setup and running on a screen connected to my laptop but management wants the live excel on a different screen. I'm not sure how to do this without buying another license

Share this post


Link to post
Share on other sites

Using Javascript and node.js you can build a webpage that displays data pulled with OPC from the RSlinx Gateway OPC server.

 

https://node-opcua.github.io/

 

1 person likes this

Share this post


Link to post
Share on other sites

Boblfoot I sucessfully done this If anybody wants my opc server code let me know.  You could also Cip message into allen bradley from node red

Share this post


Link to post
Share on other sites
1 hour ago, mmd604 said:

Boblfoot I sucessfully done this If anybody wants my opc server code let me know.  You could also Cip message into allen bradley from node red

I would definitely appreciate that mmd604

Share this post


Link to post
Share on other sites

function constructAlarmAddressSpace(server, addressSpace, eventObjects, done) {
  // server = the created node-opcua server
  // addressSpace = address space of the node-opcua server
  // eventObjects = add event variables here to hold them in memory from this script

  // internal sandbox objects are:
  // node = the compact server node,
  // coreServer = core compact server object for debug and access to NodeOPCUA
  // this.sandboxNodeContext = node context node-red
  // this.sandboxFlowContext = flow context node-red
  // this.sandboxGlobalContext = global context node-red
  // this.sandboxEnv = env variables
  // timeout and interval functions as expected from nodejs

  const opcua = coreServer.choreCompact.opcua;
  const LocalizedText = opcua.LocalizedText;
  const namespace = addressSpace.getOwnNamespace();

  const Variant = opcua.Variant;
  const DataType = opcua.DataType;
  const DataValue = opcua.DataValue;

  var flexServerInternals = this;

  this.sandboxFlowContext.set("isoInput1", 0);
  this.setInterval(() => {
    flexServerInternals.sandboxFlowContext.set(
      "isoInput1",
      Math.random() + 50.0
    );
  }, 500);
  this.sandboxFlowContext.set("isoInput2", 0);
  this.sandboxFlowContext.set("isoInput3", 0);
  this.sandboxFlowContext.set("isoInput4", 0);
  this.sandboxFlowContext.set("isoInput5", 0);
  this.sandboxFlowContext.set("isoInput6", 0);
  this.sandboxFlowContext.set("isoInput7", 0);
  this.sandboxFlowContext.set("isoInput8", 0);
  this.sandboxFlowContext.set("isoInput9", 0);

  this.sandboxFlowContext.set("isoOutput1", 0);
  this.setInterval(() => {
    flexServerInternals.sandboxFlowContext.set(
      "isoOutput1",
      Math.random() + 10.0
    );
  }, 500);

  this.sandboxFlowContext.set("isoOutput2", 0);
  this.sandboxFlowContext.set("isoOutput3", 0);
  this.sandboxFlowContext.set("isoOutput4", 0);
  this.sandboxFlowContext.set("isoOutput5", 0);
  this.sandboxFlowContext.set("isoOutput6", 0);
  this.sandboxFlowContext.set("isoOutput7", 0);
  this.sandboxFlowContext.set("isoOutput8", 0);
  this.sandboxFlowContext.set("isoOutput9", 0);

  coreServer.debugLog("init dynamic address space");
  const rootFolder = addressSpace.findNode("RootFolder");

  node.warn("construct new address space for OPC UA");

  const myDevice = namespace.addFolder(rootFolder.objects, {
    "browseName": "RaspberryPI-Zero-WLAN"
  });
  const gpioFolder = namespace.addFolder(myDevice, { "browseName": "GPIO" });
  const isoInputs = namespace.addFolder(gpioFolder, {
    "browseName": "Inputs"
  });
  const isoOutputs = namespace.addFolder(gpioFolder, {
    "browseName": "Outputs"
  });

  const gpioDI1 = namespace.addVariable({
    "organizedBy": isoInputs,
    "browseName": "I1",
    "nodeId": "ns=1;s=Isolated_Input1",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoInput1")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoInput1",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDI2 = namespace.addVariable({
    "organizedBy": isoInputs,
    "browseName": "I2",
    "nodeId": "ns=1;s=Isolated_Input2",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoInput2")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoInput2",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDI3 = namespace.addVariable({
    "organizedBy": isoInputs,
    "browseName": "I3",
    "nodeId": "ns=1;s=Isolated_Input3",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoInput3")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoInput3",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDI4 = namespace.addVariable({
    "organizedBy": isoInputs,
    "browseName": "I4",
    "nodeId": "ns=1;s=Isolated_Input4",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoInput4")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoInput4",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDI5 = namespace.addVariable({
    "organizedBy": isoInputs,
    "browseName": "I5",
    "nodeId": "ns=1;s=Isolated_Input5",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoInput5")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoInput5",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDI6 = namespace.addVariable({
    "organizedBy": isoInputs,
    "browseName": "I6",
    "nodeId": "ns=1;s=Isolated_Input6",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoInput6")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoInput6",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDI7 = namespace.addVariable({
    "organizedBy": isoInputs,
    "browseName": "I7",
    "nodeId": "ns=1;s=Isolated_Input7",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoInput7")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoInput7",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDI8 = namespace.addVariable({
    "organizedBy": isoInputs,
    "browseName": "I8",
    "nodeId": "ns=1;s=Isolated_Input8",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoInput8")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoInput8",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });
 
  const gpioDI9 = namespace.addVariable({
    "organizedBy": isoInputs,
    "browseName": "I9",
    "nodeId": "ns=1;s=Isolated_Input9",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoInput9")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoInput9",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });
  const gpioDO1 = namespace.addVariable({
    "organizedBy": isoOutputs,
    "browseName": "O1",
    "nodeId": "ns=1;s=Isolated_Output1",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoOutput1")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoOutput1",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDO2 = namespace.addVariable({
    "organizedBy": isoOutputs,
    "browseName": "O2",
    "nodeId": "ns=1;s=Isolated_Output2",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoOutput2")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoOutput2",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDO3 = namespace.addVariable({
    "organizedBy": isoOutputs,
    "browseName": "O3",
    "nodeId": "ns=1;s=Isolated_Output3",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoOutput3")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoOutput3",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDO4 = namespace.addVariable({
    "organizedBy": isoOutputs,
    "browseName": "O4",
    "nodeId": "ns=1;s=Isolated_Output4",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoOutput4")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoOutput4",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDO5 = namespace.addVariable({
    "organizedBy": isoOutputs,
    "browseName": "O5",
    "nodeId": "ns=1;s=Isolated_Output5",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoOutput5")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoOutput5",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDO6 = namespace.addVariable({
    "organizedBy": isoOutputs,
    "browseName": "O6",
    "nodeId": "ns=1;s=Isolated_Output6",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoOutput6")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoOutput6",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDO7 = namespace.addVariable({
    "organizedBy": isoOutputs,
    "browseName": "O7",
    "nodeId": "ns=1;s=Isolated_Output7",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoOutput7")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoOutput7",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDO8 = namespace.addVariable({
    "organizedBy": isoOutputs,
    "browseName": "O8",
    "nodeId": "ns=1;s=Isolated_Output8",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoOutput8")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoOutput8",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });

  const gpioDO9 = namespace.addVariable({
    "organizedBy": isoOutputs,
    "browseName": "O9",
    "nodeId": "ns=1;s=Isolated_Output9",
    "dataType": "Double",
    "value": {
      "get": function() {
        return new Variant({
          "dataType": DataType.Double,
          "value": flexServerInternals.sandboxFlowContext.get("isoOutput9")
        });
      },
      "set": function(variant) {
        flexServerInternals.sandboxFlowContext.set(
          "isoOutput9",
          parseFloat(variant.value)
        );
        return opcua.StatusCodes.Good;
      }
    }
  });
  //------------------------------------------------------------------------------
  // Add a view
  //------------------------------------------------------------------------------
  const viewDI = namespace.addView({
    "organizedBy": rootFolder.views,
    "browseName": "RPIW0-Digital-Ins"
  });

  const viewDO = namespace.addView({
    "organizedBy": rootFolder.views,
    "browseName": "RPIW0-Digital-Outs"
  });

  viewDI.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDI1.nodeId
  });

  viewDI.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDI2.nodeId
  });

  viewDI.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDI3.nodeId
  });

  viewDI.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDI4.nodeId
  });

  viewDI.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDI5.nodeId
  });

  viewDI.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDI6.nodeId
  });

  viewDI.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDI7.nodeId
  });

  viewDI.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDI8.nodeId
  });
    
    viewDI.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDI9.nodeId
  });
 
  viewDO.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDO1.nodeId
  });

  viewDO.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDO2.nodeId
  });

  viewDO.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDO3.nodeId
  });

  viewDO.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDO4.nodeId
  });

  viewDO.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDO5.nodeId
  });

  viewDO.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDO6.nodeId
  });

  viewDO.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDO7.nodeId
  });

  viewDO.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDO8.nodeId
  });
   viewDO.addReference({
    "referenceType": "Organizes",
    "nodeId": gpioDO9.nodeId
  });

  coreServer.debugLog("create dynamic address space done");
  node.warn("construction of new address space for OPC UA done");

  done();
}

 

Share this post


Link to post
Share on other sites

Download and install node red and then install this pallet "node-red-contrib-opcua-server"   

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now