Engineering-Research-and-Development / iotagent-opcua

IoT Agent for OPC UA protocol
https://iotagent-opcua.rtfd.io/
GNU Affero General Public License v3.0
41 stars 21 forks source link

Attributes are not updated in the OCB #84

Closed alberto072710 closed 1 year ago

alberto072710 commented 1 year ago

I am trying to communicate with an external opc server, the communication is established correctly and the iot agent receives the updates and sends the patch command to the OCB but it does not update the values of the attributes.

Captura de pantalla 2022-11-22 125938

The OCBreceives the patch command

Captura de pantalla 2022-11-22 130129

But when I query via postman the attribute has not been updated

Captura de pantalla 2022-11-22 130314

If I send the same patch command as the OCB agent through postman if it updates the attribute value

Captura de pantalla 2022-11-22 130535 Captura de pantalla 2022-11-22 130557 Captura de pantalla 2022-11-22 130623

Thank you very much for the help.

manfredipist commented 1 year ago

Hello @alberto072710, I need few more informations to support you. 1) what version of iotagent are you using? Could you repeat this exact scenario on iotagent v2? you can find it both on dockerhub (iotagent4fiware/iotagent-opcua:2.0.0) and under the "iotagent-v2" branch 2) Could you provide your config.js configuration once you've customized the examples provided?

P.S You should be using the PUT method to update the value of any of your entities' attributes instead of overwriting them with the PATCH e.g: curl --location --request PUT 'http://localhost:1026/v2/entities/age01_Car/attrs/Engine_Oxigen?type=Device' \ --header 'Accept: application/json' \ --header 'Fiware-Service: opcua_car' \ --header 'Fiware-ServicePath: /demo' \ --header 'Content-Type: application/json' \ --data-raw '{ "value": 5, "type":"Number" }'

alberto072710 commented 1 year ago

I have tried to do it with iotagent4fiware/iotagent-opcua:2.0.0 but any logs appear...

The config.js.

{ "logLevel": "DEBUG", "contextBroker": { "host": "orion", "port": 1026 }, "server": { "port": 4001, "baseRoot": "/" }, "deviceRegistry": { "type": "memory" }, "mongodb": { "host": "iotmongo", "port": "27017", "db": "iotagent", "retries": 5, "retryTime": 5 }, "types": { "Habitacion": { "service": "opcua_car", "subservice": "/demo", "active": [ { "name": "temperature", "type": "Float" }, { "name": "pressure", "type": "Integer" } ], "lazy": [], "commands": [] } }, "browseServerOptions": null, "service": "opcua_car", "subservice": "/demo", "providerUrl": "http://iotage:4001", "pollingExpiration": "200000", "pollingDaemonFrequency": "20000", "deviceRegistrationDuration": "P1M", "defaultType": null, "contexts": [ { "id": "Habitacion:001", "type": "Habitacion", "service": "opcua_car", "subservice": "/demo", "polling": "false", "mappings": [ { "ocb_id": "pressure", "opcua_id": "ns=4;i=4", "object_id": null, "inputArguments": [] }, { "ocb_id": "temperature", "opcua_id": "ns=4;i=3", "object_id": null, "inputArguments": [] } ] } ], "contextSubscriptions": [] }

The docker-compose file:

version: "3" secrets: age_idm_auth: file: age_idm_auth.txt

services: iotage: hostname: iotage image: iotagent4fiware/iotagent-opcua:latest networks:

volumes: iotmongo_data: iotmongo_conf: orion_mongo_data: orion_mongo_conf:

networks: hostnet: iotnet: ocbnet:

manfredipist commented 1 year ago

IotAgent v2.0 brings many breaking changes thus you should re-download the whole project from here: https://github.com/Engineering-Research-and-Development/iotagent-opcua/tree/iotagent-v2 and customize the config.js file you can find in "conf" folder (examples are also provided)

Once you've configured your agent, you can run it locally by executing, from the root of the project, the "iotagent-opcua" binary you can find in the "bin" folder, otherwise, you can run it with docker by running the "docker-compose up" command from the "docker" folder. P.S: Don't forget to edit the docker-compose according to your needs.

alberto072710 commented 1 year ago

