#!/usr/bin/env python3 """ 简单的OPC UA服务器示例 用于工业自动化数据通信 """ from opcua import Server, ua import time import random import threading from datetime import datetime # from core.system import SystemState # from config.ini_manager import ini_manager class SimpleOPCUAServer: # def __init__(self, state, endpoint=ini_manager.opcua_endpoint, name="Feed_Server"): def __init__(self, endpoint='', name="Feed_Server"): """ 初始化OPC UA服务器 Args: endpoint: 服务器端点地址 name: 服务器名称 """ self.server = Server() self.server.set_endpoint(endpoint) self.server.set_server_name(name) # self.state = state # 设置服务器命名空间 self.namespace = self.server.register_namespace("Feed_Control_System") # 获取对象节点 self.objects = self.server.get_objects_node() # 创建自定义对象 self.create_object_structure() # 运行标志 self.running = False # 订阅和监控项 self.subscription = None self.monitored_items = [] # 记录上次值用于检测变化 self._last_values = {} def create_object_structure(self): """创建OPC UA对象结构""" # 创建上料斗对象 self.upper = self.objects.add_object(self.namespace, "upper") self.lower=self.objects.add_object(self.namespace, "lower") self.sys=self.objects.add_object(self.namespace, "sys") self.mould=self.objects.add_object(self.namespace, "mould") self.pd=self.objects.add_object(self.namespace, "pd") # 创建变量 self.create_variables() def create_variables(self): """创建OPC UA变量""" # 创建变量时显式指定数据类型和初始值 #上料斗 # 上料斗 self.upper_weight = self.upper.add_variable(self.namespace, "upper_weight", ua.Variant(0.0, ua.VariantType.Float)) self.upper_is_arch = self.upper.add_variable(self.namespace, "upper_is_arch", ua.Variant(False, ua.VariantType.Boolean)) self.upper_door_closed = self.upper.add_variable(self.namespace, "upper_door_closed", ua.Variant(False, ua.VariantType.Int16)) self.upper_volume = self.upper.add_variable(self.namespace, "upper_volume", ua.Variant(0.0, ua.VariantType.Float)) self.upper_door_position = self.upper.add_variable(self.namespace, "upper_door_position", ua.Variant(0, ua.VariantType.Int16)) # 下料斗 self.lower_weight = self.lower.add_variable(self.namespace, "lower_weight", ua.Variant(0.0, ua.VariantType.Float)) self.lower_is_arch = self.lower.add_variable(self.namespace, "lower_is_arch", ua.Variant(False, ua.VariantType.Boolean)) self.lower_angle = self.lower.add_variable(self.namespace, "lower_angle", ua.Variant(0.0, ua.VariantType.Float)) # 模具车 self.mould_finish_weight = self.mould.add_variable(self.namespace, "mould_finish_weight", ua.Variant(0.0, ua.VariantType.Float)) self.mould_need_weight = self.mould.add_variable(self.namespace, "mould_need_weight", ua.Variant(0.0, ua.VariantType.Float)) self.mould_finish_ratio = self.mould.add_variable(self.namespace, "mould_finish_ratio", ua.Variant(0.0, ua.VariantType.Float)) self.mould_frequency = self.mould.add_variable(self.namespace, "mould_frequency", ua.Variant(230, ua.VariantType.Int32)) self.mould_vibrate_status = self.mould.add_variable(self.namespace, "mould_vibrate_status", ua.Variant(False, ua.VariantType.Boolean)) self.feed_status = self.mould.add_variable(self.namespace, "feed_status", ua.Variant(0, ua.VariantType.Int16)) self.pd_data=self.pd.add_variable(self.namespace, "pd_data", ua.Variant("", ua.VariantType.String)) self.pd_notify=self.pd.add_variable(self.namespace, "pd_notify", ua.Variant("", ua.VariantType.String)) self.pd_notify_finish=self.pd.add_variable(self.namespace, "pd_notify_finish", ua.Variant("", ua.VariantType.String)) self.pd_set_mode=self.pd.add_variable(self.namespace, "set_mode", ua.Variant(0, ua.VariantType.Int16)) self.pd_set_volume=self.pd.add_variable(self.namespace, "set_volume", ua.Variant("", ua.VariantType.String)) # 系统对象 self.sys_set_mode=self.sys.add_variable(self.namespace, "set_mode", ua.Variant(0, ua.VariantType.Int16)) self.sys_segment_refresh=self.sys.add_variable(self.namespace, "segment_refresh", ua.Variant(0, ua.VariantType.Int16)) self.sys_pd_refresh=self.sys.add_variable(self.namespace, "pd_refresh", ua.Variant(0, ua.VariantType.Int16)) # 在创建变量后立即设置可写权限(不需要等待服务器启动) self.upper_weight.set_writable(True) self.lower_weight.set_writable(True) self.upper_is_arch.set_writable(True) self.upper_door_closed.set_writable(True) self.upper_volume.set_writable(True) self.upper_door_position.set_writable(True) self.lower_is_arch.set_writable(True) self.mould_finish_weight.set_writable(True) self.mould_need_weight.set_writable(True) self.mould_frequency.set_writable(True) self.mould_vibrate_status.set_writable(True) self.feed_status.set_writable(True) self.pd_data.set_writable(True) self.pd_notify.set_writable(True) self.pd_notify_finish.set_writable(True) self.pd_set_mode.set_writable(True) self.pd_set_volume.set_writable(True) self.sys_set_mode.set_writable(True) self.mould_finish_ratio.set_writable(True) self.sys_segment_refresh.set_writable(True) self.sys_pd_refresh.set_writable(True) self.lower_angle.set_writable(True) print("[变量创建] 变量创建完成") def start(self): """启动服务器""" try: self.server.start() self.running = True print(f"服务器端点: opc.tcp://0.0.0.0:4840/freeopcua/server/") print("=" * 60) # 【关键修复】在设置监听器之前,先设置变量权限 # 这确保 AccessLevel 属性在客户端写入前已正确设置 # self.setup_variable_permissions() print("=" * 60) # 设置客户端写入监听器 # self.setup_write_listeners() print("=" * 60) # 初始化当前值 # if self.state: # self.upper_weight.set_value(self.state._upper_weight) # self.lower_weight.set_value(self.state._lower_weight) # print("已同步初始状态值") # 设置状态监听器 - 关键步骤! # self.setup_state_listeners() # # 只有在没有状态系统时才使用模拟线程 # if not self.state: # print("使用模拟数据模式") # self.simulation_thread = threading.Thread(target=self.simulate_data) # self.simulation_thread.daemon = True # self.simulation_thread.start() except Exception as e: print(f"启动服务器失败: {e}") def stop(self): """停止服务器""" # 移除监听器 # self.remove_write_listeners() self.running = False self.server.stop() print("OPC UA服务器已停止") # 断开状态监听器 # if hasattr(self.state, 'state_updated'): # try: # self.state.state_updated.disconnect(self.on_state_changed) # except: # pass def main(): """主函数""" # 创建系统状态实例 # state = SystemState() # 创建并启动服务器 server = SimpleOPCUAServer( endpoint="opc.tcp://0.0.0.0:4840/freeopcua/server/", name="工业自动化 OPC UA 服务器" ) try: server.start() print("服务器正在运行,按 Ctrl+C 停止...") # 保持服务器运行 while True: time.sleep(1) except KeyboardInterrupt: print("\n正在停止服务器...") server.stop() except Exception as e: print(f"服务器运行错误: {e}") server.stop() if __name__ == "__main__": main()