node-opcua / opcua-commander

a opcua client with blessed (ncurses)
MIT License
211 stars 46 forks source link

Issue in writing a OPC-Tag/Variable - wrong ValueType #33

Closed georges-schutz closed 2 years ago

georges-schutz commented 2 years ago

Hi all, I am new to github and opcua-commander but not new to opcua. First thank you to have written such a useful client, I use it in case of remote ssh server connection where only a shell is available. Especially the docker container integration is really handy as on that server I need to avoid modifying OS packages but docker is available.

For browsing and reading OPC variables this works grate and fast and is very convenient. As an input I needed to change the docker command a little to make it work due to networking aspects in docker. docker run --network host -it commander -e opc.tcp://localhost:4080

But the writing to a variable seem to be buggy. It is working but it destroys the ValueType/VariantType so that the variable is not usable any more after writing with opcua-commander. If I write with another client (python GUI FreeOpcUa Client or any own python scripts I can re-write the tag and the value is OK again also in the opcua-commander.

I am not a node-js programmer, but I looked up the code and I think the write issue may come from somewhere in opcua-commander/lib/model/model.ts in the writeNode() function at least it is where the WriteValue() method from node-opcua-client lib is used and where also the Variant() value is created. Is this it possible that this code line value.dataType = dataType.text.split(" ")[0]; results in a wrong representation of the dataType to use here?

As a test environment I use a simple python opcua server. But I can also use other professional OPCUA servers on some production sides.

georges-schutz commented 2 years ago

Here a writing to a tag screenshot:

After submitting the value I see some items in the Info-Box where especially the value: Variant(Scalar<10>, value 7) (see screenshot) strikes me as <10> should refer to the ValueType().

Screenshot_Info_after_submit The writing ends without an error but the monitored Tag reads Variant(Scalar\, value: \) Screenshot_Info2_after_submit

opcua-commander and also other OPCUA Client cannot read this Tag correctly any more.

Screenshot_Attributes_after writing

georges-schutz commented 2 years ago

Hi again in case if anybody interested I found a solution/fix that seems to work at least for me.

diff --git a/lib/model/model.ts b/lib/model/model.ts
index 4544277..c499789 100644
--- a/lib/model/model.ts
+++ b/lib/model/model.ts
@@ -301,10 +301,11 @@ export class Model extends EventEmitter {
     const dataType = this.getAttributeValue(attributes, AttributeIds.DataType);
     const arrayDimension = this.getAttributeValue(attributes, AttributeIds.ArrayDimensions);
     if (dataType) {
-      const value = new Variant();
-      value.dataType = dataType.text.split(" ")[0];
-      value.value = data;
-      value.arrayType = arrayDimension.text > 0 ? VariantArrayType.Array : VariantArrayType.Scalar;
+      const value = new Variant({
+        dataType: dataType.text.split(" ")[0],
+        value: data,
+        arrayType: arrayDimension.text > 0 ? VariantArrayType.Array : VariantArrayType.Scalar,
+      });
       const writeValue = new WriteValue({
         nodeId: node.nodeId,
         attributeId: AttributeIds.Value,

I cannot be sure about that fix in any situation but it does get me to use the tool for all the types I use in my work. If someone more knowledgeable could validate this and may be correct the original code/repository this would be grate. best Georges

georges-schutz commented 2 years ago

Just an additional feedback, Float, Int and its variants like Int32,UInt32 do work fine with this modification. But I have en error with Boolean Type variables. It seems that this type is not handled in the coerceVariantType() (variant.ts of node-opcua-variant module). I tried it with writing true/false and 0/1 and non of this is working. The data given to the constructor is a string "true"/"false" "1"/"0" is not converted to a type conform value. Finally isValidVariant() reruns with an error.

Error: Invalid variant arrayType: Scalar  dataType: Boolean value:1 (javascript type = string )
    at constructHook (/opt/opcuacommander/node_modules/node-opcua-variant/source/variant.ts:472:19)
    at new Variant (/opt/opcuacommander/node_modules/node-opcua-variant/source/variant.ts:112:26)
    at Model.writeNode (/opt/opcuacommander/lib/model/model.ts:304:21)
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
    at Form.<anonymous> (/opt/opcuacommander/lib/view/view.ts:249:33)

I can live with that by not using OPCUA Boolean types as long as I have the OPC-Server configuration in hand but it would be nice to have this issue also fixed.

erossignon commented 2 years ago

fix in version 0.18.0

georges-schutz commented 2 years ago

Hi all and thank you for the fix. I have pulled the 0.18.0 code base and rebuild the docker container. I have tested the same write action and this does produce the following exception

Error: dimension can only provided if variant is a matrix
    at assert (/opt/opcuacommander/node_modules/node-opcua-assert/source/index.ts:12:21)
    at constructHook (/opt/opcuacommander/node_modules/node-opcua-variant/source/variant.ts:486:15)
    at new Variant (/opt/opcuacommander/node_modules/node-opcua-variant/source/variant.ts:112:26)
    at Model.writeNode (/opt/opcuacommander/lib/model/model.ts:311:21)
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
    at Form.<anonymous> (/opt/opcuacommander/lib/view/view.ts:238:23)

Base on that and my previous research, I have just removed the dimension property at Variant creation.

diff --git a/lib/model/model.ts b/lib/model/model.ts
@@ -311,7 +311,7 @@ export class Model extends EventEmitter {
       const value = new Variant({
         dataType,
         arrayType: valueRank === -1 ? VariantArrayType.Scalar : valueRank === 1 ? VariantArrayType.Array : VariantArrayType.Matrix,
-        dimensions: arrayDimension,
+//        dimensions: arrayDimension,
         value: data,
       });
       const writeValue = new WriteValue({

With that I am back to be able to just write scalar opc-variables. The error in writing Boolean types is still present.

Error: Invalid variant arrayType: Scalar  dataType: Boolean value:1 (javascript type = string )
    at constructHook (/opt/opcuacommander/node_modules/node-opcua-variant/source/variant.ts:472:19)
    at new Variant (/opt/opcuacommander/node_modules/node-opcua-variant/source/variant.ts:112:26)
    at Model.writeNode (/opt/opcuacommander/lib/model/model.ts:311:21)
    at processTicksAndRejections (node:internal/process/task_queues:94:5)
    at Form.<anonymous> (/opt/opcuacommander/lib/view/view.ts:238:23)