I just tried version 2 and it still doesn't update the attributes. I attach the screenshots where it is seen that the iot agent receives the temperature value 27 and the screenshot where the fiware-orion receives that 27. When I do a get of the entities from postman I receive another value.

Captura de pantalla 2022-11-23 092552 Captura de pantalla 2022-11-23 092619 Captura de pantalla 2022-11-23 092643

var config = {};

config.iota = {
    /**
     * Configures the log level. Appropriate values are: FATAL, ERROR, INFO, WARN and DEBUG.
     */
    logLevel: 'DEBUG',
    /**
     * When this flag is active, the IoTAgent will add the TimeInstant attribute to every entity created, as well
     * as a TimeInstant metadata to each attribute, with the current timestamp.
     */
    timestamp: true,
    /**
     * Context Broker configuration. Defines the connection information to the instance of the Context Broker where
     * the IoT Agent will send the device data.
     */
    contextBroker: {
        /**
         * Host where the Context Broker is located.
         */
        host: 'localhost',
        /**
         * Port where the Context Broker is listening.
         */
        port: '1026',
        /**
         * Version of the Context Broker (v2 or ld)
         */
        ngsiVersion: 'v2',
        /**
         * JSON LD Context
         */
        jsonLdContext: 'https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld',
        /**
         * Used as fallbackTenant
         */
        service: 'opcua_car',
        /**
         * Used as fallbackPath
         */
        subservice: '/demo'
    },
    /**
     * Configuration of the North Port of the IoT Agent.
     */
    server: {
        /**
         * Port where the IoT Agent will be listening for NGSI and Provisioning requests.
         */
        port: 4041
    },

    /**
     * Configuration for secured access to instances of the Context Broker secured with a PEP Proxy.
     * For the authentication mechanism to work, the authentication attribute in the configuration has to be fully
     * configured, and the authentication.enabled subattribute should have the value `true`.
     *
     * The Username and password should be considered as sensitive data and should not be stored in plaintext.
     * Either encrypt the config and decrypt when initializing the instance or use environment variables secured by
     * docker secrets.
     */
    //authentication: {
    //enabled: false,
    /**
     * Type of the Identity Manager which is used when authenticating the IoT Agent.
     */
    //type: 'keystone',
    /**
     * Name of the additional header passed to hold the identity of the IoT Agent
     */
    //header: 'X-Auth-Token',
    /**
     * Hostname of the Identity Manager.
     */
    //host: 'localhost',
    /**
     * Port of the Identity Manager.
     */
    //port: '5000',
    /**
     * Username for the IoT Agent - Note this should not be stored in plaintext.
     */
    //user: 'IOTA_AUTH_USER',
    /**
     * Password for the IoT Agent - Note this should not be stored in plaintext.
     */
    //password: 'IOTA_AUTH_PASSWORD',
    /**
     * OAuth2 client ID - Note this should not be stored in plaintext.
     */
    //clientId: 'IOTA_AUTH_CLIENT_ID',
    /**
     * OAuth2 client secret - Note this should not be stored in plaintext.
     */
    //clientSecret: 'IOTA_AUTH_CLIENT_SECRET'
    //},

    /**
     * Defines the configuration for the Device Registry, where all the information about devices and configuration
     * groups will be stored. There are currently just two types of registries allowed:
     *
     * - 'memory': transient memory-based repository for testing purposes. All the information in the repository is
     *             wiped out when the process is restarted.
     *
     * - 'mongodb': persistent MongoDB storage repository. All the details for the MongoDB configuration will be read
     *             from the 'mongodb' configuration property.
     */
    deviceRegistry: {
        type: 'mongodb'
    },
    /**
     * Mongo DB configuration section. This section will only be used if the deviceRegistry property has the type
     * 'mongodb'.
     */
    mongodb: {
        /**
         * Host where MongoDB is located. If the MongoDB used is a replicaSet, this property will contain a
         * comma-separated list of the instance names or IPs.
         */
        host: 'localhost',
        /**
         * Port where MongoDB is listening. In the case of a replicaSet, all the instances are supposed to be listening
         * in the same port.
         */
        port: '27017',
        /**
         * Name of the Mongo database that will be created to store IoT Agent data.
         */
        db: 'iotagent_opcua'
    },
    /**
     * Types array for static configuration of services. Check documentation in the IoT Agent Library for Node.js for
     *  further details:
     *
     *      https://github.com/Engineering-Research-and-Development/iotagent-opcua#type-configuration
     */
    types: {
        "Habitacion" : {
              "service" : "opcua_car",
              "subservice" : "/demo",
              "active" : [ {
                "name" : "temperature",
                "type" : "Float"
              }, {
                "name" : "pressure",
                "type" : "Integer"
              } ],
              "lazy" : [ ],
              "commands" : [ ]
        }
    },
    contexts: [
    {
        "id": "Habitacion:001",
        "type": "Habitacion",
        "service": "opcua_car",
        "subservice": "/demo",
        "polling": "false",
        "mappings": [
            {
                "ocb_id": "pressure",
                "opcua_id": "ns=4;i=4",
                "object_id": null,
                "inputArguments": []
            },
            {
                "ocb_id": "temperature",
                "opcua_id": "ns=4;i=3",
                "object_id": null,
                "inputArguments": []
            }
        ]
    }
    ],
    contextSubscriptions: [],
    /**
     * Default service, for IoT Agent installations that won't require preregistration.
     */
    service: 'opcua_car',
    /**
     * Default subservice, for IoT Agent installations that won't require preregistration.
     */
    subservice: '/demo',
    /**
     * URL Where the IoT Agent Will listen for incoming updateContext and queryContext requests (for commands and
     * passive attributes). This URL will be sent in the Context Registration requests.
     */
    providerUrl: 'http://localhost:4041',
    /**
     * Default maximum expire date for device registrations.
     */
    deviceRegistrationDuration: 'P20Y',
    /**
     * Default type, for IoT Agent installations that won't require preregistration.
     */
    defaultType: 'Device',
    /**
     * Default resource of the IoT Agent. This value must be different for every IoT Agent connecting to the IoT
     * Manager.
     */
    defaultResource: '/iot/opcua',
    /**
     * flag indicating whether the incoming measures to the IoTAgent should be processed as per the "attributes" field.
     */
    explicitAttrs: false
};

