import streamlit as st import yaml import time import os from opcua_connector import opcua_connector # Load config early for password if present app_cfg = yaml.safe_load(open('./cfg.yaml')) or {} # Page configuration st.set_page_config( page_title="OPC UA Robot Control Dashboard", page_icon="đ¤", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS for better styling (external stylesheet) with open('styles.css') as f: st.markdown(f"", unsafe_allow_html=True) def execute_button_action(button_name): """Execute button action with proper error handling""" if st.session_state.opcon is None: return False if button_name == 'INIT': st.session_state.opcon.adapt_access_rights() print(f"đ§ INIT button pressed - Access rights adapted") else: st.session_state.opcon.press_btn(button_name) print(f"đ {button_name} button pressed") return True # Re-validate connection status each render (do this before rendering UI) def is_opcua_connected(conn) -> bool: try: return bool(conn and conn.check_connection() == 1) except Exception: return False # Initialize session state if 'opcon' not in st.session_state: st.session_state.opcon = None if 'connection_status' not in st.session_state: st.session_state.connection_status = "Disconnected" # Update connection status on each render st.session_state.connection_status = ( "Connected" if is_opcua_connected(st.session_state.opcon) else "Disconnected" ) if 'authenticated' not in st.session_state: st.session_state.authenticated = False # Sidebar with st.sidebar: st.write(f"Status: {st.session_state.connection_status}") # Initialize button if st.button("đ Initialize Connection", use_container_width=True): with st.spinner("Initializing connection..."): try: if st.session_state.opcon is None: st.session_state.opcon = opcua_connector(app_cfg) st.session_state.opcon.connect() if st.session_state.opcon.check_connection() == 1: st.session_state.connection_status = "Connected" print("đ Connection initialized successfully") else: st.session_state.connection_status = "Disconnected" print("â Connection failed") except Exception as e: print(f"â Failed to initialize connection: {e}") st.session_state.connection_status = "Disconnected" st.rerun() # Disconnect button if st.button("đ Disconnect", use_container_width=True): try: if st.session_state.opcon: st.session_state.opcon.disconnect() print("đ Disconnected from OPC UA server") except Exception as e: print(f"â ī¸ Warning during disconnect: {e}") st.session_state.opcon = None st.session_state.connection_status = "Disconnected" print("đ Connection reset") st.rerun() st.divider() # 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 'admin' ) ui_locked = not st.session_state.authenticated if ui_locked: pwd = st.text_input("Enter Dashboard Password", type="password") if st.button("Login", use_container_width=True): if pwd == expected_password: st.session_state.authenticated = True st.rerun() else: st.error("Wrong password") if not ui_locked: # Button container st.markdown('
', unsafe_allow_html=True) # Footer removed for minimal UI