• 学习open62541 --- [69] Client监测多个变量值


    有读者问Client如何监测多个变量值,这篇文章给了提示,但是没给例子,本文给出详细例子,使用的open62541版本是1.3.3, 运行环境debian10.5。


    一 准备Server

    首先准备一个server,然后添加2个变量,再加个定时任务来修改这2个变量的值,代码如下,

    // server.c
    
    #include 
    #include 
    #include 
    #include 
    
    #include "open62541.h"
    
    UA_Boolean running = true;
    
    void stopHandler(int sign) {
        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
        running = false;
    }
    
    
    
    UA_NodeId addTheAnswerVariable(UA_Server *server) 
    {
        /* Define the attribute of the myInteger variable node */
        UA_VariableAttributes attr = UA_VariableAttributes_default;
        UA_Int32 myInteger = 1;
        UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
        attr.description = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"the answer");
        attr.displayName = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"the answer");
        attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
        attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
    
        /* Add the variable node to the information model */
        UA_NodeId theAnswerNodeId = UA_NODEID_STRING(1, (char*)"the.answer");
        UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, (char*)"the answer");
        UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
        UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
        UA_Server_addVariableNode(server, theAnswerNodeId, parentNodeId,
                                  parentReferenceNodeId, myIntegerName,
                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr, NULL, NULL);
        
        return theAnswerNodeId;
    }
    
    UA_NodeId addTheAnswer2Variable(UA_Server *server) 
    {
        /* Define the attribute of the myInteger variable node */
        UA_VariableAttributes attr = UA_VariableAttributes_default;
        UA_Int32 myInteger = 1;
        UA_Variant_setScalar(&attr.value, &myInteger, &UA_TYPES[UA_TYPES_INT32]);
        attr.description = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"the answer2");
        attr.displayName = UA_LOCALIZEDTEXT((char*)"en-US", (char*)"the answer2");
        attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
        attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
    
        /* Add the variable node to the information model */
        UA_NodeId theAnswerNodeId = UA_NODEID_STRING(1, (char*)"the.answer2");
        UA_QualifiedName myIntegerName = UA_QUALIFIEDNAME(1, (char*)"the answer2");
        UA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
        UA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
        UA_Server_addVariableNode(server, theAnswerNodeId, parentNodeId,
                                  parentReferenceNodeId, myIntegerName,
                                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), attr, NULL, NULL);
        
        return theAnswerNodeId;
    }
    
    void cycleCallback(UA_Server *server, void *data) 
    {
        static UA_Int32 update = 2;
        static UA_Int32 update2 = 8;
            
        UA_NodeId * idArray = (UA_NodeId*)data;
    
        UA_Variant myVar;
        UA_Variant_init(&myVar);
        UA_Variant_setScalar(&myVar, &update, &UA_TYPES[UA_TYPES_INT32]);
        UA_Server_writeValue(server, idArray[0], myVar);
    
        UA_Variant_init(&myVar);
        UA_Variant_setScalar(&myVar, &update2, &UA_TYPES[UA_TYPES_INT32]);
        UA_Server_writeValue(server, idArray[1], myVar);
        
        update++;
        update2++;
        
        if (update == 100)
        {
            update = 2;
        }
    
        if (update2 == 200)
        {
            update = 8;
        }
    }
    
    
    int main(void) 
    {    
        signal(SIGINT, stopHandler);
        signal(SIGTERM, stopHandler);
    
        UA_Server *server = UA_Server_new();
        UA_ServerConfig_setDefault(UA_Server_getConfig(server));
        
        UA_NodeId targetNodeId = addTheAnswerVariable(server);
        UA_NodeId target2NodeId = addTheAnswer2Variable(server);
    
        UA_NodeId idArr[2] = {targetNodeId, target2NodeId};
    
        UA_UInt64 callbackId = 0;
    	UA_Server_addRepeatedCallback(server, cycleCallback, idArr, 2000, &callbackId); // call every 2s
        
      
        UA_StatusCode retval = UA_Server_run(server, &running);
        
        UA_Server_delete(server);
        
        return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119

    这里使用了定时接口来做修改任务。


    二 Client代码

    代码如下,

    #include 
    #include 
    #include "open62541.h"
    
    
    UA_Boolean running = true;
    
    
    UA_NodeId idArr[2] = {UA_NODEID_STRING(1, (char*)"the.answer"), UA_NODEID_STRING(1, (char*)"the.answer2")};
    
    void stopHandler(int sign) {
        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, "received ctrl-c");
        running = false;
    }
    
    
    static void handler_DataChanged(UA_Client *client, UA_UInt32 subId, 
                                        void *subContext, UA_UInt32 monId, 
                                        void *monContext, UA_DataValue *value) 
    {
        UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, "Received Notification");
    
        UA_NodeId *ptr = (UA_NodeId*)monContext;
    
        if (UA_NodeId_equal(ptr, &idArr[0]))
        {
            UA_Int32 currentValue = *(UA_Int32*)(value->value.data);
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, "SubId:%u, MonId:%u, Current Value: %d\n", 
                                                                subId, monId, currentValue);
        }
        else if (UA_NodeId_equal(ptr, &idArr[1]))
        {
            UA_Int32 currentValue = *(UA_Int32*)(value->value.data);
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, "SubId:%u, MonId:%u, Current Value: %d\n", 
                                                                subId, monId, currentValue);
        }
    }
    
    
    
    
    void addMonitoredItemToVariable(UA_Client *client)
    {
        /* Create a subscription */
        UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
        UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
                                                                                NULL, NULL, NULL);
    
        UA_UInt32 subId = response.subscriptionId;
        if(response.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
        {
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, "Create subscription succeeded, id %u\n", subId);
        }
    
        
    	UA_MonitoredItemCreateRequest items[2];
        UA_UInt32 newMonitoredItemIds[2];
        UA_Client_DataChangeNotificationCallback callbacks[2];
        UA_Client_DeleteMonitoredItemCallback deleteCallbacks[2];
        void *contexts[2];
    
        /* monitor "ths answer" */
        items[0] = UA_MonitoredItemCreateRequest_default(idArr[0]);
        callbacks[0] = handler_DataChanged;
        contexts[0] = &idArr[0];
        deleteCallbacks[0] = NULL;
    
        /* monitor "the answer2" */
        items[1] = UA_MonitoredItemCreateRequest_default(idArr[1]);
        callbacks[1] = handler_DataChanged;
        contexts[1] = &idArr[1];
        deleteCallbacks[1] = NULL;
    
    
        UA_CreateMonitoredItemsRequest createRequest;
        UA_CreateMonitoredItemsRequest_init(&createRequest);
        createRequest.subscriptionId = subId;
        createRequest.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH;
        createRequest.itemsToCreate = items;
        createRequest.itemsToCreateSize = 2;
        UA_CreateMonitoredItemsResponse createResponse =
           UA_Client_MonitoredItems_createDataChanges(client, createRequest, contexts,
                                                       callbacks, deleteCallbacks);
    
    
    	for (uint32_t i = 0; i < createResponse.resultsSize; ++i)
    	{
    		if (createResponse.results->statusCode != UA_STATUSCODE_GOOD)
    		{
    			printf("==> error\n");
    		}
    	}
    
    }
    
    int main(void) 
    {
        signal(SIGINT, stopHandler);
        signal(SIGTERM, stopHandler);
    
    
        UA_Client *client = UA_Client_new();
        UA_ClientConfig_setDefault(UA_Client_getConfig(client));
        UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
        if(retval != UA_STATUSCODE_GOOD) 
        {
            UA_Client_delete(client);
            return (int)retval;
        }
    
        addMonitoredItemToVariable(client);
    
        while(running)
        {
            // send publish request, time out 1000ms
            UA_Client_run_iterate(client, 1000); 
        }
    
        UA_Client_delete(client); /* Disconnects the client internally */
        
        return EXIT_SUCCESS;
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124

    关键部分在addMonitoredItemToVariable()里,其实也比较简单,就是挨个赋值,2个监测项都使用相同的回调函数,里面会判断节点的nodeid,注意代码里使用了一个全局数组idArr来保存目标id。


    三 运行

    如何编译不再赘述,最后运行如下,
    在这里插入图片描述
    可以看到MonId是不同的,说明监测成功!

  • 相关阅读:
    C++数据结构X篇_12_树的基本概念和存储
    vue-cil之elementui、vuex(任务管理器)
    LeetCode-28-找出字符串中第一个匹配项的下标
    计算机毕业设计ssm校园竞赛管理系统设计与实现hyr9b系统+程序+源码+lw+远程部署
    bp神经网络 损失函数,bp神经网络参数优化
    利用Tensorrt实现int8量化
    如何创建加载项(1)
    基于微信小程序的高校宿舍信息管理系统设计与实现(源码+lw+部署文档+讲解等)
    2-Java进阶知识总结-7-UDP-TCP
    华为云计算之物理节点CNA安装教程
  • 原文地址:https://blog.csdn.net/whahu1989/article/details/126841525