config.opcua = {
    /**
     * Endpoint where the IoT Agent will listen for an active OPC UA Server.
     */
    endpoint: 'opc.tcp://192.168.2.1:4840/PLC',
    /**
     * Security Mode to access OPC UA Server.
     */
    securityMode: 'None',
    /**
     * Security Policy to access OPC UA Server.
     */
    securityPolicy: 'None',
    /**
     * Username to access OPC UA Server.
     */
    username: null,
    /**
     * Password to access OPC UA Server.
     */
    password: null,
    /**
     * Flag indicating whether the OPC uA variables readings should be handled as single subscription.
     */
    uniqueSubscription: false,
    /**
     * Specific for mapping tool.
     * Flag to enable polling TBD.
     */
    polling: false,
    /**
     * Specific for mapping tool.
     * agentId.
     */
    agentId: 'age01_',
    /**
     * Specific for mapping tool.
     * namespaces must be ignored by mappingTool processing.
     */
    namespaceIgnore: '0,7',
    /**
     * Specific for mapping tool.
     * name assigned to the entity
     */
    entityId: 'age01_Car',
    /**
     * Specific for mapping tool.
     * type assigned to the entity
     */
    entityType: 'Device'
};

/**
 * map {name: function} of extra transformations avaliable at JEXL plugin
 *  see https://github.com/telefonicaid/iotagent-node-lib/tree/master/doc/expressionLanguage.md#available-functions
 */

config.jexlTransformations = {};

/**
 * flag indicating whether the incoming notifications to the IoTAgent should be processed using the bidirectionality
 * plugin from the latest versions of the library or the OPCUA-specific configuration retrieval mechanism.
 */
config.configRetrieval = false;
/**
 * Default API Key, to use with device that have been provisioned without a Configuration Group.
 */
config.defaultKey = 'iot';
/**
 * Default transport protocol when no transport is provisioned through the Device Provisioning API.
 */
config.defaultTransport = 'OPCUA';
/**
 * flag indicating whether the node server will be executed in multi-core option (true) or it will be a
 * single-thread one (false).
 */
