diff --git a/app.py b/app.py index ca61a1c..442f9a7 100644 --- a/app.py +++ b/app.py @@ -4,13 +4,38 @@ import time import os from opcua_connector import opcua_connector +class app: + def __init__(self): + self.app_cfg = yaml.safe_load(open('./cfg.yaml')) or {} + self.OPCon = opcua_connector(self.app_cfg) + + def initialize_connection(self): + """Initialize OPC UA connection""" + try: + self.OPCon.connect() + if self.OPCon.check_connection() == 1: + st.session_state.connection_status = "Connected" + print("🎉 Connection initialized successfully") + return True + st.session_state.connection_status = "Disconnected" + return False + except Exception as e: + print(f"❌ Failed to initialize connection: {e}") + st.session_state.connection_status = "Disconnected" + return False + + def execute_button_action(self, button_name): + """Execute button action with proper error handling""" + if button_name == 'INIT': + self.OPCon.adapt_access_rights() + print(f"🔧 INIT button pressed - Access rights adapted") + else: + self.OPCon.press_btn(button_name) + print(f"🔘 {button_name} button pressed") + return True + # Load config early for password if present -try: - _APP_CFG = yaml.safe_load(open('./cfg.yaml')) or {} -except Exception: - _APP_CFG = {} - -OPCcon = opcua_connector(_APP_CFG) +app = app() # Page configuration st.set_page_config( @@ -20,130 +45,28 @@ st.set_page_config( initial_sidebar_state="expanded" ) -# Custom CSS for better styling -st.markdown(""" - -""", unsafe_allow_html=True) +# Custom CSS for better styling (external stylesheet) +with open('styles.css') as f: + st.markdown(f"", unsafe_allow_html=True) # Initialize session state -if 'opcua_connector' not in st.session_state: - st.session_state.opcua_connector = None if 'connection_status' not in st.session_state: st.session_state.connection_status = "Disconnected" if 'authenticated' not in st.session_state: st.session_state.authenticated = False # Re-validate connection status each render (do this before rendering UI) -def is_opcua_connected(OPCcon) -> bool: +def is_opcua_connected(conn) -> bool: try: - if OPCcon is None: - return False - return OPCcon.check_connection() == 1 + return bool(conn and conn.check_connection() == 1) except Exception: return False -if st.session_state.opcua_connector and is_opcua_connected(st.session_state.opcua_connector): - if st.session_state.connection_status != "Connected": - st.session_state.connection_status = "Connected" -else: - if st.session_state.connection_status != "Disconnected": - st.session_state.connection_status = "Disconnected" +st.session_state.connection_status = ( + "Connected" if is_opcua_connected(app.OPCon) else "Disconnected" +) -def initialize_connection(): - """Initialize OPC UA connection""" - try: - # Connect and check status - OPCcon.connect() - if OPCcon.check_connection() == 1: - st.session_state.opcua_connector = OPCcon - st.session_state.connection_status = "Connected" - print("🎉 Connection initialized successfully") - return True - - st.session_state.connection_status = "Disconnected" - return False - except Exception as e: - print(f"❌ Failed to initialize connection: {e}") - st.session_state.connection_status = "Disconnected" - return False - -def execute_button_action(button_name): - """Execute button action with proper error handling""" - if button_name == 'INIT': - OPCcon.adapt_access_rights() - print(f"🔧 INIT button pressed - Access rights adapted") - else: - OPCcon.press_btn(button_name) - print(f"🔘 {button_name} button pressed") - return True # Sidebar with st.sidebar: @@ -152,22 +75,16 @@ with st.sidebar: # Initialize button if st.button("🔌 Initialize Connection", use_container_width=True): with st.spinner("Initializing connection..."): - initialize_connection() + app.initialize_connection() st.rerun() # Disconnect button if st.button("🔌 Disconnect", use_container_width=True): - if st.session_state.opcua_connector: - try: - - # Disconnect OPC UA using the new method - st.session_state.opcua_connector.disconnect() - print("🔌 Disconnected from OPC UA server") - - except Exception as e: - print(f"âš ī¸ Warning during disconnect: {e}") - - st.session_state.opcua_connector = None + try: + app.OPCon.disconnect() + print("🔌 Disconnected from OPC UA server") + except Exception as e: + print(f"âš ī¸ Warning during disconnect: {e}") st.session_state.connection_status = "Disconnected" print("🔌 Connection reset") st.rerun() @@ -179,8 +96,7 @@ with st.sidebar: # Password gate # Prefer cfg.yaml cred.dashboard.password, else env DASHBOARD_PASSWORD, else 'admin' expected_password = ( - (_APP_CFG.get('cred', {}).get('dashboard', {}) or {}).get('password') - or os.getenv('DASHBOARD_PASSWORD') + (app.app_cfg.get('cred', {}).get('dashboard', {}) or {}).get('password') or 'admin' ) ui_locked = not st.session_state.authenticated @@ -204,19 +120,19 @@ if not ui_locked: with btn_col1: if st.button("🔧\n\nINIT", key="init_btn", use_container_width=True, disabled=buttons_disabled): - execute_button_action('INIT') + app.execute_button_action('INIT') with btn_col2: if st.button("â–ļī¸\n\nSTART", key="start_btn", use_container_width=True, disabled=buttons_disabled): - execute_button_action('BTN_START') + app.execute_button_action('BTN_START') with btn_col3: if st.button("âšī¸\n\nSTOP", key="stop_btn", use_container_width=True, disabled=buttons_disabled): - execute_button_action('BTN_STOP') + app.execute_button_action('BTN_STOP') with btn_col4: if st.button("🔄\n\nRESET", key="reset_btn", use_container_width=True, disabled=buttons_disabled): - execute_button_action('BTN_RESET') + app.execute_button_action('BTN_RESET') st.markdown('', unsafe_allow_html=True) diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..f79bc49 --- /dev/null +++ b/styles.css @@ -0,0 +1,68 @@ +.main-header { + text-align: center; + color: #1f77b4; + margin-bottom: 2rem; +} +.button-container { + display: flex; + justify-content: center; + gap: 2rem; + margin: 2rem 0; + flex-wrap: wrap; +} +.control-button { + display: flex; + flex-direction: column; + align-items: center; + padding: 1.5rem; + border-radius: 15px; + background: linear-gradient(145deg, #f0f2f6, #ffffff); + box-shadow: 5px 5px 15px #d1d9e6, -5px -5px 15px #ffffff; + transition: all 0.3s ease; + min-width: 150px; + cursor: pointer; +} +.control-button:hover { + transform: translateY(-2px); + box-shadow: 8px 8px 20px #d1d9e6, -8px -8px 20px #ffffff; +} +.status-indicator { + padding: 0.5rem 1rem; + border-radius: 20px; + font-weight: bold; + text-align: center; + margin: 1rem 0; +} +.status-connected { + background-color: #d4edda; + color: #155724; + border: 1px solid #c3e6cb; +} +.status-disconnected { + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; +} +.log-container { + background-color: #f8f9fa; + border: 1px solid #dee2e6; + border-radius: 5px; + padding: 1rem; + max-height: 300px; + overflow-y: auto; +} +.stButton > button { + height: 60px !important; + font-size: 14px !important; + font-weight: bold !important; + border-radius: 10px !important; + border: 2px solid #e0e0e0 !important; + transition: all 0.3s ease !important; +} +.stButton > button:hover { + transform: translateY(-2px) !important; + box-shadow: 0 4px 8px rgba(0,0,0,0.2) !important; + border-color: #1f77b4 !important; +} + +