How to make selectable option in OPC-UA? - node.js

Assuming having a read/write variable called Fruit.
Selectable options are Apple, Pear, Strawberry & Pineapple.
Using OptionSetType seems to be the most suiteable way.
But I did not find any examples for node-opcua
Can somebody provide an example or is there another/better/smarter way?

Enumeration become my best friend
const fruitEnumType = ownNameSpace.addEnumerationType({
browseName: "Fruits",
enumeration: ["apple", "pear", "strawberry", "pineapple"],
});
let selected = "apple";
ownNameSpace.addVariable({
browseName: "Fruit",
componentOf: folder,
dataType: fruitEnumType,
value: {
get: () =>
new Variant({
dataType: DataType.String,
value: selected,
}),
set: (value: Variant) => {
selected = value.value;
return StatusCodes.Good;
},
},
});

The UAVariable class in node-opcua comes with two helpers methods that make it easy to deal with enumeration. readEnumValue and writeEnumValue .
You will find this form more practical:
const fruit2 = ownNameSpace.addVariable({
browseName: "Fruit2s",
componentOf: myObject,
dataType: fruitEnumType
});
fruit2.writeEnumValue("strawberry");
console.log("enum value = ", fruit2.readEnumValue());
console.log("enum value name = ", fruit2.readEnumValue().name);
console.log("enum value value = ", fruit2.readEnumValue().value);
console.log("dataValue is ", fruit2.readValue().toString());
enum value = { value: 2, name: 'strawberry' }
enum value name = strawberry
enum value value = 2
dataValue is { /* DataValue */
value: Variant(Scalar<Int32>, value: 2)
statusCode: Good (0x00000)
serverTimestamp: 2021-01-23T08:59:04.273Z $ 990.400.000
sourceTimestamp: 2021-01-23T08:59:04.273Z $ 990.400.000
}
Note: that you don't need to use the get/set form as well as the value is already store inside the variable.

Related

Formik initial value partially undefined to result type

with a type icecream i have this model.
enum Sugar {
High = 1,
Medium = 2,
Low = 3,
}
Type IceCream = {
Name:string;
SugarContent: Sodium
}
now, in my formik form i wanna create a form with initial values, where sugarcontent is undefined. But it has to be set in the form according to my validiationschema (yup)
sugar: yup
.number()
.required("Sugar content is required")
.min(1)
.max(3)
is it possible to get a correctly typed form output for this? Something like the following as an idea
Type FormIceCream = {
Name:string;
SugarContent?: Sugar
}
const InitialValues:FormIceCream = {
Name:"",
SugarContent:undefined
}
return <Formik<IceCream>
initialValues={InitialValues} // <-- warning, Type 'undefined' is not assignable to type 'SugarContent'
validationSchema={IceCreamValidation}
onSubmit={(values:IceCream) => console.log(values)}
> ...

How do i get a randomly selected string name and still select an existing substring without the code coming out as text

I'm currently trying to get info off of an object but that's randomly selected. I believe that the true problem is that what I wrote is not being taken as a variable for selecting an existing object if not as the variable for the object, I don't know if this is a clear message or not.
Example of what I have tried:
let PK = ["Random1", "Random2", "Random3"]
let PKS = Math.floor(Math.random() * PK.length)
let Random1 = {
name: "Random1",
number: "010"
}
let Random2 = {
name: "Random2",
number: "011"
}
if(message.content.toLowerCase() == "random"){
message.channel.send(PK[PKS].number)
}
There is another thing I have tried which is by using ${}. These are the results:
"Random1.number" or "Random2.number" when what I was looking for is actually "010" or "011".
You should wrap your objects inside some collection such as an Array and then you just compare the value from your random selection to the value find in the collection (if any (randoms)):
let PK = ["Random1", "Random2", "Random3"];
let PKS = Math.floor(Math.random() * PK.length);
const randoms = [
{
name: "Random1",
number: "010",
},
{
name: "Random2",
number: "011",
},
];
if (message.content.toLowerCase() == "random") {
const findRandom = randoms.find((v) => v.name === PK[PKS]);
if (findRandom) {
message.channel.send(findRandom.number);
}
}

How to resolve Enums as String values with Node grpc?