//config.multiCore = false;
/**
 * flag indicating whether or not to provision the Group and Device automatically
 */
config.autoprovision = true;

module.exports = config;

Thanks.

manfredipist commented 1 year ago

Hello @alberto072710 , could you please try to test the environment with the following configs?

docker-compose.yml

version: "3.1"

volumes:
  mongodb: ~

services:
  iot-agent:
    image: iotagent4fiware/iotagent-opcua:2.0.0
    hostname: iotagent-opcua
    depends_on:
      - mongodb
      - orion
    networks:
      - hostnet
    ports:
      - "4041:4041"
      - "9229:9229"
    environment:
      - "IOTA_CB_HOST=orion"
      - "IOTA_CB_PORT=1026"
      - "IOTA_NORTH_PORT=4041"
      - "IOTA_REGISTRY_TYPE=mongodb"
      - "IOTA_MONGO_HOST=mongodb"
      - "IOTA_MONGO_PORT=27017"
      - "IOTA_MONGO_DB=iotagent_opcua"
      - "IOTA_PROVIDER_URL=http://iotagent-opcua:4041"
    volumes:
      - ../conf/config.js:/opt/iotagent-opcua/conf/config.js
    extra_hosts:
      - "SIMATIC.S7-1200:192.168.2.1"

  mongodb:
    image: mongo:4.2
    hostname: mongodb
    networks:
      - hostnet
    expose:
      - "27017"
    command: --bind_ip_all
    volumes:
      - mongodb:/data

  orion:
    image: fiware/orion
    hostname: orion
    depends_on:
      - mongodb
    networks:
      - hostnet
    ports:
      - "1026:1026"
    command: -dbhost mongodb -logLevel DEBUG

networks:
  hostnet:

config.js

var config = {};
config.iota = {
    logLevel: 'DEBUG',
    timestamp: true,
    contextBroker: {
        host: 'orion',
        port: '1026',
        ngsiVersion: 'v2',
        jsonLdContext: 'https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context.jsonld',
        service: 'opcua_home',
        subservice: '/demo'
    },
    server: {
        port: 4041
    },
    deviceRegistry: {
        type: 'mongodb'
    },
    mongodb: {
        host: 'mongodb',
        port: '27017',
        db: 'iotagent_opcua'
    },
    types: {
        Habitacion: {
            active: [
                {
                    name: 'pressure',
                    type: 'Integer'
                },
                {
                    name: 'temperature',
                    type: 'Float'
                }
            ],
            lazy: [],
            commands: []
        }
    },
    contexts: [
        {
            id: 'Habitacion:001',
            type: 'Habitacion',
            mappings: [
                {
            "ocb_id": "pressure",
            "opcua_id": "ns=4;i=4",
            "object_id": null,
            "inputArguments": []
        },
        {
            "ocb_id": "temperature",
            "opcua_id": "ns=4;i=3",
            "object_id": null,
            "inputArguments": []
        }
            ]
        }
    ],
    contextSubscriptions: [],
    service: 'opcua_home',
    subservice: '/demo',
    providerUrl: 'http://iotagent-opcua:4041',
    deviceRegistrationDuration: 'P20Y',
    defaultType: 'Habitacion',
    defaultResource: '/iot/opcua',
    explicitAttrs: false
};

config.opcua = {
    endpoint: 'opc.tcp://192.168.2.1:4840/PLC',
    securityMode: 'None',
    securityPolicy: 'None',
    username: null,
    password: null,
    uniqueSubscription: false,
    polling: false,
    agentId: 'age01_',
    namespaceIgnore: '0,7',
    entityId: 'Habitacion:001',
    entityType: 'Habitacion'
};

config.jexlTransformations = {};

config.configRetrieval = false;
config.defaultKey = 'iot';
config.defaultTransport = 'OPCUA';
//config.multiCore = false;
config.autoprovision = true;

module.exports = config;
alberto072710 commented 1 year ago

It finally worked. I forgot to put the header when doing the get

curl -X GET \
  http://localhost:1026/v2/entities \
  -H 'fiware-service: opcua_car' \
  -H 'fiware-servicepath: /demo'
manfredipist commented 1 year ago

Glad to hear that. Closing the issue.