Nodejs OPCUA multiple monitored items in a subscription object - node.js

i need subscribe to mutliple monitored item on a subcripiton object. I build below codes in nodejs and working.
const itemToMonitor = {
nodeId: resolveNodeId("ns=2;s=Channel1.Device1.temprature"),
attributeId: AttributeIds.Value
};
const itemToMonitor2 = {
nodeId: resolveNodeId("ns=2;s=Channel1.Device1.altitude"),
attributeId: AttributeIds.Value
};
const monitoringParamaters = {
samplingInterval: 1000,
discardOldest: true
};
the_subscription.monitor(itemToMonitor, monitoringParamaters, TimestampsToReturn.Both, (err, monitoredItem) => {
monitoredItem.on("changed", function (dataValue) {
console.log("monitored item changed: temprature = ", dataValue.value.value);
});
});
the_subscription.monitor(itemToMonitor2, monitoringParamaters, TimestampsToReturn.Both, (err, monitoredItem) => {
monitoredItem.on("changed", function (dataValue) {
console.log("monitored item changed: altitude = ", dataValue.value.value);
});
});
but i need something like that :
the_subscription.monitor({itemToMonitor,itemToMonitor2}, monitoringParamaters, TimestampsToReturn.Both, (err, monitoredItem) => {
monitoredItem.on("changed", function (datavalues) {
datavalues.each(){
//
}
});
});
Is it possible ? I did something similar to this in .net core:
.net core codes (what i want sample)
_subscription.AddItems(_nodes);
_subscription.FastDataChangeCallback = new FastDataChangeNotificationEventHandler(DataChanged);
_session.AddSubscription(_subscription);
_subscription.Create();
private void DataChanged(Subscription subscription, DataChangeNotification notification, IList<string> stringTable)
{
//
}

I solved;
its wrong;
the_subscription.monitor({itemToMonitor,itemToMonitor2}, monitoringParamaters, TimestampsToReturn.Both, (err, monitoredItem) => {
monitoredItem.on("changed", function (datavalues) {
});
});
its true
//monitoredNodes is an monitoredItem list
the_subscription.monitorItems(monitoredNodes, monitoringParamaters, TimestampsToReturn.Both, (err, monitoredItems) => {
monitoredItems.on("changed", function (items,data) {
console.log("Node ID: ", items.itemToMonitor.nodeId.value);
console.log("Node value: ", data.value.value);
});
});
Document : https://node-opcua.github.io/api_doc/2.32.0/classes/node_opcua.clientsubscription.html#monitoritems

Related

Discord button only works once discord.js

I have posted a button but it only works once
but after that when I use it again
Also
How can I reply to message if I use deferUpdate it shows
Code
client.on('ready', () => {
client.user.setActivity('people and managing the server', {
type: 'WATCHING',
});
const channel = client.channels.cache.get('894171605608042496');
const row = new MessageActionRow().addComponents(
new MessageButton()
.setCustomId('openTicket')
.setLabel('Create ticket')
.setEmoji('📩')
.setStyle('SECONDARY')
);
channel
.send({
embeds: [
{
title: 'SGAS Tickets',
color: '#388e3c',
description: 'To create a ticket react with 📩',
},
],
components: [row],
})
.then(() => {
const filter = () => {
return true;
};
const collector = channel.createMessageComponentCollector({
filter,
time: 15 * 1000,
});
collector.on('collect', (i) => {
i.deferUpdate().then(() => {
Ticket.count({}, (err, result) => {
if (err) {
console.log(err);
} else {
const ticketNumber = result + 1;
const ticketString = convertNumber(ticketNumber);
const ticket = new Ticket({
tickedId: ticketString,
});
ticket.save((err) => {
if (err) {
console.log(err);
} else {
const myguild = client.guilds.cache.get('887277806386565150');
if (!myguild) {
console.log('guild not found');
return;
}
const category = myguild.channels.cache.find(
(c) =>
c.id === '887277807279947826' &&
c.type == 'GUILD_CATEGORY'
);
if (!category) {
console.log('category not found');
return;
}
myguild.channels
.create(`Ticket#${ticketString}`, {
type: 'GUILD_TEXT',
})
.then(async (myc) => {
myc.setParent(category).then(() => {
myc.send(
`Hello <#${i.user.id}>, your question will be solved here shortly`
);
i.reply({
content: `Go to <#${myc.id}>, for your question`,
ephemeral: true,
});
});
});
}
});
}
});
});
});
});
});
you are using a component collector - which expires in 15 seconds, as seen in your code. That means after 15 seconds your bot stops listening for button clicks. My recommendation is to use the interactionCreate event to listen for that button: see docs https://discord.js.org/#/docs/main/stable/class/ButtonInteraction
Example:
client.on("interactionCreate", (interaction) => {
if(!interaction.isButton()) return;
if(interaction.customId === "openTicket") {
// your ticket code here
}
});

