{"id":4041,"date":"2020-09-07T12:04:44","date_gmt":"2020-09-07T03:04:44","guid":{"rendered":"https:\/\/now0930.pe.kr\/wordpress\/?p=4041"},"modified":"2020-09-07T12:05:41","modified_gmt":"2020-09-07T03:05:41","slug":"open62541-server-%ec%84%a4%ec%a0%95","status":"publish","type":"post","link":"https:\/\/now0930.pe.kr\/wordpress\/open62541-server-%ec%84%a4%ec%a0%95\/","title":{"rendered":"open62541 server \uc124\uc815"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">tutorial\uc744 \ub530\ub77c\ud558\ub2e4 \ubcf4\uba74 \ub0b4\uac00 \ubb34\uc5c7\uc744 \ubaa8\ub974\ub294\uc9c0 \uc798 \ubaa8\ub978\ub2e4. \uc544\ub798 \uac19\uc740 \uadf8\ub9bc\uc744 \uadf8\ub9ac\uace0 \uc2f6\uc5c8\ub294\ub370 \uc798 \uc548\ub41c\ub2e4. \ub0b4\uac00 \uc11c\ubc84\ub97c \uac74\ub4dc\ub9b4 \uc77c\uc740 \uc5c6\uaca0\uc9c0\ub9cc, \ud074\ub77c\uc774\uc5b8\ud2b8\ub97c \ud14c\uc2a4\ud2b8\ud558\ub824\uba74 \uc11c\ubc84\uac00 \ud544\uc694\ud558\ub2e4.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1600\" height=\"900\" src=\"https:\/\/now0930.pe.kr\/wordpress\/wp-content\/uploads\/2020\/09\/Cylinder.png\" alt=\"\" class=\"wp-image-4042\" srcset=\"https:\/\/now0930.pe.kr\/wordpress\/wp-content\/uploads\/2020\/09\/Cylinder.png 1600w, https:\/\/now0930.pe.kr\/wordpress\/wp-content\/uploads\/2020\/09\/Cylinder-768x432.png 768w, https:\/\/now0930.pe.kr\/wordpress\/wp-content\/uploads\/2020\/09\/Cylinder-1536x864.png 1536w\" sizes=\"auto, (max-width: 1600px) 100vw, 1600px\" \/><\/figure>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include \"open62541.h\"\n\n#include &lt;signal.h>\n#include &lt;stdlib.h>\n\nstatic volatile UA_Boolean running = true;\nstatic void stopHandler(int sig) {\n    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, \"received ctrl-c\");\n    running = false;\n}\n\nstatic void\nbeforeReadVal(UA_Server *server,\n               const UA_NodeId *sessionId, void *sessionContext,\n               const UA_NodeId *nodeid, void *nodeContext,\n               const UA_NumericRange *range, const UA_DataValue *data) {\n    \/\/updateCurrentTime(server);\n\tint tmpVal = rand()%1000;\n    UA_Variant value;\n    UA_Variant_setScalar(&amp;value, &amp;tmpVal, &amp;UA_TYPES[UA_TYPES_INT32]);\n    UA_NodeId currentNodeId = UA_NODEID_STRING(1, \"Test Var:Me\");\n    UA_Server_writeValue(server, currentNodeId, value);\n}\n\n\n\/* predefined identifier for later use *\/\nUA_NodeId pumpTypeId = {1, UA_NODEIDTYPE_NUMERIC, {1001}};\nUA_NodeId cylTypeId = {1, UA_NODEIDTYPE_NUMERIC, {2001}};\n\nstatic void\ndefineObjectTypes(UA_Server *server) {\n    \/* Define the object type for \"Device\" *\/\n    UA_NodeId deviceTypeId; \/* get the nodeid assigned by the server *\/\n    UA_ObjectTypeAttributes dtAttr = UA_ObjectTypeAttributes_default;\n    dtAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", \"DeviceType\");\n    UA_Server_addObjectTypeNode(server, UA_NODEID_NULL,\n                                UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),\n                                UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),\n                                UA_QUALIFIEDNAME(1, \"DeviceType\"), dtAttr,\n                                NULL, &amp;deviceTypeId);\n\n    UA_VariableAttributes mnAttr = UA_VariableAttributes_default;\n    mnAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", \"ManufacturerName\");\n    UA_NodeId manufacturerNameId;\n    UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),\n                              UA_QUALIFIEDNAME(1, \"ManufacturerName\"),\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), mnAttr, NULL, &amp;manufacturerNameId);\n    \/* Make the manufacturer name mandatory *\/\n    UA_Server_addReference(server, manufacturerNameId,\n                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),\n                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);\n\n\n    UA_VariableAttributes modelAttr = UA_VariableAttributes_default;\n    modelAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", \"ModelName\");\n    UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),\n                              UA_QUALIFIEDNAME(1, \"ModelName\"),\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), modelAttr, NULL, NULL);\n\n    \/* Define the object type for \"Pump\" *\/\n    UA_ObjectTypeAttributes ptAttr = UA_ObjectTypeAttributes_default;\n    ptAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", \"PumpType\");\n    UA_Server_addObjectTypeNode(server, pumpTypeId,\n                                deviceTypeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),\n                                UA_QUALIFIEDNAME(1, \"PumpType\"), ptAttr,\n                                NULL, NULL);\n\n    UA_VariableAttributes statusAttr = UA_VariableAttributes_default;\n    statusAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", \"Status\");\n    statusAttr.valueRank = UA_VALUERANK_SCALAR;\n    UA_NodeId statusId;\n    UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),\n                              UA_QUALIFIEDNAME(1, \"Status\"),\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), statusAttr, NULL, &amp;statusId);\n    \/* Make the status variable mandatory *\/\n    UA_Server_addReference(server, statusId,\n                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),\n                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);\n\n    UA_VariableAttributes rpmAttr = UA_VariableAttributes_default;\n    rpmAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", \"MotorRPM\");\n    rpmAttr.valueRank = UA_VALUERANK_SCALAR;\n    UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),\n                              UA_QUALIFIEDNAME(1, \"MotorRPMs\"),\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), rpmAttr, NULL, NULL);\n}\n\nstatic void\ndefineCylTypes(UA_Server *server) {\n    \/* Define the object type for \"Device\" *\/\n    UA_NodeId deviceTypeId; \/* get the nodeid assigned by the server *\/\n    UA_ObjectTypeAttributes dtAttr = UA_ObjectTypeAttributes_default;\n    dtAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", \"Cylinder Type\");\n    UA_Server_addObjectTypeNode(server, UA_NODEID_NULL,\n                                UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),\n                                UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),\n                                UA_QUALIFIEDNAME(1, \"Cylinder Type\"), dtAttr,\n                                NULL, &amp;deviceTypeId);\n\n    UA_VariableAttributes mnAttr = UA_VariableAttributes_default;\n    mnAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", \"Manufacturer Name\");\n    UA_NodeId manufacturerNameId;\n    UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),\n                              UA_QUALIFIEDNAME(1, \"Cylinder\"),\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), mnAttr, NULL, &amp;manufacturerNameId);\n\n    UA_VariableAttributes modelAttr = UA_VariableAttributes_default;\n\tUA_NodeId modelNameId;\n    modelAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", \"Cyl Model Name\");\n    UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),\n                              UA_QUALIFIEDNAME(1, \"Cyl Model Name\"),\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), modelAttr, NULL, &amp;modelNameId);\n\n    UA_Server_addReference(server,modelNameId,\n                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),\n                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);\n\n    \/* Define the object type for \"Pump\" *\/\n    UA_ObjectTypeAttributes ptAttr = UA_ObjectTypeAttributes_default;\n    ptAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", \"Running State\");\n    UA_Server_addObjectTypeNode(server, cylTypeId,\n                                deviceTypeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),\n                                UA_QUALIFIEDNAME(1, \"Running State\"), ptAttr,\n                                NULL, NULL);\n\n\n    UA_VariableAttributes statusAttr = UA_VariableAttributes_default;\n    statusAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", \"Status\");\n    statusAttr.valueRank = UA_VALUERANK_SCALAR;\n    UA_NodeId statusId;\n    UA_Server_addVariableNode(server, UA_NODEID_NULL, cylTypeId,\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),\n                              UA_QUALIFIEDNAME(1, \"Status\"),\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), statusAttr, NULL, &amp;statusId);\n    \/* Make the manufacturer name mandatory *\/\n\t\/\/ UA_Server_addReference()\ub97c \uc5b4\ub5bb\uac8c \ud558\ub0d0\uc5d0 \ub530\ub77c  statusId\n\t\/\/ instance \ub9cc\ub4e4\uacbd\uc6b0 \ud45c\uc2dc\n    UA_Server_addReference(server, statusId,\n                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),\n                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);\n}\n\nstatic void\naddPumpObjectInstance(UA_Server *server, char *name) {\n    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;\n    oAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", name);\n    UA_Server_addObjectNode(server, UA_NODEID_NULL,\n                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),\n                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),\n                            UA_QUALIFIEDNAME(1, name),\n                            pumpTypeId, \/* this refers to the object type\n                                           identifier *\/\n                            oAttr, NULL, NULL);\n}\n\nstatic void\naddCylObjectInstance(UA_Server *server, char *name) {\n    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;\n    oAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\", name);\n\t\/*\n\tUA_Server_addObjectNode(UA_Server *server, const UA_NodeId requestedNewNodeId,\n                        const UA_NodeId parentNodeId,\n                        const UA_NodeId referenceTypeId,\n                        const UA_QualifiedName browseName,\n                        const UA_NodeId typeDefinition,\n                        const UA_ObjectAttributes attr,\n                        void *nodeContext, UA_NodeId *outNewNodeId) {\n\t\t\t\t\t\t*\/\n\n    UA_Server_addObjectNode(server, UA_NODEID_NULL,\n                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),\n                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),\n                            UA_QUALIFIEDNAME(1, name),\n                            cylTypeId, \/* this refers to the object type\n                                           identifier *\/\n                            oAttr, NULL, NULL);\n}\n\nstatic UA_StatusCode\npumpTypeConstructor(UA_Server *server,\n                    const UA_NodeId *sessionId, void *sessionContext,\n                    const UA_NodeId *typeId, void *typeContext,\n                    const UA_NodeId *nodeId, void **nodeContext) {\n    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, \"New pump created\");\n\n    \/* Find the NodeId of the status child variable *\/\n    UA_RelativePathElement rpe;\n    UA_RelativePathElement_init(&amp;rpe);\n    rpe.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT);\n    rpe.isInverse = false;\n    rpe.includeSubtypes = false;\n    rpe.targetName = UA_QUALIFIEDNAME(1, \"Status\");\n\n    UA_BrowsePath bp;\n    UA_BrowsePath_init(&amp;bp);\n    bp.startingNode = *nodeId;\n    bp.relativePath.elementsSize = 1;\n    bp.relativePath.elements = &rpe;\n\n    UA_BrowsePathResult bpr =\n        UA_Server_translateBrowsePathToNodeIds(server, &amp;bp);\n    if(bpr.statusCode != UA_STATUSCODE_GOOD ||\n       bpr.targetsSize &lt; 1)\n        return bpr.statusCode;\n\n    \/* Set the status value *\/\n    UA_Boolean status = true;\n    UA_Variant value;\n    UA_Variant_setScalar(&amp;value, &amp;status, &amp;UA_TYPES[UA_TYPES_BOOLEAN]);\n    UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);\n    UA_BrowsePathResult_clear(&amp;bpr);\n\n    \/* At this point we could replace the node context .. *\/\n\n    return UA_STATUSCODE_GOOD;\n}\n\nstatic void\naddPumpTypeConstructor(UA_Server *server) {\n    UA_NodeTypeLifecycle lifecycle;\n    lifecycle.constructor = pumpTypeConstructor;\n    lifecycle.destructor = NULL;\n    UA_Server_setNodeTypeLifecycle(server, pumpTypeId, lifecycle);\n}\n\n\n\n\n\/\/method \ucd94\uac00\nstatic UA_StatusCode\nhelloWorldMethodCallback(UA_Server *server,\n                         const UA_NodeId *sessionId, void *sessionHandle,\n                         const UA_NodeId *methodId, void *methodContext,\n                         const UA_NodeId *objectId, void *objectContext,\n                         size_t inputSize, const UA_Variant *input,\n                         size_t outputSize, UA_Variant *output) {\n    UA_String *inputStr = (UA_String*)input->data;\n    UA_String tmp = UA_STRING_ALLOC(\"Hello \");\n    if(inputStr->length > 0) {\n        tmp.data = (UA_Byte *)UA_realloc(tmp.data, tmp.length + inputStr->length);\n        memcpy(&amp;tmp.data[tmp.length], inputStr->data, inputStr->length);\n        tmp.length += inputStr->length;\n    }\n    UA_Variant_setScalarCopy(output, &amp;tmp, &amp;UA_TYPES[UA_TYPES_STRING]);\n    UA_String_clear(&amp;tmp);\n    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_SERVER, \"Hello World was called\");\n    return UA_STATUSCODE_GOOD;\n}\n\nstatic void\naddHellWorldMethod(UA_Server *server) {\n    UA_Argument inputArgument;\n    UA_Argument_init(&amp;inputArgument);\n    inputArgument.description = UA_LOCALIZEDTEXT(\"en-US\", \"A String\");\n    inputArgument.name = UA_STRING(\"MyInput\");\n    inputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId;\n    inputArgument.valueRank = UA_VALUERANK_SCALAR;\n\n    UA_Argument outputArgument;\n    UA_Argument_init(&amp;outputArgument);\n    outputArgument.description = UA_LOCALIZEDTEXT(\"en-US\", \"A String\");\n    outputArgument.name = UA_STRING(\"MyOutput\");\n    outputArgument.dataType = UA_TYPES[UA_TYPES_STRING].typeId;\n    outputArgument.valueRank = UA_VALUERANK_SCALAR;\n\n    UA_MethodAttributes helloAttr = UA_MethodAttributes_default;\n    helloAttr.description = UA_LOCALIZEDTEXT(\"en-US\",\"Say `Hello World`\");\n    helloAttr.displayName = UA_LOCALIZEDTEXT(\"en-US\",\"Hello World\");\n    helloAttr.executable = true;\n    helloAttr.userExecutable = true;\n    UA_Server_addMethodNode(server, UA_NODEID_NUMERIC(1,62541),\n                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),\n                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),\n                            UA_QUALIFIEDNAME(1, \"hello world\"),\n                            helloAttr, &amp;helloWorldMethodCallback,\n                            1, &amp;inputArgument, 1, &amp;outputArgument, NULL, NULL);\n}\n\n\nint main(void) {\n    signal(SIGINT, stopHandler);\n    signal(SIGTERM, stopHandler);\n\n    UA_Server *server = UA_Server_new();\n    UA_ServerConfig_setDefault(UA_Server_getConfig(server));\n\tUA_ServerConfig* config = UA_Server_getConfig(server);\n\tconfig->verifyRequestTimestamp = UA_RULEHANDLING_ACCEPT;\n\n\t\/\/addVariable(server);\n\t\/\/writeVariable(server);\n\t\/\/writeWrongVariable(server);\n\n\n\t\/\/vendor, serial, variable \uc21c\uc73c\ub85c \ucd94\uac00.\n\n\t\/\/\uacf5\ud1b5\uc73c\ub85c \uc0ac\uc6a9\ud560 \ubd80\ubd84 \uc124\uc815.\n\tUA_NodeId parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);\n\tUA_NodeId parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT);\n\t\/\/variable \ucd94\uac00.\n\tUA_VariableAttributes varAttr = UA_VariableAttributes_default;\n\tUA_Int32 varName = 10;\n    UA_Variant_setScalar(&amp;varAttr.value, &amp;varName, &amp;UA_TYPES[UA_TYPES_INT32]);\n    UA_NodeId varNodeId = UA_NODEID_STRING(1, \"Test Var:Me\");\n\tUA_QualifiedName myVarName = UA_QUALIFIEDNAME(1, \"variable\");\n    UA_Server_addVariableNode(server, varNodeId, parentNodeId,\n                              parentReferenceNodeId, myVarName,\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), varAttr, NULL, NULL);\n\n\t\/\/add callback\n    UA_ValueCallback callback ;\n    callback.onRead = beforeReadVal;\n    callback.onWrite = NULL;\n\tUA_NodeId currentNodeId = UA_NODEID_STRING(1, \"Test Var:Me\");\n    UA_Server_setVariableNode_valueCallback(server, currentNodeId, callback);\n\n\tdefineObjectTypes(server);\n\tdefineCylTypes(server);\n\taddPumpObjectInstance(server, \"pump2\");\n\taddPumpObjectInstance(server, \"pump3\");\n\taddPumpTypeConstructor(server);\n\taddPumpObjectInstance(server, \"pump4\");\n\taddPumpObjectInstance(server, \"pump5\");\n\n\taddCylObjectInstance(server, \"pin1\");\n\taddCylObjectInstance(server, \"pin2\");\n\n\n\n\n\t\/\/method\n\taddHellWorldMethod(server);\n\n\n\t\/\/\uc11c\ubc84 \uad6c\ub3d9.\n\tUA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, \"Starting server...\");\n\tUA_StatusCode retval = UA_Server_run(server, &amp;running);\n\tUA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, \"Shutdown server...\");\n\n\n\tUA_Server_delete(server);\n\treturn retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">object\ub97c define\ud560 \ub54c \uc5b4\ub290 \ubcc0\uc218\ub97c \uc778\uc2a4\ud134\uc2a4\uc5d0 \ud3ec\ud568\ud560\uc9c0 \uacb0\uc815\ud560 \uc218 \uc788\ub2e4. defineCylTypes \ud568\uc218 \uc911 UA_Server_addReference\uc758 \ubcc0\uc218\ub85c \uc804\uc5d0 \uc120\uc5b8\ud55c id\ub97c \ub118\uaca8\uc8fc\uba74 \ubd99\ub294\ub2e4. <\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">    UA_NodeId statusId;\n    UA_Server_addVariableNode(server, UA_NODEID_NULL, cylTypeId,\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),\n                              UA_QUALIFIEDNAME(1, \"Status\"),\n                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), statusAttr, NULL, &amp;statusId);\n    \/* Make the manufacturer name mandatory *\/\n\t\/\/ UA_Server_addReference()\ub97c \uc5b4\ub5bb\uac8c \ud558\ub0d0\uc5d0 \ub530\ub77c  statusId\n\t\/\/ instance \ub9cc\ub4e4\uacbd\uc6b0 \ud45c\uc2dc\n    UA_Server_addReference(server, statusId,\n                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),\n                           UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\uaf2c\ub9ac\uc758 \uaf2c\ub9ac\ub97c \ubb34\ub294 OPC UA.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>tutorial\uc744 \ub530\ub77c\ud558\ub2e4 \ubcf4\uba74 \ub0b4\uac00 \ubb34\uc5c7\uc744 \ubaa8\ub974\ub294\uc9c0 \uc798 \ubaa8\ub978\ub2e4. \uc544\ub798 \uac19\uc740 \uadf8\ub9bc\uc744 \uadf8\ub9ac\uace0 \uc2f6\uc5c8\ub294\ub370 \uc798 \uc548\ub41c\ub2e4. \ub0b4\uac00 \uc11c\ubc84\ub97c \uac74\ub4dc\ub9b4 \uc77c\uc740 \uc5c6\uaca0\uc9c0\ub9cc, \ud074\ub77c\uc774\uc5b8\ud2b8\ub97c \ud14c\uc2a4\ud2b8\ud558\ub824\uba74 \uc11c\ubc84\uac00 \ud544\uc694\ud558\ub2e4. object\ub97c define\ud560 \ub54c \uc5b4\ub290 \ubcc0\uc218\ub97c \uc778\uc2a4\ud134\uc2a4\uc5d0 \ud3ec\ud568\ud560\uc9c0 \uacb0\uc815\ud560 \uc218 \uc788\ub2e4. defineCylTypes \ud568\uc218 \uc911 UA_Server_addReference\uc758 \ubcc0\uc218\ub85c \uc804\uc5d0 \uc120\uc5b8\ud55c id\ub97c \ub118\uaca8\uc8fc\uba74 \ubd99\ub294\ub2e4. \uaf2c\ub9ac\uc758 \uaf2c\ub9ac\ub97c \ubb34\ub294 OPC UA.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[12],"tags":[807,808,745,798],"class_list":["post-4041","post","type-post","status-publish","format-standard","hentry","category-12","tag-opcua","tag-open62541","tag-plc","tag-raspberry"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/now0930.pe.kr\/wordpress\/wp-json\/wp\/v2\/posts\/4041","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/now0930.pe.kr\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/now0930.pe.kr\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/now0930.pe.kr\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/now0930.pe.kr\/wordpress\/wp-json\/wp\/v2\/comments?post=4041"}],"version-history":[{"count":2,"href":"https:\/\/now0930.pe.kr\/wordpress\/wp-json\/wp\/v2\/posts\/4041\/revisions"}],"predecessor-version":[{"id":4044,"href":"https:\/\/now0930.pe.kr\/wordpress\/wp-json\/wp\/v2\/posts\/4041\/revisions\/4044"}],"wp:attachment":[{"href":"https:\/\/now0930.pe.kr\/wordpress\/wp-json\/wp\/v2\/media?parent=4041"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/now0930.pe.kr\/wordpress\/wp-json\/wp\/v2\/categories?post=4041"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/now0930.pe.kr\/wordpress\/wp-json\/wp\/v2\/tags?post=4041"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}