from flask import Flask, request, jsonify from flask_cors import CORS from opcua import Client, ua from opcua.ua import Variant, VariantType import logging # Disable certificate check (not secure - use only in development!) #from opcua.crypto import certificate_handler #certificate_handler.CertificateHandler.validate = lambda self, cert: True #from opcua.common import certificate_store #certificate_store.CertificateStore.check_certificate = lambda self, cert: True # Configure logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger(__name__) app = Flask(__name__) CORS(app) variable_mapping = { "IN_Bit_Esterni": {"node_id": "ns=4;s=IN_Bit_Esterni", "type": VariantType.UInt32}, "IN_Prossimo_Formato": {"node_id": "ns=4;s=IN_Prossimo_Formato", "type": VariantType.UInt16}, "IN_Prossimo_Lotto": {"node_id": "ns=4;s=IN_Prossimo_Lotto", "type": VariantType.String}, "IN_Target_Produzione": {"node_id": "ns=4;s=IN_Target_Produzione", "type": VariantType.UInt32}, "OUT_Bit_Esterni": {"node_id": "ns=4;s=OUT_Bit_Esterni", "type": VariantType.UInt32}, "OUT_Ricetta_in_Uso": {"node_id": "ns=4;s=OUT_Ricetta_in_Uso", "type": VariantType.String}, "OUT_Velocita_Istantanea": {"node_id": "ns=4;s=OUT_Velocita_Istantanea", "type": VariantType.String}, "OUT_Vel_Effettiva": {"node_id": "ns=4;s=OUT_Vel_Effettiva", "type": VariantType.String}, "OUT_Vel_Impostata": {"node_id": "ns=4;s=OUT_Vel_Impostata", "type": VariantType.String}, "OUT_Contapezzi_Parziale": {"node_id": "ns=4;s=OUT_Contapezzi_Parziale", "type": VariantType.UInt32}, "OUT_Contapezzi_Totale": {"node_id": "ns=4;s=OUT_Contapezzi_Totale", "type": VariantType.UInt32}, "OUT_Lotto_Attuale":{"node_id":"ns=4;s=OUT_Lotto_Attuale","type":VariantType.String} } def opcua_request(server_url, callback): """ Connects to an OPC UA server, executes a callback, then disconnects. """ logger.debug(f"Attempting to connect to OPC UA server: {server_url}") client = Client(server_url) try: client.connect() logger.debug("Successfully connected to OPC UA server") return callback(client) except Exception as e: logger.error(f"OPC UA error: {e}") return {"error": str(e)}, 500 finally: client.disconnect() logger.debug("Disconnected from OPC UA server") @app.route('/write_multiple', methods=['POST']) def write_multiple_values(): """ Write multiple values to OPC UA variables on a specified server. """ data = request.get_json() server_url = data.get('server_url') variables = data.get('variables') if not server_url or not variables: return jsonify({"error": "server_url and variables are required"}), 400 results = [] errors = [] def write_callback(client): for variable_name, value in variables.items(): variable_info = variable_mapping.get(variable_name) if not variable_info: errors.append({"variable": variable_name, "error": "Invalid variable name"}) continue try: node = client.get_node(variable_info["node_id"]) # Ensure correct data type expected_type = variable_info["type"] if expected_type == VariantType.UInt32: converted_value = ua.Variant(int(value), ua.VariantType.UInt32) elif expected_type == VariantType.UInt16: converted_value = ua.Variant(int(value), ua.VariantType.UInt16) elif expected_type == VariantType.String: converted_value = ua.Variant(str(value), ua.VariantType.String) elif expected_type == VariantType.Boolean: converted_value = ua.Variant(bool(value), ua.VariantType.Boolean) elif expected_type == VariantType.Float: converted_value = ua.Variant(float(value), ua.VariantType.Float) else: errors.append({"variable": variable_name, "error": "Unsupported data type"}) continue node.set_value(ua.DataValue(converted_value)) results.append({"variable": variable_name, "status": "success"}) except Exception as e: logger.error(f"Write error for {variable_name}: {e}") errors.append({"variable": variable_name, "error": f"Failed to write {variable_name}. {str(e)}"}) if errors: return jsonify({"results": results, "errors": errors}), 207 # Multi-status response return jsonify({"results": results}) return opcua_request(server_url, write_callback) @app.route('/variables', methods=['GET']) def get_all_variables(): """ Read all OPC UA variables from a specified server, skipping missing ones. """ server_url = request.args.get('server_url') if not server_url: return jsonify({"error": "server_url is required"}), 400 def variables_callback(client): all_variables = {} for var_name, var_info in variable_mapping.items(): try: node = client.get_node(var_info["node_id"]) all_variables[var_name] = node.get_value() except Exception as e: logger.warning(f"Skipping missing variable: {var_name}") continue # Skip missing variables return jsonify(all_variables) return opcua_request(server_url, variables_callback) if __name__ == '__main__': app.run(host='0.0.0.0', port=40000)