Files
Feeding_control_system/opc/opcua_server_test.py

237 lines
9.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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.Boolean))
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.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_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.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)
print("[变量创建] 变量创建完成AccessLevel权限已设置")
# 验证并打印当前的AccessLevel属性
# try:
# al = self.upper_weight.get_attribute(ua.AttributeIds.AccessLevel)
# ual = self.upper_weight.get_attribute(ua.AttributeIds.UserAccessLevel)
# print(f"[变量创建] upper_weight AccessLevel: {al.Value.Value}, UserAccessLevel: {ual.Value.Value}")
# al2 = self.lower_weight.get_attribute(ua.AttributeIds.AccessLevel)
# ual2 = self.lower_weight.get_attribute(ua.AttributeIds.UserAccessLevel)
# print(f"[变量创建] lower_weight AccessLevel: {al2.Value.Value}, UserAccessLevel: {ual2.Value.Value}")
# except Exception as e:
# print(f"[变量创建] 获取权限属性失败: {e}")
def setup_variable_permissions(self):
"""设置变量权限 - 在服务器启动后调用"""
try:
# 重新设置变量为可写,确保权限生效
self.upper_weight.set_writable(True)
self.lower_weight.set_writable(True)
print("[权限设置] 变量权限已重新设置")
# 验证权限
try:
al = self.upper_weight.get_attribute(ua.AttributeIds.AccessLevel)
ual = self.upper_weight.get_attribute(ua.AttributeIds.UserAccessLevel)
print(f"[权限设置] upper_weight AccessLevel: {al.Value.Value}, UserAccessLevel: {ual.Value.Value}")
except Exception as e:
print(f"[权限设置] 验证失败: {e}")
except Exception as e:
print(f"[权限设置] 设置权限失败: {e}")
print("[权限设置] 尝试强制设置...")
# def setup_state_listeners(self):
# """设置状态监听器 - 事件驱动更新"""
# if hasattr(self.state, 'state_updated'):
# self.state.state_updated.connect(self.on_state_changed)
# print("状态监听器已设置 - 事件驱动模式")
# def on_state_changed(self, property_name, value):
# """状态变化时的回调函数"""
# try:
# # 根据属性名更新对应的OPC UA变量
# if property_name == "upper_weight":
# self.upper_weight.set_value(value)
# elif property_name == "lower_weight":
# self.lower_weight.set_value(value)
# # 可以在这里添加更多状态映射
# print(f"状态更新: {property_name} = {value}")
# except Exception as e:
# print(f"状态更新错误: {e}")
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()