{"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>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>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>\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, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"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_featured_media_url":"","jetpack_sharing_enabled":true,"_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}]}}