Closed boualid closed 3 years ago
I have coded this with Typescript. Have to take a look how to do same as flow.
Just mention that OPCUA IIoT nodes are from another package.
thank you for the prompt response, could you please send me the path in witch you share the code. thank you
I looked my code and it is totally different. I suppose I have to add it into the client node as own operation.
I need to test it a bit, but just few lines.
could you please share your test. that'll help me to understand the code behaviour. thank you
In my code eventId seems to be problem:
async function acknowledge_input(msg) {
console.log(chalk.cyan("A&C MSG: ") + stringify(msg.payload));
// ConditionId == Alarm object nodeId like Prosys ns=6;s=MyLevel.Alarm eventId is ByteString that identifies event instance
// Event payload object
// {"EventId":"0x00000000000000f100000000000000ee","SourceName":"MyLevel","Time":"2021-09-01T18:43:44.820Z","ReceiveTime":"2021-09-01T18:43:44.820Z","Message":"Level exceeded","Severity":500,"Retain":true,"EnabledState":"Enabled","Quality":{"value":0},"StatusText":"Good (0x00000)","AckedState":"Unacknowledged","ActiveState":"Inactive","HighLimit":70,"LowLimit":30,"HighHighLimit":90,"LowLowLimit":10}
verbose_log("Acknowledge: " + msg.topic + " conditionId: " + msg.nodeId + " eventId: " + msg.eventId + " comment: " + msg.comment);
try {
const status = await node.session.acknowledgeCondition(coerceNodeId(msg.nodeId), opcua.coerceByteString(msg.eventId), opcua.coerceLocalizedText(msg.comment));
if (status !== opcua.StatusCodes.Good) {
node_error(node.name + " error at acknowledge, status: " + status.toString());
set_node_errorstatus_to("error", status.toString());
}
}
catch(err) {
node_error(node.name + " error at acknowledge: " + stringify(err));
set_node_errorstatus_to("error", err);
}
}
I asked this from @erossignon and he will check this. EventId and nodeId are correct but Prosys UA Simulation Server has branch value null and inside node-opcua this is causing BadEventIdUnknown error code. Let´s wait...
ok, thanks a lot Mika
Now it works:
I will publish this one as starting point. I will add alarm objects to server.
Function node contains now needed parameters:
Available v0.2.237
hello mika,
First of all, i want to thank you for your collaboration. I tried several times to generate an acknowledgement to an alarm, by flowing your example, but unfortunately i did not success. In fact each time i activate the flow, Node-RED stop to run.
Please find, on the below screen shot, the details of what i did: 1- the tree structure of the alarms 2- the parameters of the node function:
i think the problem is at the value assigned to the parameters. could you help me. thank you.
Can you check actual ns=1;s=Green.Alarm1.Alm04.EventId value? There seems to be [20] before actual 0x ByteString value. Is it just your tool that shows it.
This is Prosys UA Simulation Server address space, note that MyLevel.Alarm object must contain: 1) Acknowledge method and 2) EventId
hello,
In response to your first question about the Event ID, according to UA Expert and Prosys OPC tools, the value of EventID of the alarm Alm04 is .
Yes, i confirm that the name space of the object Alm04 contain Acknowledge method and EventId see the below screen shot
also, i succeeded to acknowledge the alarm using UA Expert tools
thank you
hello, please find the content of the message error when i run the flow
Sorry msg.topic must contain nodeId, see code below:
Don' t mix msg.topic and msg.conditionId to different alarm object / eventId.
You can run "node-red -v FLOW.json" then verbose is on and parameter will become to console.
Please check nodeId for both objects with UaExpert.
event i wrote the same code, like you mentioned, in the node function, but i always got eventId=null. please take a look on the below error message.
should i add msg.eventId in my funtion or is there something missing from me?
thank you
Typo or wrong nodeId, I asked you to check actual nodeId with UaExpert. UaExpert shows in hiearchy browseName, not actual nodeId. Look panel on right:
I expect you are missing part of the NodeId, perhaps it is: msg.topic = "ns=1;s=Green.Alarm1.Alm04"; msg.conditionId = "ns=1;s=Green.Alarm1.Alm04.EventId";
i am sorry, i misunderstand. i have a question: in the case of the value of NodeId = ns=1;i=1001, should i assign msg topic and conditionId like below:
thank you for your patience and collaboration
Yes if they are Alm03 + EventId for it. Or Alm04 + EventId for it.
Did it work?
You can acknowledge only active alarm
Alarm have states and also it can be non acknowledgeable alarm
Yes, i acknowledge only the active alarm witch has AckedState === false. the problem is that I can not understand why the "acknowledgeCondition" function, in client_tools.ts file, returns errors although I am sure that the values that I pass in parameter are correct (conditionId and EventId). if you don't mind, i send you my OPCUA Server in private in order make test in your side.
thank you
Ok, no problem. I had long weekend.
hello, please find the entire code of my opcua server
var opcua = require("node-opcua");
var server = new opcua.OPCUAServer({
port: 4334, // the port of the listening socket of the server
resourcePath: "UA/MyLittleServer", // this path will be added to the endpoint resource name
buildInfo: {
productName: "MySampleServer1",
buildNumber: "7658",
buildDate: new Date(2021, 8, 28)
}
});
server.initialize(post_initialize);
function post_initialize() {
console.log("initialized");
construct_my_address_space(server, function () {
server.start(function () {
console.log("Server is now listening ... ( press CTRL+C to stop)");
console.log("port ", server.endpoints[0].port);
var endpointUrl = server.endpoints[0].endpointDescriptions()[0].endpointUrl;
console.log(" the primary server endpoint url is ", endpointUrl);
});
});
}
function construct_my_address_space(server, callback) {
var addressSpace = server.engine.addressSpace;
// declare a new object
var device = addressSpace.addObject({
organizedBy: addressSpace.rootFolder.objects,
browseName: "MyDevice"
});
// add a variable named MyVariable1 to the newly created folder "MyDevice"
var variable1 = 1;
// emulate variable1 changing every 500 ms
setInterval(function () { variable1 += 1; }, 500);
addressSpace.addVariable({
componentOf: device,
nodeId: "ns=1;s=variable_1",
browseName: "MyVariable1",
dataType: "Double",
value: {
get: function () {
return new opcua.Variant({ dataType: opcua.DataType.Double, value: variable1 });
}
}
});
addressSpace.installAlarmsAndConditionsService();
var green = addressSpace.addObject({
browseName: "Green",
eventNotifier: 0x1,
notifierOf: addressSpace.rootFolder.objects.server,
organizedBy:addressSpace.rootFolder.objects.server
});
source = addressSpace.addObject({
browseName: "Alarm1",
componentOf: green,
eventSourceOf: green
});
setTimeout(alarm, 5000, "Alm01", addressSpace, "Alm01", "MyFirstAlarm", 800, "Alm01, created by oualid");
setTimeout(alarm, 10000, "Alm02", addressSpace, "Alm02", "MyFirstAlarm", 200, "Alm02, created by oualid");
callback();
}
function alarm(condition, addressSpace, nameOfBrowse1, nameOfBrowse2, severity , msg){
var alarmSourceTime = new Date(); // From external source
const NodeId = require("node-opcua-nodeid").NodeId;
const alarmConditionType = addressSpace.findEventType("AlarmConditionType");
const alarm = alarmConditionType.instantiate({
componentOf: source,
conditionSource: source,
browseName: nameOfBrowse1
});
var alarmNode = addressSpace.instantiateAlarmCondition("AlarmConditionType", {
conditionName: "Error",
conditionClass: "ProcessConditionClassType",
conditionSource: source,
inputNode: NodeId.NullNodeId,
//componentOf: NodeId.NullNodeId,
browseName: nameOfBrowse2,
}, []);
var branch = alarmNode.currentBranch();
alarmNode.setSourceName(condition);
branch._set_var("sourceName", "String", condition);
alarmNode.activateAlarm();
branch.setMessage(msg);
branch.setSeverity(severity);
branch.setTime(alarmSourceTime);
branch.setReceiveTime(new Date());
branch.setAckedState(false);
branch.setActiveState(false);
branch.renewEventId();
alarmNode.raiseConditionEvent(branch, true);
}
thank you
I have to fix first your code, now it works, but I added/fixed instantiation. I expect it was creating new nodeId always. It made is impossible to acknowledge alarm as new object was created.
Works, now. I made changes to your server.js. Just quick ones, you need to modify it more perhaps...
Here:
var opcua = require("node-opcua");
async function main() {
var server = new opcua.OPCUAServer({
port: 4334, // the port of the listening socket of the server
resourcePath: "/UA/MyLittleServer/", // this path will be added to the endpoint resource name
buildInfo: {
productName: "MySampleServer1",
buildNumber: "7658",
buildDate: new Date(2021, 8, 28)
}
});
await server.start();
console.log("Server is now listening ... ( press CTRL+C to stop)");
console.log("port ", server.endpoints[0].port);
var endpointUrl = server.endpoints[0].endpointDescriptions()[0].endpointUrl;
console.log(" the primary server endpoint url is ", endpointUrl);
post_initialize(server);
}
function post_initialize(server) {
console.log("initialized");
construct_my_address_space(server, function () {
console.log("Address space created!")
});
}
function construct_my_address_space(server, callback) {
var addressSpace = server.engine.addressSpace;
var namespace = addressSpace.getOwnNamespace();
// declare a new object
var device = namespace.addObject({
organizedBy: addressSpace.rootFolder.objects,
browseName: "MyDevice"
});
// add a variable named MyVariable1 to the newly created folder "MyDevice"
var variable1 = 1;
// emulate variable1 changing every 500 ms
setInterval(function () { variable1 += 1; }, 500);
var variable = namespace.addVariable({
componentOf: device,
nodeId: "ns=1;s=variable_1",
browseName: "MyVariable1",
dataType: "Double",
value: {
get: function () {
return new opcua.Variant({ dataType: opcua.DataType.Double, value: variable1 });
}
}
});
server.engine.addressSpace.installAlarmsAndConditionsService();
var green = namespace.addObject({
// parent: device,
organizedBy: device,
// propertyOf: device,
browseName: "Green",
eventNotifier: 0x1,
notifierOf: addressSpace.rootFolder.objects.server,
organizedBy:addressSpace.rootFolder.objects.server
});
source = namespace.addObject({
browseName: "Alarm1",
nodeId: "ns=1;s=Alarm1",
componentOf: green,
eventSourceOf: green
});
setTimeout(alarm, 5000, "Alarm1-Alm01", addressSpace, "Alarm1-Alm01", "MyFirstAlarm", 800, "Alarm1-Alm01, created by oualid", source);
setTimeout(alarm, 10000, "Alarm1-Alm02", addressSpace, "Alarm1-Alm02", "MyFirstAlarm", 200, "Alarm1-Alm02, created by oualid", source);
callback();
}
function alarm(condition, addressSpace, nameOfBrowse1, nameOfBrowse2, severity , msg, source){
var alarmSourceTime = new Date(); // From external source
var NodeId = require("node-opcua-nodeid").NodeId;
const alarmConditionType = addressSpace.findEventType("AlarmConditionType");
const alarm = alarmConditionType.instantiate({
componentOf: source,
conditionSource: source,
browseName: nameOfBrowse1
});
var namespace = addressSpace.getOwnNamespace();
var alarmNode = addressSpace.findNode("ns=1;s=" + nameOfBrowse2);
if (!alarmNode) {
alarmNode = namespace.instantiateAlarmCondition("AlarmConditionType", {
conditionName: "Error",
conditionClass: "ProcessConditionClassType",
conditionSource: source,
inputNode: source, // NodeId.NullNodeId,
//componentOf: NodeId.NullNodeId,
browseName: nameOfBrowse1,
nodeId: "ns=1;s=" + nameOfBrowse1
}, []);
}
var branch = alarmNode.currentBranch();
alarmNode.setSourceName(condition);
// branch._set_var("sourceName", "String", condition);
alarmNode.activateAlarm();
branch.setMessage(msg);
branch.setSeverity(severity);
branch.setTime(alarmSourceTime);
branch.setReceiveTime(new Date());
branch.setAckedState(false);
branch.setActiveState(true); // Must be Active
branch.renewEventId();
const eventId = addressSpace.generateEventId();
// console.log("EventId node:" + alarmNode.eventId.toString() + " value: " + eventId.toString());
const ret = alarmNode.eventId.setValueFromSource({dataType: opcua.DataType.ByteString, value: eventId.value});
alarmNode.raiseConditionEvent(branch, true);
}
main()
hello Mika , first of all , i want to thank you very much for your help. Unlucky, Even i copied your code, i still have a problem and i am so sorry for that.
thanks a lot for your help
it's possible please provide me your flow that you used to test the acknowledge function. thank you
Here, just keep in mind that you don´t create new nodes, it´s enough to raise new condition. MYLITTLESERVER.txt
Can be that I modified code and didn´t test it again. Sorry, but I expect you can learn more by studying it as you fix it.
This code snippet you should look:
const eventId = addressSpace.generateEventId();
console.log("EventId node:" + alarmNode.eventId.nodeId.toString() + " value: " + eventId.toString("hex")); // For node-red
const ret = alarmNode.eventId.setValueFromSource({dataType: opcua.DataType.ByteString, value: eventId.value});
thank you very much
hello,
Currently i am developing OPCUA client using Node Red. I am able to read the event/Alarm from OPC UA server. now i want to acknowledge the same , so i had tried create a data flow, with OPCUA IIoT nodes , that allow to call acknowledgement method for opcua. Here it is:
the content of the node function: Remark: i took the value of eventID from UA Expert
the problem is when i execute the flow i get the below error message:
it seems that the problem is related to Event ID but i didn't know how convert it to ByteString. could you please help me
thanks