Unable to retrive data and push inside loop in node js

I am trying to retrieve attendance list along with user details.
I am using caminte.js(http://www.camintejs.com/) Cross-db ORM for database interaction.
Here is my code sample of model function "attendanceList".
exports.attendanceList = function (req, callback) {
var query = req.query;
var searchfilters = {};
if(!req.user){
callback({ code:400, status:'error', message: 'Invalid Request', data:{}});
}else{
searchfilters["vendor_id"] = parseInt(req.user._id);
}
if(query.location && parseString(query.location) != '') {
searchfilters["location"] = parseString(query.location);
}
if (query.device_details && parseString(query.device_details) != '') {
searchfilters["device_details"] = parseString(query.device_details);
}
if(query.created_on) {
searchfilters["created_on"] = query.created_on;
}
if(query.status) {
searchfilters["status"] = { regex: new RegExp(query.status.toLowerCase(), "i") };
}
var SkipRecord = 0;
var PageSize = 10;
var LimitRecord = PageSize;
var PageIndex = 1;
if(query.pagesize) {
PageSize = parseInt(query.pagesize);
}
if(query.pageindex) {
PageIndex = parseInt(query.pageindex);
}
if (PageIndex > 1) {
SkipRecord = (PageIndex - 1) * PageSize;
}
LimitRecord = PageSize;
var SortRecord = "created_on";
if(query.sortby && query.sorttype) {
var sortingBy = query.sortby;
var sortingType = 'ASC';
if(typeof query.sorttype !== 'undefined') {
sortingType = query.sorttype;
}
SortRecord = sortingBy + ' ' + sortingType;
}
Attendance.find({ where: searchfilters, order: SortRecord, limit: LimitRecord, skip: SkipRecord }, async function (err, result) {
if(err){
callback({ code:400, status:'error', message:'Unable to connect server', errors:err });
} else {
await result.map(function(row, i){
User.findById(parseInt(row.user_id), function(err, data){
if(err){
console.log(err);
} else {
result[i]['userDetails'] = data;
}
});
});
await Attendance.count({ where: searchfilters }, function (err, count) {
callback({ code:200, status:'success', message:'OK', total:count, data:result });
});
}
});
};
I am getting only attendance list without user details. How do I force to push user details into attendance list? Any Help!!
Thank You
This behavior is asynchronous. When you're making request to DB, your code keeps running, while task to get data comes to task queue.
To keep things simple, you need to use promises while handling asynchronous jobs.
Rewrite your code from this:
Attendance.find({ where: searchfilters, order: SortRecord, limit: LimitRecord, skip: SkipRecord }, async function (err, result) {
if(err){
callback({ code:400, status:'error', message:'Unable to connect server', errors:err });
} else {
await result.map(function(row, i){
User.findById(parseInt(row.user_id), function(err, data){
if(err){
console.log(err);
} else {
result[i]['userDetails'] = data;
}
});
});
await Attendance.count({ where: searchfilters }, function (err, count) {
callback({ code:200, status:'success', message:'OK', total:count, data:result });
});
}
});
To this:
const findAttendanceFirst = (searchFilters, SortRecord, LimitRecord, SkipRecord) => {
return new Promise((resolve, reject) => {
Attendance.find({ where: searchFilters, order: SortRecord, limit: LimitRecord, skip: SkipRecord }, (err, result) => {
if(err) return reject(err);
resolve(result);
});
});
}
const findUserByIdForUserDetails = (userId) => {
return new Promise((resolve, reject) => {
User.findById(parseInt(userId), function(err, data){
if(err) return reject(err);
resolve(data);
})
});
}
const getAttendanceCount = (searchFilters) => {
return new Promise((resolve, reject) => {
Attendance.count({ where: searchFilters }, (err, count) => {
if(err) return reject(err);
resolve(count);
});
})
}
So, now we can use this separate functions to make async behavior looks like sync.
try {
const data = await findAttendanceFirst(searchFilters, SortRecord, LimitRecord, SkipRecord);
for(let userData of data){
try {
userData.userDetails = await findUserByIdForUserDetails(userData.user_id);
} catch(e) {
// Some error happened, so no user details.
// you can set here null or nothing to userDetails.
}
}
let count;
try {
count = await getAttendanceCount(searchFilters);
} catch(e){
// Same as before.
}
const callBackData = { code:200, status:'success', message:'OK', total:count, data:result };
// And here you can do whatever you want with callback data. Send to client etc.
} catch(e) {
}
NB: I've not tested this code, it will be easier for yu to play with your actual data and use Promises and async/await
Just remember that each request to db is asynchronous, and you need to make your code wait for this data.

node opc-ua - how do i discover a variable in a server?

I am learning node opc-ua and have followed the example provided in the GitHub page for the sample_server.js and simple_client.js.
In the sample_server I add a variable when constructing the address space of the server such as:
//this code is in the server
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 });
}
}
});
Here is the whole server code for reference:
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(2014, 5, 2)
}
});
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 });
}
}
});
callback();
}
Now, in the client i want to discover this variable by name or the full nodeId.
I am using the sample provided to browse the session to the server but in the return i only see FolderType, Objects, Types and Views and can not locate this variable anywhere.
Here is the client code:
var opcua = require("node-opcua");
var async = require("async");
var client = new opcua.OPCUAClient();
var endpointUrl = "opc.tcp://" + require("os").hostname() + ":4334/UA/MyLittleServer";
var the_session, the_subscription;
async.series([
// step 1 : connect to
function (callback) {
client.connect(endpointUrl, function (err) {
if (err) {
console.log(" cannot connect to endpoint :", endpointUrl);
} else {
console.log("connected !");
}
callback(err);
});
},
// step 2 : createSession
function (callback) {
client.createSession(function (err, session) {
if (!err) {
the_session = session;
}
callback(err);
});
},
// step 3 : browse
function (callback) {
the_session.browse("RootFolder", function (err, browse_result) {
if (!err) {
console.log('Result of browsing: ', browse_result);
browse_result[0].references.forEach(function (reference) {
console.log('browsing: ', reference.browseName);
console.log(reference);
console.log("**************************************");
});
}
callback(err);
});
},
/* step 4 : read a variable with readVariableValue
function (callback) {
the_session.readVariableValue("ns=1;s=variable_1", function (err, dataValue) {
if (!err) {
console.log(" var 1 = ", dataValue.toString());
}
callback(err);
});
},
// step 4' : read a variable with read
function (callback) {
var max_age = 0;
var nodes_to_read = [
{ nodeId: "ns=1;s=variable_1", attributeId: opcua.AttributeIds.Value }
];
the_session.read(nodes_to_read, max_age, function (err, nodes_to_read, dataValues) {
if (!err) {
console.log(" variable 1 = ", dataValues[0]);
}
callback(err);
});
},
*/
// step 5: install a subscription and install a monitored item for 10 seconds
function (callback) {
the_subscription = new opcua.ClientSubscription(the_session, {
requestedPublishingInterval: 1000,
requestedLifetimeCount: 10,
requestedMaxKeepAliveCount: 2,
maxNotificationsPerPublish: 10,
publishingEnabled: true,
priority: 10
});
the_subscription.on("started", function () {
console.log("subscription started for 2 seconds - subscriptionId=", the_subscription.subscriptionId);
}).on("keepalive", function () {
console.log("keepalive");
}).on("terminated", function () {
callback();
});
setTimeout(function () {
the_subscription.terminate();
}, 10000);
// install monitored item
var monitoredItem = the_subscription.monitor({
nodeId: opcua.resolveNodeId("ns=1;s=variable_1"),
attributeId: opcua.AttributeIds.Value
},
{
samplingInterval: 100,
discardOldest: true,
queueSize: 10
},
opcua.read_service.TimestampsToReturn.Both
);
console.log("-------------------------------------");
monitoredItem.on("changed", function (dataValue) {
console.log("variable_1 = ", dataValue.value.value);
});
},
// close session
function (callback) {
the_session.close(function (err) {
if (err) {
console.log("session closed failed ?");
} else{
console.log("session closed!");
}
callback();
});
}
],
function (err) {
if (err) {
console.log(" failure ", err);
} else {
console.log("done!");
}
client.disconnect(function () { });
});
Thanks in advance
You need to drill down from from the rootFolder and investigate the various objects until you find the variable you want to monitor, with a series of browseNode.
The best option is to use a free OPCUA client from a commercial vendor such as UAExpert or Prosys OPC UA Client to name a few.
You can also use opcua-commander: This little utility will allow you to explore the address space of the server and find the node you're looking for. ( source code available on github )

