# PLC S7-315 Streamer & Logger - AI Coding Guide ## Architecture Overview This is a **dual-stack industrial automation system** for Siemens S7-315 PLCs combining Python backend orchestration with React frontend controls: - **Backend**: Flask app (`main.py`) orchestrating core modules via `PLCDataStreamer` - **Frontend**: Vite + React + Chakra UI + RJSF for dynamic configuration forms - **Data Flow**: PLC → snap7 → CSV recording + UDP streaming → PlotJuggler visualization - **Configuration**: JSON Schema-driven with validation for PLC variables and plot definitions ## Core Architecture Principles ### 1. Orchestrator Pattern `core/plc_data_streamer.py` is the main coordinator that initializes and manages: - `ConfigManager`: JSON configuration persistence with schema validation - `PLCClient`: Siemens snap7 communication - `DataStreamer`: Independent CSV recording + UDP streaming threads - `EventLogger`: Persistent application event logging - `InstanceManager`: Single-instance control with auto-recovery ### 2. Independent Data Streams **Critical**: CSV recording and UDP streaming are **separate concerns**: - CSV recording: Always active when PLC connected (automatic) - UDP streaming: Manual control for PlotJuggler visualization - Each dataset thread handles both, but UDP transmission is independently controlled ### 3. Schema-Driven Configuration with RJSF All configuration uses JSON Schema validation with React JSON Schema Forms (RJSF): - **Frontend-First Validation**: RJSF handles all form generation and validation - **Backend API Simplification**: Flask provides simple CRUD operations for JSON files - **Array-Based Data Structure**: All configurations use array format for RJSF compatibility - **Three Form Types**: - Type 1: Single object forms (PLC config) - Type 2: Array management forms (dataset definitions, plot definitions) - Type 3: Filtered array forms with combo selectors (variables linked to datasets/plots) ### 4. JSON Configuration Structure **CRITICAL**: All JSON files use array-based structures for RJSF compatibility: - `plc_config.json`: Single object with `udp_config` containing `sampling_interval` - `dataset_definitions.json`: `{"datasets": [{"id": "DAR", "name": "...", ...}]}` - `dataset_variables.json`: `{"variables": [{"dataset_id": "DAR", "variables": [...]}]}` - `plot_definitions.json`: `{"plots": [{"id": "plot1", "name": "...", ...}]}` - `plot_variables.json`: `{"plot_variables": [{"plot_id": "plot1", "variables": [...]}]}` ## Development Workflows ### Backend Development ```bash # Setup Python environment (REQUIRED before any Python work) conda create -n plc_streamer python=3.10 conda activate plc_streamer pip install -r requirements.txt # Run backend server python main.py # Access at http://localhost:5000 ``` ### Frontend Development ```bash cd frontend npm install npm run dev # Development server at http://localhost:5173 npm run build # Production build to dist/ ``` ### Key External Dependencies - **snap7.dll**: Must be in system PATH or project root for PLC communication - **PlotJuggler**: Configured to receive UDP JSON at 127.0.0.1:9870 ## Critical File Patterns ### Configuration Management - `config/data/*.json`: Runtime configuration files - `config/schema/*.json`: JSON Schema definitions - `ConfigSchemaManager` in `core/schema_manager.py`: Centralized schema loading and validation ### Frontend Components - `pages/DashboardNew.jsx`: Main control interface with tabbed layout - `components/EditableTable.jsx`: Reusable schema-to-table converter - `components/PlotManager.jsx`: Real-time Chart.js plotting with streaming - **Pattern**: RJSF forms for configuration, custom tables for data management ### API Endpoints Structure Flask routes in `main.py` follow simplified REST patterns with unified JSON handling: - `/api/config/*`: Unified configuration CRUD operations for all JSON files - `/api/plc/*`: PLC connection and status - `/api/streaming/*`: Data streaming controls - `/api/plots/*`: Plot session management - **API Philosophy**: Backend provides simple file I/O, frontend handles all validation via RJSF ## Important Conventions ### 1. Error Handling & Logging - All core classes require logger injection: `__init__(self, logger)` - Use `self.event_logger.log_event()` for persistent events - PyInstaller compatibility: Use `resource_path()` for file access ### 2. React Component Patterns - **FormTable.jsx**: Single-row forms per item using RJSF schemas - **DatasetFormManager/PlotFormManager**: Master-detail table management - Chakra UI components with consistent styling via `theme.js` - **RJSF Integration**: All forms auto-generated from JSON Schema, no hardcoded form fields ### 3. Thread Safety - Data streaming uses thread-safe collections and proper cleanup - Instance management prevents multiple app instances - Background threads properly handle graceful shutdown ### 4. Schema Evolution Follow existing patterns in `config/schema/` - all forms are auto-generated from JSON Schema + UI Schema combinations. Never hardcode form fields. - **Array-First Design**: All multi-item configurations use array structures for RJSF type 2 forms - **Unified Validation**: JSON Schema validation both client-side (RJSF) and server-side (jsonschema library) - **Schema-UI Separation**: Data schemas in `/config/schema/`, UI schemas in `/config/schema/ui/` ### 5. Development Context - Use `.doc/MemoriaDeEvolucion.md` for understanding recent changes and decisions - Comments and variables must be in English per project conventions - No standalone markdown files unless specifically requested ## Integration Points ### PLC Communication - Data blocks accessed via `DB{number}.{offset}` addressing - Supported types: REAL, INT, DINT, BOOL - Connection state managed through `PLCClient` with automatic reconnection ### Real-time Visualization - Chart.js with chartjs-plugin-streaming for real-time plots - Automatic data ingestion from `/api/plots/{session_id}/data` - Plot session lifecycle managed through backend API ### CSV Data Export - Automatic file rotation by size/time in `records/` directory - Thread-safe CSV writing with proper cleanup - Configurable retention policies for long-term storage ### Notes Always write software variables and comments in English The development is focused on Windows and after testing must work without CDN completely offline. ## RJSF Configuration Management ### Form Type Architecture The system implements three distinct RJSF form patterns: **Type 1: Single Object Forms** - Used for: PLC configuration (`plc_config.json`) - Structure: Single JSON object with nested properties - RJSF Pattern: Direct object form rendering - Example: Connection settings, UDP configuration with `sampling_interval` **Type 2: Array Management Forms** - Used for: Dataset definitions (`dataset_definitions.json`), Plot definitions (`plot_definitions.json`) - Structure: `{"datasets": [...]}` or `{"plots": [...]}` - RJSF Pattern: Array form with add/remove/edit capabilities - Critical: Root must be array wrapper for RJSF compatibility **Type 3: Filtered Array Forms with Combo Selectors** - Used for: Variables linked to datasets/plots (`dataset_variables.json`, `plot_variables.json`) - Structure: Array with foreign key references (`dataset_id`, `plot_id`) - RJSF Pattern: Filtered forms based on selected dataset/plot - Workflow: Select parent → Edit associated variables - **Implementation**: Combo selector + dynamic schema generation for selected item - **Key Functions**: `getSelectedDatasetVariables()`, `updateSelectedDatasetVariables()` ### RJSF Best Practices and Common Pitfalls **Critical Widget Guidelines**: - **Arrays**: Never specify `"ui:widget": "array"` - arrays use built-in ArrayField component - **Valid Widgets**: text, textarea, select, checkbox, updown, variableSelector - **Widget Registry**: All widgets must be registered in `AllWidgets.jsx` - **Custom Widgets**: Use specific widget names, avoid generic type names **Schema Structure Rules**: - **Array Items**: Always include `title` property for array item schemas - **UI Layout**: Use `"ui:layout"` for grid-based field arrangement - **Field Templates**: Leverage `LayoutObjectFieldTemplate` for responsive layouts - **Error Handling**: RJSF errors often indicate missing widgets or malformed schemas ### Type 3 Form Implementation Pattern ```javascript // Step 1: Parent Selector (Combo) const [selectedItemId, setSelectedItemId] = useState('') // Step 2: Filtered Data Helper const getSelectedItemData = () => { return allData.find(item => item.parent_id === selectedItemId) || defaultData } // Step 3: Update Helper const updateSelectedItemData = (newData) => { const updated = allData.map(item => item.parent_id === selectedItemId ? { ...item, ...newData } : item ) setAllData({ ...allData, items: updated }) } // Step 4: Dynamic Schema Generation const dynamicSchema = { type: "object", properties: { /* fields specific to selected item */ } } ``` ### JSON Schema Migration Notes - **Legacy to Array**: All object-based configs converted to array format - **ID Fields**: Added explicit `id` fields to all array items for referencing - **Validation**: Unified validation using `jsonschema` library server-side + RJSF client-side - **Backward Compatibility**: Migration handled in backend for existing configurations ### Development Debugging Guide **RJSF Error Resolution**: - `No widget 'X' for type 'Y'`: Check widget registration in `AllWidgets.jsx` - Array rendering errors: Remove `"ui:widget"` specification from array fields - Schema validation failures: Use `validate_schema.py` to test JSON structure - Form not displaying: Verify schema structure matches expected Type 1/2/3 pattern **Type 3 Form Debugging**: - Combo not showing options: Check parent data loading and `availableItems` array - Form not updating: Verify `selectedItemId` state and helper functions - Data not persisting: Check `updateSelectedItemData()` logic and save operations - Schema errors: Ensure dynamic schema generation matches data structure **Frontend-Backend Integration**: - API endpoint naming: Use consistent `/api/config/{config-name}` pattern - JSON structure validation: Backend uses `jsonschema`, frontend uses RJSF validation - Error handling: Both client and server should handle array format gracefully - Configuration loading: Always verify API response structure before setting form data