Using grpc with Node, Enums in responses to my queries are resolving as integer values. However, when I make the same queries with BloomRPC, the Enums resolve as Integer values.
Is there a parameter or option to force these Enums to be resolved as String using Node grpc?
In our project, we use enum to help us ensure the integrity of a finite set of possibilities by eliminating human error. Why should we need to remember what the string value is when we have the protocol buffer enum so handy? Thus, we use the .proto as the source of truth; that's our rule.
To do that, follow these steps, which are written for ES6+ code.
Define your gRPC/Protobuf enum in a .proto file.
// life.proto
syntax = 'proto3';
package life;
enum Choices
{
EAT = 0;
DRINK = 1;
SLEEP = 2;
CODE = 3;
SKI = 4;
}
Install #grpc/proto-loader and #grpc/grpc-js.
$ npm i -s #grpc/proto-loader #grpc/grpc-js
Import the modules that pay the bills, so to speak. Load the .proto file directly into memory (don't compile).
// myNodeApp.js
import * as grpc from '#grpc/grpc-js'
import * as protoLoader from '#grpc/proto-loader'
import path from 'path'
// these options help make definitions usable in our code
const protoOptions = {
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
}
// this allows us to prepare the path to the current dir
const dir = path.dirname(new URL(import.meta.url).pathname)
// this loads the .proto file
const lifeDef = protoLoader.loadSync(path.join(dir, 'life.proto'), protoOptions)
// this loads the package 'life' from the .proto file
const life = grpc.loadPackageDefinition(lifeDef).life
Take a peek at the enum Choices definition (in the same file).
// myNodeApp.js (cont'd)
console.log(life.Choices)
/* stdout */
{
format: 'Protocol Buffer 3 EnumDescriptorProto',
type: {
value: [ [Object], [Object], [Object], [Object], [Object] ],
name: 'Choices',
options: null
},
fileDescriptorProtos: [
<Buffer 0a ... 328 more bytes>
]
}
...look deeper...
console.log(life.Choices.value)
/* stdout */
{
value: [
{ name: 'EAT', number: 0, options: null },
{ name: 'DRINK', number: 1, options: null },
{ name: 'SLEEP', number: 2, options: null },
{ name: 'CODE', number: 3, options: null },
{ name: 'SKI', number: 4, options: null }
],
name: 'Choices',
options: null
}
Use the enum.
// myNodeApp.js
const myDay = { // plain JSON (or define a gRPC message, same same)
dawn: life.Choices.type.value[1].name,
morning: life.Choices.type.value[0].name,
afternoon: life.Choices.type.value[4].name,
evening: life.Choices.type.value[3].name,
night: life.Choices.type.value[2].name
}
You could write an accessor or utility function to manage the key lookup (by passing the imported grpc enum and index), like so:
export const getEnumByName = function (protoEnum, needle) {
return protoEnum.type.value.find(p => {
return p.name === needle
})
}
export const getEnumByNum = function (protoEnum, needle) {
return protoEnum.type.value.filter(p => {
return p.number = needle
})
}
export const getEnumKeys = function (protoEnum, key = 'name') {
return protoEnum.type.value.map(p => {
return p[key]
})
}
Inverting and assigning a value to a Message is what's already covered in other answers, just set the enum field to the string value using, you guessed it, the string that represents the enum name, which you access using the code above.
This is along the lines of how we do it. Clean and simple, just a touch obscure until you look "under the hood" one day.
Learn more about #grpc/proto-loader and #grpc/grpc-js. Hope this helps someone out there in the wild. :)
If you are using the #grpc/proto-loader library, you can set the option enums to the value String (not the string "String", the constructor function String). Then all enum values will be represented by their name strings.

adding an assign function as property to an object in NodeJs

for the sake of fun and exploring nodeJS I made an object
var f15c = {
fuel : 10000,
IRST: true,
AESA: true,
speed: 2500,
Ammo:
{
AMRAAM: 6,
Python5: 2,
Delilah: 3,
},
tailnumber : the question begins here.
}
The problem came when I wanted to add tailnumber that is not the same for every plane but should be assigned to the plane.
what is the methode?
var f15c = {
...
tailnumber = function (tn){"whats should i add here?"}
}
or
var f15c = {
...
tailnumber: ?? what should i place here?
SetTailNumber = function(tn)
{
tailnumber=tn;
}
}
or must I have the entire F15c as a function?
var f15c = function(tn) {
...
tailnumber = tn;
but then i cannot set the entire variables complex.
or perhaps I'm doing it wrong and should refer the variable as an individual F15 and use a different function to create it?
but then how do I make that field in a way it is unassigned and waiting to be assigned (and then saves the assigned number)?
would appreciate some heads up
The secret is to use this to refer to a property of the own object
var f15c = {
...
tailnumber: null,
setTailNumber : function(tn)
{
this.tailnumber=tn;
}
}
Then:
f15c.setTailNumber(1234);
console.log(f15c.tailnumber);
Do you mean you want to set a value to a property?
var f15c = {
_tailnumber: 0,
set tailnumber(newtailnumber) {
this._tailnumber = newtailnumber;
},
get tailnumber() {
return this._tailnumber
}
};
f15c.tailnumber = "304";
console.log(f15c.tailnumber);
console.log(f15c);

jqgrid, autocomplete under several input boxes

For jqGrid, how to do autocomplete under several input boxes, namely A, B, C. After the input A, autocomplete values provided by B need to have a reference from input A.
For the dataInit at input B, I can only get the original content of input A, not the current input one.
Any idea or link so that I can pay attention to. Thanks
B/R
Gene Leung
Here is the code:
...
{ name:'order_no',
index:'order_no',
align:"center",
width:80,
editable:true,
editoptions:
{
dataInit: function (elem) {
myAutocomplete(elem, "./autoComplete.php?id=sales_no");
},
dataEvents: [
{ type: 'change',
fn: function(e) {
savedSalesNo = $(this).val();
//console.log( savedSalesNo );
}
}
]
}
},
{ name:'item_no',
index:'item_no',
width:120,
editable:true,
editoptions:
{
dataInit: function (elem) {
myAutocomplete(elem, "./autoComplete.php?id=sales_items&vchr_no=" + savedSalesNo);
}
}
},
... php code: ...
if isset($_GET["term"]))
$maskTP = $_GET['term'];
else
$maskTP = "";
$sWhere = "WHERE 1=1";
if($maskTP!='') {
switch ($_GET["id"]) {
case "sales_no":
$sWhere.= " AND name LIKE '%$maskTP%'";
$sSQL = "SELECT name AS order_no FROM sale_order ". $sWhere ." ORDER BY name";
break;
case "sales_items":
$sWhere.= " AND name LIKE '%$maskTP%'";
$sSQL = "SELECT name AS order_no FROM sale_order ". $sWhere ." ORDER BY name";
break;
}
}
$result = $db->Execute( $sSQL );
Can you post some code snippet it will be helpful.
But looking at your question what i understand is you need to autocomplete in B based on A and so on.
So what you can do is while making ajax request for the B autocomplete check the value A and pass it in your call and perform your business logic.

Resources