node js mongo db dependencies (doc not being found)

I have the following code:
var method = PushLoop.prototype;
var agent = require('./_header')
var request = require('request');
var User = require('../models/user_model.js');
var Message = require('../models/message_model.js');
var async = require('async')
function PushLoop() {};
method.startPushLoop = function() {
getUserList()
function getUserList() {
User.find({}, function(err, users) {
if (err) throw err;
if (users.length > 0) {
getUserMessages(users)
} else {
setTimeout(getUserList, 3000)
}
});
}
function getUserMessages(users) {
// console.log("getUserMessages")
async.eachSeries(users, function (user, callback) {
var params = {
email: user.email,
pwd: user.password,
token: user.device_token
}
messageRequest(params)
callback();
}, function (err) {
if (err) {
console.log(err)
setTimeout(getUserList, 3000)
}
});
}
function messageRequest(params) {
var url = "https://voip.ms/api/v1/rest.php?api_username="+ params.email +"&api_password="+ params.pwd +"&method=getSMS&type=1&limit=5"
request(url, function(err, response, body){
if (!err) {
var responseObject = JSON.parse(body);
var messages = responseObject.sms
if (responseObject["status"] == "success") {
async.eachSeries(messages, function(message, callback){
console.log(params.token)
saveMessage(message, params.token)
callback();
}, function(err) {
if (err) {
console.log(err)
}
// setTimeout(getUserList, 3000)
})
} else {
// setTimeout(getUserList, 3000)
}
} else {
console.log(err)
// setTimeout(getUserList, 3000)
}
});
setTimeout(getUserList, 3000)
}
function saveMessage(message, token) {
// { $and: [ { price: { $ne: 1.99 } }, { price: { $exists: true } }
// Message.find({ $and: [{ message_id: message.id}, {device_token: token}]}, function (err, doc){
Message.findOne({message_id: message.id}, function (err, doc){
if (!doc) {
console.log('emtpy today')
var m = new Message({
message_id: message.id,
did: message.did,
contact: message.contact,
message: message.message,
date: message.date,
created_at: new Date().toLocaleString(),
updated_at: new Date().toLocaleString(),
device_token: token
});
m.save(function(e) {
if (e) {
console.log(e)
} else {
agent.createMessage()
.device(token)
.alert(message.message)
.set('contact', message.contact)
.set('did', message.did)
.set('id', message.id)
.set('date', message.date)
.set('message', message.message)
.send();
}
});
}
}) //.limit(1);
}
};
module.exports = PushLoop;
Which actually works perfectly fine in my development environment - However in production (i'm using Openshift) the mongo documents get saved in an endless loop so it looks like the (if (!doc)) condition always return true therefore the document gets created each time. Not sure if this could be a mongoose issue - I also tried the "find" method instead of "findOne". My dev env has node 0.12.7 and Openshift has 0.10.x - this could be the issue, and i'm still investigating - but if anybody can spot an error I cannot see in my logic/code please let me know
thanks!
I solved this issue by using a "series" like pattern and using the shift method on the users array. The mongoose upsert findOneOrCreate is good however if there is a found document, the document is returned, if one isn't found and therefore created, it's also returned. Therefore I could not distinguish between the newly insert doc vs. a found doc, so used the same findOne function which returns null if no doc is found I just create it and send the push notification. Still abit ugly, and I know I could have used promises or the async lib, might refactor in the future. This works for now
function PushLoop() {};
var results = [];
method.go = function() {
var userArr = [];
startLoop()
function startLoop() {
User.find({},function(err, users) {
if (err) throw err;
users.forEach(function(u) {
userArr.push(u)
})
function async(arg, callback) {
var url = "https://voip.ms/api/v1/rest.php?api_username="+ arg.email +"&api_password="+ arg.password +"&method=getSMS&type=1&limit=5"
request.get(url, {timeout: 30000}, function(err, response, body){
if (!err) {
var responseObject = JSON.parse(body);
var messages = responseObject.sms
var status = responseObject.status
if (status === "success") {
messages.forEach(function(m) {
var message = new Message({
message_id: m.id,
did: m.did,
contact: m.contact,
message: m.message,
date: m.date,
created_at: new Date().toLocaleString(),
updated_at: new Date().toLocaleString(),
device_token: arg.device_token
});
var query = { $and : [{message_id: m.id}, {device_token: arg.device_token}] }
var query1 = { message_id: m.id }
Message.findOne(query).lean().exec(function (err, doc){
if (!doc || doc == null) {
message.save(function(e) {
console.log("message saved")
if (e) {
console.log("there is an error")
console.log(e)
} else {
console.log(message.device_token)
var messageStringCleaned = message.message.toString().replace(/\\/g,"");
var payload = {
"contact" : message.contact,
"did" : message.did,
"id" : message.message_id,
"date" : message.date,
"message" : messageStringCleaned
}
var note = new apns.Notification();
var myDevice = new apns.Device(message.device_token);
note.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now.
note.badge = 3;
note.alert = messageStringCleaned;
note.payload = payload;
apnsConnection.pushNotification(note, myDevice);
}
})
}
});
});
}
else {
console.log(err)
}
}
});
setTimeout(function() {
callback(arg + "testing 12");
}, 1000);
}
// Final task (same in all the examples)
function series(item) {
if(item) {
async( item, function(result) {
results.push(result);
return series(userArr.shift());
});
} else {
return final();
}
}
function final() {
console.log('Done');
startLoop();
}
series(userArr.shift())
});
}
}
module.exports = PushLoop;

nodejs orm many to many

Hello Im trying to do associaton with many to many in node using node-orm2.
I have this tables:
project --> id, name
user --> id, name
user_project --> user_fk, project_fk (this is many to many association table)
The controller returns me a list of users and a list of projects, but i need to return in a both another property with projects of every user and users of every prject.
Models:
module.exports = function (orm, db) {
var Project = db.define('project', {
name : { type: 'text', required: true }
},
{
methods: {
serialize: function () {
return {
id : this.id,
name : this.name
};
}
}
});
};
module.exports = function (orm, db) {
var User = db.define('user', {
name : { type: 'text', required: true },
email : { type: 'text', required: true }
},
{
methods: {
serialize: function () {
return {
id : this.id,
name : this.name,
email : this.email
};
}
}
});
};
Controller:
module.exports = {
list: function (req, res, next) {
req.models.project.find().limit(4).order('-created').all(function (err, messages) {
if (err) return next(err);
var projects = messages.map(function (m) {
return m.serialize();
});
console.log(projects);
});
req.models.user.find().limit(4).order('-created').all(function (err, messages) {
if (err) return next(err);
var users = messages.map(function (m) {
return m.serialize();
});
console.log(users);
});
res.sendfile(settings.path + '/public/index2.html');
}
How can I do this I'm confused, I readed the documentation but i don't understand this.
Had some issues with node-orm also...
You can do it with light-orm or bookshelf.js.
In light-orm you can simply extend model with complex request like this:
var SiteCollection = new ORM.Collection({
connector: ORM.driver,
tableName: 'site',
modelExtension: {
getAds: function(callback) {
var query = "SELECT DISTINCT `ads`.* FROM `ads` INNER JOIN `siteads` " +
"ON `ads`.`id` = `siteads`.`ads_id` " +
"WHERE site_id = " + this.get('id');
ORM.Collections.AdsCollection.find(query, callback);
},
renderAds: function(callback) {
var that = this;
this.getAds(function(err, ads) {
var html = ejs.render(adsTemplate, {
content: new ORM.Collection(ads).toJSON()
});
fs.writeFileSync(writeDir + that.get('id') + ".html", html, {
encoding: 'utf8'
});
callback();
});
}
}
});
Try it: https://npmjs.org/package/light-orm

Resources