diff --git a/PROJECT_OVERVIEW.html b/PROJECT_OVERVIEW.html new file mode 100644 index 0000000..d859c7d --- /dev/null +++ b/PROJECT_OVERVIEW.html @@ -0,0 +1,115 @@ +Mini Factory Automation Simulation — Project Overview
+

Mini Factory Automation Simulation — Project Overview

+

Project summary

+

This Java project simulates a small automated factory with conveyors, machines, sensors, workers, actuators and a simple logging / persistence layer. It provides a simulation engine, controllers for workflow and item tracking, a console UI, and repositories that persist entities to an SQLite database (automation.sqlite).

+
+
+

High-level architecture

+
    +
  • Entities: domain objects representing factory parts (Product, ProductItem, Machine, Sensor, Worker, ConveyorBelt, EventLog, ItemTracker).
  • +
  • Controllers / Simulators: SimulationEngine, SimulationClock, WorkFlowController, ItemTracker controller manage simulation steps and item flow.
  • +
  • Repositories: CRUD-like persistence layer (Repository, MachineRepository, ConveyorRepository, SensorRepository, WorkerRepository, ProductItemRepository, LoggerRepository).
  • +
  • Actuators / Packaging: Actuator, ActuatorManager, PackagingMachine — components responsible for simulated physical actions.
  • +
  • UI: ConsoleUI package with ConsoleApp and ConsoleUI to interact with the simulation.
  • +
  • Utilities: Logger and DatabaseManager for logging and DB access.
  • +
+
+
+

Important files & responsibilities

+
    +
  • +

    src/main/java/org/Automation/Main.java — Application entry point.

    +
  • +
  • +

    src/main/java/org/Automation/DatabaseManager.java — SQLite connection and DB helpers.

    +
  • +
  • +

    src/main/java/org/Automation/Logger.java — Application logging wrapper.

    +
  • +
  • +

    src/main/java/org/Automation/ConsoleUI/ConsoleApp.java, ConsoleUI.java — Console-based interface and commands.

    +
  • +
  • +

    src/main/java/org/Automation/Controllers/WorkFlowController.java — Orchestrates item flow between machines/conveyors.

    +
  • +
  • +

    src/main/java/org/Automation/Controllers/Simluators/SimulationEngine.java — Core simulation loop; advances SimulationClock and triggers events.

    +
  • +
+
+
+
    +
  • +

    src/main/java/org/Automation/entities/* — Domain models (Product, ProductItem, Machine, Sensor, ConveyorBelt, Worker, EventLog, ItemTracker).

    +
  • +
  • +

    src/main/java/org/Automation/repositories/* — Persistence adapter layer into SQLite; check Repository.java for interface details.

    +
  • +
  • +

    Actuator/, ActuatorManager/, PackagingMachine/ — Additional modules representing actuators and packaging machines (single-file implementations).

    +
  • +
+
+
+

How the simulation typically runs

+
    +
  1. Main initializes DatabaseManager, repositories, logger and loads initial entities.
  2. +
  3. SimulationEngine / SimulationClock drive simulated time and call controllers.
  4. +
  5. WorkFlowController and ItemTracker move ProductItem instances through conveyors and machines.
  6. +
  7. Sensors and Actuators simulate detection and actions; EventLog records notable events.
  8. +
  9. ConsoleUI allows starting/stopping the simulation and observing logs.
  10. +
+
+
+

Database

+
    +
  • File: automation.sqlite (in repo root)
  • +
  • DatabaseManager abstracts JDBC/SQLite usage. Backups or schema changes should be handled carefully.
  • +
+

Logging

+
    +
  • Logger and LoggerRepository provide logging to console and persistence (EventLog entries).
  • +
+
+
+

Extending the project

+
    +
  • Add new entity: create in entities/, add repository implementation and register it where repositories are loaded.
  • +
  • Add a machine or actuator: implement Machine/Actuator subclass and update WorkFlowController to use it.
  • +
  • Add UI commands: extend ConsoleApp/ConsoleUI to expose new controls.
  • +
+
+
+

Notes and pointers for contributors

+
    +
  • Read Repository.java to understand persistence contract.
  • +
  • SimulationEngine is the heart of runtime behavior—review it before modifying controllers.
  • +
  • Keep domain model logic in entities; controllers should orchestrate behavior, not contain domain rules.
  • +
  • Tests are in src/test/ — add unit tests for new behavior.
  • +
  • The project uses SQLite for simplicity; consider migration scripts if schema evolves.
  • +
+
+
+

Quick file map (top-level)

+
    +
  • pom.xml — Maven build
  • +
  • automation.sqlite — persisted DB used during simulation
  • +
  • src/main/java/org/Automation — main source tree
  • +
  • Actuator/, ActuatorManager/, PackagingMachine/ — simple module files
  • +
+

Contact / further help

+

For targeted walkthroughs (class-by-class), request which package or file to dig into next and a focused .md can be produced.

+
+
\ No newline at end of file diff --git a/PROJECT_OVERVIEW.md b/PROJECT_OVERVIEW.md new file mode 100644 index 0000000..b4e9196 --- /dev/null +++ b/PROJECT_OVERVIEW.md @@ -0,0 +1,162 @@ +--- +marp: true +theme: default +size: 16:9 +paginate: true +class: lead +style: | + section { + background: #0b1221; + color: #ffffff; + font-family: 'Inter', sans-serif; + padding: 60px; + } + + h1, h2, h3 { + font-weight: 900; + letter-spacing: -0.5px; + } + + h1 { + font-size: 3.2rem; + color: #7c5dff; + } + + h2 { + font-size: 2.2rem; + color: #c1b3ff; + } + + p { + font-size: 1.2rem; + line-height: 1.6; + color: #d6d6e4; + } + + .card { + background: #0f1b2b; + padding: 20px; + border-radius: 18px; + margin: 20px 0; + box-shadow: 0 0 20px rgba(124, 93, 255, 0.2); + } + + ul { + font-size: 1.2rem; + line-height: 1.7; + } + +--- + +# 🌌 **Deep Dive Presentation** +### Elegant. Minimal. Professional. + +--- + +# ⭐ Introduction +Welcome to a deep and structured exploration of your topic. + +This presentation is designed to: +- Give clarity +- Build strong understanding +- Present ideas in a polished way + +--- + +# 🧠 Understanding the Core Concepts +## A Strong Foundation + +
+Your learning begins with breaking each idea into small, digestible parts. +
+ +We focus on: +- Definitions +- Purpose +- Real-world relevance + +--- + +# šŸŒ Real-World Application +### Why These Concepts Matter + +
+Real engineering isn’t about memorizing theory—it’s about applying it. +
+ +Examples: +- Scalable systems +- Efficient problem-solving +- Clean architecture + +--- + +# āš™ļø Technical Insight +## Key Mechanics & How They Work + +This section explores: +- Internal processes +- Data flow +- Performance factors + +--- + +# šŸ“Š Visualization +### How Everything Connects + +
+Use diagrams, mental models, and intuitive analogies. +
+ +Helps you: +- See patterns +- Predict results +- Build long-term understanding + +--- + +# 🧩 Problem Breakdown +## From Complex → Simple + +Your thinking process should: +1. Define the goal +2. Identify constraints +3. Break steps down +4. Optimize solutions + +--- + +# šŸš€ Strategy & Best Practices +### What You Must Always Do + +- Think in systems +- Document your thought process +- Prioritize clarity +- Avoid unnecessary complexity + +--- + +# šŸ›”ļø Common Mistakes +## What to Avoid + +- Overthinking trivial details +- Skipping fundamentals +- Writing unreadable code +- Forgetting performance impact + +--- + +# 🧭 Summary +### The Path to Mastery + +
+Build understanding → Apply → Reflect → Improve. +
+ +That is the cycle that makes an engineer unstoppable. + +--- + +# šŸ™Œ Thank You +### Questions? +### Ready for the next step? diff --git a/automation.sqlite b/automation.sqlite index 335fb02..dc724d0 100644 Binary files a/automation.sqlite and b/automation.sqlite differ diff --git a/mini_factory_automation_simulation_docs.zip b/mini_factory_automation_simulation_docs.zip deleted file mode 100644 index 859ca2b..0000000 Binary files a/mini_factory_automation_simulation_docs.zip and /dev/null differ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..f691ac6 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,142 @@ +{ + "name": "OOP-Mini-Factory-Automation-Simulation", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "prettier": "3.7.4", + "prettier-plugin-java": "2.7.7" + } + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, + "node_modules/java-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/java-parser/-/java-parser-3.0.1.tgz", + "integrity": "sha512-sDIR7u9b7O2JViNUxiZRhnRz7URII/eE7g2B+BmGxDeS6Ex3OYAcCyz5oh0H4LQ+hL/BS8OJTz8apMy9xtGmrQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "chevrotain": "11.0.3", + "chevrotain-allstar": "0.3.1", + "lodash": "4.17.21" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/prettier": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", + "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-java": { + "version": "2.7.7", + "resolved": "https://registry.npmjs.org/prettier-plugin-java/-/prettier-plugin-java-2.7.7.tgz", + "integrity": "sha512-K3N2lrdKzx2FAi67E0UOTLKybX6iitAxYGuiv/emY8v6TzzGzoaKjmhaAyDKIH5iakFqdN+xUwWoauXnE2JZPA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "java-parser": "3.0.1" + }, + "peerDependencies": { + "prettier": "^3.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..301bb72 --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "devDependencies": { + "prettier": "3.7.4", + "prettier-plugin-java": "2.7.7" + } +} diff --git a/pom.xml b/pom.xml index 000a5de..81efdc3 100644 --- a/pom.xml +++ b/pom.xml @@ -1,53 +1,88 @@ - 4.0.0 - - org.example - Mini-Factory-Automation-Simulation - 1.0-SNAPSHOT - - - 22 - 22 - UTF-8 - - - - - org.xerial - sqlite-jdbc - 3.46.0.0 - - - - org.openjfx - javafx-controls - 21 - - - - - org.openjfx - javafx-fxml - 21 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.13.0 - - 25 - 25 - 25 - - - - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + org.example + Mini-Factory-Automation-Simulation + 1.0-SNAPSHOT + + + + 22 + ${java.version} + ${java.version} + UTF-8 + + + org.automation.TestSensorManager + + + + + + org.xerial + sqlite-jdbc + 3.45.2.0 + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.13.0 + + ${maven.compiler.source} + ${maven.compiler.target} + ${project.build.sourceEncoding} + ${java.version} + + + + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + ${main.class} + + + + + + diff --git a/scripts/test_input.txt b/scripts/test_input.txt new file mode 100644 index 0000000..69d88cf --- /dev/null +++ b/scripts/test_input.txt @@ -0,0 +1,8 @@ +1 +2 +LineA +20 +0.5 +25 +1 +0 diff --git a/src/main/java/org/Automation/ConsoleUI/ConsoleApp.java b/src/main/java/org/Automation/ConsoleUI/ConsoleApp.java deleted file mode 100644 index 5ba5601..0000000 --- a/src/main/java/org/Automation/ConsoleUI/ConsoleApp.java +++ /dev/null @@ -1,35 +0,0 @@ -package ConsoleUI; -import Sim_Engine.SimulationEngine; -import WorkflowController.WorkflowController; -import Logger.Logger; -public class ConsoleApp extends ConsoleUI { - //Instance Variables - private SimulationEngine simulationEngine; - private WorkflowController controller; - private Logger logger; - ConsoleApp(){ - simulationEngine= new SimulationEngine(); - } - - //Instance Methods - public void start() { - simulationEngine.startSimulation(); - - } - - public void runMainMenu() { - - } - - public void handleUserInput(String input) { - - } - - public void printWelcomeMessage() { - - } - - public void exit() { - - } -} diff --git a/src/main/java/org/Automation/Controllers/Simluators/SimulationClock.java b/src/main/java/org/Automation/Controllers/Simluators/SimulationClock.java deleted file mode 100644 index 80eb42c..0000000 --- a/src/main/java/org/Automation/Controllers/Simluators/SimulationClock.java +++ /dev/null @@ -1,94 +0,0 @@ -package Sim_Engine; -import java.time.LocalDateTime; -//import java.time.Duration; -import java.util.ArrayList; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.time.temporal.ChronoUnit; -public class SimulationClock { - //Instance Variables - private static SimulationClock instance; - - private LocalDateTime simTime; - private LocalDateTime lastNotificationDate; - private int speedFactor=1; - private boolean ispaused=false; - - private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();//for the entire system to work on the same time - private final int Tick_Per_MS=50;// well we set it into a task per 50 milliseconds, meaning 20 times in a second - - private ArrayList observers = new ArrayList(); - - private SimulationClock(){ - this.simTime= LocalDateTime.now(); - this.lastNotificationDate=this.simTime; - - startIntegralTimer(); - } - - //Instance Methods - public static synchronized SimulationClock getInstance() { // used to create a single instance for all tasks - if(instance != null) { - instance= new SimulationClock(); - } - return instance; - } - - private void startIntegralTimer() { - scheduler.scheduleAtFixedRate(()->{ - if(!ispaused) { - tick(); - }} , 0, Tick_Per_MS, TimeUnit.MILLISECONDS); - } - - private void tick() { - - long MillsToAdd = Tick_Per_MS * speedFactor; - - simTime = simTime.plusNanos(MillsToAdd*1_000_000); - - long secondsAfterPreviousNotification = ChronoUnit.SECONDS.between(simTime, lastNotificationDate); - - if(secondsAfterPreviousNotification >=1) { - notifyOthers(); - - lastNotificationDate = lastNotificationDate.plusSeconds(secondsAfterPreviousNotification); - - } - - } - - public synchronized void register(ClockObservers observer) { - observers.add(observer); - } - - private synchronized void notifyOthers() { - for(ClockObservers observer : observers) { - observer.onTick(simTime); - } - - } - - public void start() { - ispaused=false; - System.out.println("The Simulation has been started at time: \n"+ simTime); - } - - public void stop() { - ispaused=true; - System.out.println("The Simulation has been stopped at time: \n"+ simTime); - } - - public void setSpeedFactor(int speed) { - speedFactor=speed; - System.out.println("The Simulation speed has been intiated into: \n"+ speedFactor); - } - - public LocalDateTime getCurrentTime() { - return simTime; - } - public interface ClockObservers{ - void onTick(LocalDateTime currentTime); - } -} diff --git a/src/main/java/org/Automation/Controllers/WorkFlowController.java b/src/main/java/org/Automation/Controllers/WorkFlowController.java deleted file mode 100644 index 11b3bc7..0000000 --- a/src/main/java/org/Automation/Controllers/WorkFlowController.java +++ /dev/null @@ -1,26 +0,0 @@ -package WorkflowController; -import ProductionLine.ProductionLine; -import SensorManager.SensorManager; -import ActuatorManager.ActuatorManager; -import ItemTracker.ItemTracker; -public class WorkflowController { - //Instance Variables - private ProductionLine productionLine; - private SensorManager sensorMgmt; - private ActuatorManager ActuatorMgmt; - ItemTracker itemTracker; - - //Instance Methods - public void startProduction() { - - } - public void stopProduction() { - - } - public void handleItemFlow() { - - } - public void printSystemStatus() { - - } -} diff --git a/src/main/java/org/Automation/DatabaseManager.java b/src/main/java/org/Automation/DatabaseManager.java deleted file mode 100644 index 37a8727..0000000 --- a/src/main/java/org/Automation/DatabaseManager.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.Automation; - -import java.sql.*; - -interface DatabaseManagerInterface { - - boolean connect(); - - Connection getConnection(); - - boolean disconnect(); - - ResultSet find(String tableName, String where, Object[] params); - - boolean insert(String tableName, String[] columns, Object[] values); - - boolean delete(String tableName, String where, Object[] params); - - boolean update(String tableName, String setClause, String where, Object[] params); -} - -public final class DatabaseManager implements DatabaseManagerInterface { - - private Connection connection; - private final String url = "jdbc:sqlite:automation.sqlite"; - - public DatabaseManager() { - } - - @Override - public boolean connect() { - if (connection != null) - return true; - - try { - connection = DriverManager.getConnection(url); - System.out.println("Connection to SQLite established."); - return true; - } catch (SQLException e) { - throw new RuntimeException("Failed to connect", e); - } - } - - @Override - public Connection getConnection() { - return this.connection; - } - - @Override - public boolean disconnect() { - try { - if (connection != null) { - connection.close(); - System.out.println("Connection closed."); - } - return true; - } catch (SQLException e) { - throw new RuntimeException("Failed to disconnect", e); - } - } - - // ------------ Helper method for parameter binding ------------- - private void bindParams(PreparedStatement pstmt, Object[] params) throws SQLException { - if (params == null) - return; - - for (int i = 0; i < params.length; i++) { - pstmt.setObject(i + 1, params[i]); - } - } - - // ---------------- Helper method for SELECT queries ---------------- - private ResultSet executeQuery(String sql, Object[] params) { - try { - PreparedStatement pstmt = connection.prepareStatement(sql); - bindParams(pstmt, params); - return pstmt.executeQuery(); - } catch (SQLException e) { - throw new RuntimeException("Query execution failed: " + e.getMessage(), e); - } - } - - // ---------------- Helper method for INSERT, UPDATE, DELETE ---------------- - private boolean executeMutator(String sql, Object[] params) { - try (PreparedStatement pstmt = connection.prepareStatement(sql)) { - bindParams(pstmt, params); - return pstmt.executeUpdate() > 0; - } catch (SQLException e) { - throw new RuntimeException("Mutator execution failed: " + e.getMessage(), e); - } - } - - // ------------ Find (SELECT) ------------- - @Override - public ResultSet find(String tableName, String where, Object[] params) { - String sql = "SELECT * FROM " + tableName; - - if (where != null && !where.trim().isEmpty()) { - sql += " WHERE " + where; - } - - return executeQuery(sql, params); - } - - // ------------ INSERT ------------- - @Override - public boolean insert(String tableName, String[] columns, Object[] values) { - - if (columns.length != values.length) - throw new IllegalArgumentException("Columns and values length mismatch"); - - String cols = String.join(", ", columns); - - // creating placeholders (?) for the statement - String placeholders = ""; - for (int i = 0; i < values.length; i++) { - if (i < values.length - 1) { - placeholders += "?, "; - } else { - placeholders += "?"; - } - } - - String sql = "INSERT INTO " + tableName + " (" + cols + ") VALUES (" + placeholders + ")"; - - return executeMutator(sql, values); - } - - // ------------ DELETE ------------- - @Override - public boolean delete(String tableName, String where, Object[] params) { - String sql = "DELETE FROM " + tableName + - (where != null ? " WHERE " + where : ""); - - return executeMutator(sql, params); - } - - // ------------ UPDATE ------------- - @Override - public boolean update(String tableName, String setClause, String where, Object[] params) { - - String sql = "UPDATE " + tableName + " SET " + setClause + - (where != null ? " WHERE " + where : ""); - - return executeMutator(sql, params); - } -} diff --git a/src/main/java/org/Automation/Main.java b/src/main/java/org/Automation/Main.java deleted file mode 100644 index 8fd6ea3..0000000 --- a/src/main/java/org/Automation/Main.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.Automation; - -public class Main { - public static void main(String[] args) { - DatabaseManager db = new DatabaseManager(); - db.connect(); - } -} \ No newline at end of file diff --git a/src/main/java/org/Automation/TestSensorManager.java b/src/main/java/org/Automation/TestSensorManager.java deleted file mode 100644 index 6116df9..0000000 --- a/src/main/java/org/Automation/TestSensorManager.java +++ /dev/null @@ -1,114 +0,0 @@ -package org.Automation; - -import org.Automation.controllers.SensorManager; -import org.Automation.entities.*; -import java.util.List; - -public class TestSensorManager { - public static void main(String[] args) { - System.out.println("=== SensorManager Test Suite ===\n"); - - // Step 1: Create SensorManager - System.out.println("Step 1: Creating SensorManager"); - SensorManager manager = new SensorManager(); - System.out.println("Initial sensor count: " + manager.getSensorCount()); - - // Step 2: Add Temperature Sensors - System.out.println("\nStep 2: Adding Temperature Sensors"); - TemperatureSensor temp1 = new TemperatureSensor("Temperature", "Factory Floor A", "Active", 20.0, 80.0, "°C"); - TemperatureSensor temp2 = new TemperatureSensor("Temperature", "Factory Floor B", "Active", 15.0, 75.0, "°C"); - - manager.addSensor(temp1); - manager.addSensor(temp2); - System.out.println("Sensor count after adding temperature sensors: " + manager.getSensorCount()); - - // Step 3: Add Weight Sensors - System.out.println("\nStep 3: Adding Weight Sensors"); - WeightSensor weight1 = new WeightSensor("Weight", "Conveyor Belt 1", "Active", 50.0, 100.0, "kg"); - WeightSensor weight2 = new WeightSensor("Weight", "Conveyor Belt 2", "Active", 10.0, 50.0, "kg"); - - manager.addSensor(weight1); - manager.addSensor(weight2); - System.out.println("Sensor count after adding weight sensors: " + manager.getSensorCount()); - - // Step 4: Display all sensors - manager.displayAllSensors(); - - // Step 5: Test sensor reading - System.out.println("\nStep 5: Reading all sensor data (3 times)"); - for (int i = 1; i <= 3; i++) { - System.out.println("\n--- Reading #" + i + " ---"); - manager.readAllSensorData(); - - // Check for alerts - List alerts = manager.getAlertSensors(); - if (!alerts.isEmpty()) { - System.out.println("\nāš ļø ALERTS DETECTED:"); - for (Sensor sensor : alerts) { - System.out.println(" " + sensor); - } - } - - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - // Step 6: Test search by type - System.out.println("\n\nStep 6: Testing search by type"); - List tempSensors = manager.findSensorsByType("Temperature"); - System.out.println("Temperature sensors found: " + tempSensors.size()); - tempSensors.forEach(s -> System.out.println(" " + s)); - - List weightSensors = manager.findSensorsByType("Weight"); - System.out.println("Weight sensors found: " + weightSensors.size()); - weightSensors.forEach(s -> System.out.println(" " + s)); - - // Step 7: Test search by location - System.out.println("\nStep 7: Testing search by location"); - List floorASensors = manager.findSensorsByLocation("Factory Floor A"); - System.out.println("Sensors at Factory Floor A: " + floorASensors.size()); - floorASensors.forEach(s -> System.out.println(" " + s)); - - // Step 8: Test find by ID - System.out.println("\nStep 8: Testing find by ID"); - Sensor found = manager.findSensorById(2); - if (found != null) { - System.out.println("Found sensor with ID 2: " + found); - } else { - System.out.println("Sensor with ID 2 not found"); - } - - // Step 9: Test calibration - System.out.println("\nStep 9: Testing sensor calibration"); - manager.calibrateSensor(1); - manager.calibrateAllSensors(); - - // Step 10: Test activation/deactivation - System.out.println("\nStep 10: Testing activation/deactivation"); - manager.deactivateAllSensors(); - manager.printSensorStatus(); - - manager.activateAllSensors(); - manager.printSensorStatus(); - - // Step 11: Test sensor removal - System.out.println("\nStep 11: Testing sensor removal"); - System.out.println("Removing sensor with ID 3"); - boolean removed = manager.removeSensor(3); - System.out.println("Removal successful: " + removed); - System.out.println("Final sensor count: " + manager.getSensorCount()); - - manager.displayAllSensors(); - - // Step 12: Test edge cases - System.out.println("\nStep 12: Testing edge cases"); - manager.addSensor(null); // Should handle null - manager.removeSensor(999); // Should handle non-existent ID - manager.calibrateSensor(999); // Should handle non-existent ID - - System.out.println("\n=== Test Complete ==="); - } -} \ No newline at end of file diff --git a/src/main/java/org/Automation/controllers/SensorManager.java b/src/main/java/org/Automation/controllers/SensorManager.java deleted file mode 100644 index 1254c0a..0000000 --- a/src/main/java/org/Automation/controllers/SensorManager.java +++ /dev/null @@ -1,261 +0,0 @@ -package org.Automation.controllers; - -import org.Automation.entities.Sensor; -import java.util.ArrayList; -import java.util.List; - -/** - * SensorManager - Manages all sensors in the factory - * Responsibilities: - * - Add/remove sensors - * - Update all sensor values - * - Monitor sensor status - * - Find sensors by ID or type - */ -public class SensorManager { - private Map sensors; - private int totalSensors; - private int activeSensors; - - // Simulation clock for sensor manager - private SimulationClock simulationClock; - - public SensorManager() { - this.sensors = new HashMap<>(); - - // Create simulation clock for sensor manager - this.simulationClock = new SimulationClock("SensorManager", 2000) { - @Override - protected void tick() { - super.tick(); - readValue(); - } - }; - - System.out.println("SensorManager initialized with empty sensor list"); - } - - // SimulationClock delegation - public void start() { simulationClock.start(); } - public void stop() { simulationClock.stop(); } - public boolean isRunning() { return simulationClock.isRunning(); } - public int getCurrentTime() { return simulationClock.getCurrentTime(); } - public void setInterval(int intervalMs) { simulationClock.setInterval(intervalMs); } - - // Utility methods - public int getSensorCount() { - return totalSensors; - } - - public Map getAllSensors() { - return new HashMap<>(sensors); - } - - private void updateCounts() { - totalSensors = sensors.size(); - activeSensors = 0; - for (Sensor sensor : sensors.values()) { - if (sensor.isActive()) { - activeSensors++; - } - } - } - - public void updateValue() { - readValue(); - } - - public Object getValue() { - return getAllSensors(); - } - - - // Core management methods - public void addSensor(Sensor sensor) { - if (sensor == null) { - System.out.println("Error: Cannot add null sensor"); - return; - } - - Integer key = sensor.getSensorId(); - - if (sensors.containsKey(key)) { - System.out.println("Sensor with ID " + key + " already exists"); - return; - } - - sensors.put(key, sensor); - totalSensors++; - - if (sensor.isActive()) { - activeSensors++; - } - System.out.println("Added sensor: " + sensor); - } - - public boolean removeSensor(int sensorId) { - if (!sensors.containsKey(sensorId)) { - System.out.println("Sensor with ID " + sensorId + " not found"); - return false; - } - Sensor removed = sensors.remove(sensorId); - totalSensors--; - if (removed.isActive()) { - activeSensors--; - } - System.out.println("Removed sensor: " + removed); - return true; - } - - public void activateAllSensors() { - System.out.println("\n=== Activating All Sensors ==="); - sensors.values().forEach(sensor -> { - sensor.activateSensor(); - if (sensor.isActive()) { - activeSensors++; - } - }); - } - - public void deactivateAllSensors() { - System.out.println("\n=== Deactivating All Sensors ==="); - sensors.values().forEach(sensor -> { - sensor.deactivateSensor(); - if (!sensor.isActive()) { - activeSensors--; - } - }); - } - - // Search methods - public Sensor findSensorById(int sensorId) { - return sensors.get(sensorId); - } - - public List findSensorsByType(String sensorType) { - return sensors.get(sensorType); - } - - // Operations methods - public void readValue() { - System.out.println("\n=== Reading All Sensor Data ==="); - sensors.values().forEach(sensor -> { - sensor.readSensorData(); - System.out.println(" " + sensor); - }); - updateCounts(); - } - - public void updateAllSensors() { - System.out.println("\n=== Updating All Sensors ==="); - sensors.forEach((id,sensor) -> { - sensor.updateValue(); - System.out.println(" " + sensor); - }); - updateCounts(); - } - - public void calibrateAllSensors() { - System.out.println("\n=== Calibrating All Sensors ==="); - sensors.values().forEach(Sensor::calibrateSensor); - } - - public void calibrateSensor(int sensorId) { - Sensor sensor = findSensorById(sensorId); - if (sensor != null) { - sensor.calibrateSensor(); - } else { - System.out.println("Sensor with ID " + sensorId + " not found for calibration"); - } - } - - // Status monitoring - public List getAlertSensors() { - return sensors.values().stream() - .filter(sensor -> sensor.getStatus().contains("Alert")) - .toList(); - } - - public List getActiveSensors() { - return sensors.values().stream() - .filter(Sensor::isActive) - .toList(); - } - - public List getInactiveSensors() { - return sensors.values().stream() - .filter(sensor -> !sensor.isActive()) - .toList(); - } - - // Display methods - public void displayAllSensors() { - System.out.println("\n=== All Sensors ==="); - if (sensors.isEmpty()) { - System.out.println(" No sensors registered"); - } else { - sensors.values().forEach(sensor -> System.out.println(" " + sensor)); - } - } - - public void printSensorStatus() { - updateCounts(); - System.out.println("\n=== Sensor Status Summary ==="); - System.out.println("Total sensors: " + totalSensors); - System.out.println("Active sensors: " + activeSensors); - System.out.println("Inactive sensors: " + (totalSensors - activeSensors)); - System.out.println("Alert sensors: " + getAlertSensors().size()); - } - - - // Temperature control methods - public void enableTemperatureControl(int sensorId, double targetTemp, double threshold) { - Sensor sensor = findSensorById(sensorId); - if (sensor instanceof TemperatureSensor) { - ((TemperatureSensor) sensor).enableTemperatureControl(targetTemp, threshold); - } else { - System.out.println("Sensor " + sensorId + " is not a temperature sensor"); - } - } - - public void enableAllTemperatureControl(double targetTemp, double threshold) { - List tempSensors = findSensorsByType("Temperature"); - for (Sensor sensor : tempSensors) { - ((TemperatureSensor) sensor).enableTemperatureControl(targetTemp, threshold); - } - } - - // Weight control methods - public void enableWeightControl(int sensorId, double capacity) { - Sensor sensor = findSensorById(sensorId); - if (sensor instanceof WeightSensor) { - ((WeightSensor) sensor).enableWeightControl(capacity); - } else { - System.out.println("Sensor " + sensorId + " is not a weight sensor"); - } - } - - public boolean addWeightToSensor(int sensorId, double weight) { - Sensor sensor = findSensorById(sensorId); - if (sensor instanceof WeightSensor) { - return ((WeightSensor) sensor).addWeight(weight); - } - System.out.println("Sensor " + sensorId + " is not a weight sensor"); - return false; - } - - public void printControlStatus() { - System.out.println("\n=== Control Status ==="); - for (Sensor sensor : sensors.values()) { - if (sensor instanceof TemperatureSensor) { - TemperatureSensor temp = (TemperatureSensor) sensor; - System.out.println("Temp Sensor " + sensor.getSensorId() + ": " + - temp.getTemperatureStatus() + " (" + temp.getCurrentValue() + "°C)"); - } else if (sensor instanceof WeightSensor) { - WeightSensor weight = (WeightSensor) sensor; - System.out.println("Weight Sensor " + sensor.getSensorId() + ": " + - weight.getWeightStatus() + " (" + weight.getCurrentValue() + "kg)"); - } - } - } -} diff --git a/src/main/java/org/Automation/controllers/SimulationClock.observerclass.java b/src/main/java/org/Automation/controllers/SimulationClock.observerclass.java deleted file mode 100644 index 6ef253a..0000000 --- a/src/main/java/org/Automation/controllers/SimulationClock.observerclass.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.Automation.controllers; - -import java.time.LocalDateTime; - -/** - * ClockObserver - Interface for receiving simulation clock notifications - */ -public interface ClockObserver { - void onTick(LocalDateTime currentTime); -} - - diff --git a/src/main/java/org/Automation/entities/EventLog.java b/src/main/java/org/Automation/entities/EventLog.java deleted file mode 100644 index 50b6f9e..0000000 --- a/src/main/java/org/Automation/entities/EventLog.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.Automation.entities; - -public class EventLog { - public int id; - public String timestamp; - public String componentType; - public int componentId; - public String eventType; - public String message; - - public EventLog(int id, String timestamp, String componentType, int componentId, String eventType, String message) { - this.id = id; - this.timestamp = timestamp; - this.componentType = componentType; - this.componentId = componentId; - this.eventType = eventType; - this.message = message; - } - - @Override - public String toString() { - return "EventLog{id=" + id + ", timestamp=" + timestamp + ", componentType=" + componentType + ", componentId=" + componentId + ", eventType=" + eventType + ", message=" + message + "}"; - } -} diff --git a/src/main/java/org/Automation/entities/Product.java b/src/main/java/org/Automation/entities/Product.java deleted file mode 100644 index d50a76d..0000000 --- a/src/main/java/org/Automation/entities/Product.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.Automation.entities; - -public class Product { - public int id; - public String name; - public String status; - - public Product(int id, String name, String status) { - this.id = id; - this.name = name; - this.status = status; - } - - @Override - public String toString() { - return "Product{id=" + id + ", name=" + name + ", status=" + status + "}"; - } -} diff --git a/src/main/java/org/Automation/entities/Sensor.java b/src/main/java/org/Automation/entities/Sensor.java deleted file mode 100644 index 5f4aead..0000000 --- a/src/main/java/org/Automation/entities/Sensor.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.Automation.entities; - -public abstract class Sensor { - private static int idCounter = 0; - - protected int sensorId; - protected String sensorType; - protected String location; - protected String status; - protected double currentValue; - protected boolean isActive; - - // Constructor with auto-increment ID - public Sensor(String sensorType, String location, String status) { - this.sensorId = ++idCounter; - this.sensorType = sensorType; - this.location = location; - this.status = status; - this.isActive = false; - this.currentValue = 0.0; - } - - // Constructor with manual ID - public Sensor(int sensorId, String sensorType, String location, String status) { - this.sensorId = sensorId; - this.sensorType = sensorType; - this.location = location; - this.status = status; - this.isActive = false; - this.currentValue = 0.0; - if (sensorId > idCounter) { - idCounter = sensorId; - } - } - - // Abstract methods from diagram - public abstract void readValue(); - public abstract void calibrateSensor(); - public abstract boolean validateReading(); - public abstract void sendAlert(); - public abstract void updateValue(); - public abstract Object getValue(); - - // Concrete methods - public void activateSensor() { - this.isActive = true; - this.status = "Active"; - System.out.println("Sensor " + sensorId + " activated"); - } - - public void deactivateSensor() { - this.isActive = false; - this.status = "Inactive"; - System.out.println("Sensor " + sensorId + " deactivated"); - } - - public void updateStatus(String newStatus) { - this.status = newStatus; - } - - // Getters and Setters - public int getSensorId() { return sensorId; } - public String getSensorType() { return sensorType; } - public String getLocation() { return location; } - public String getStatus() { return status; } - public double getCurrentValue() { return currentValue; } - public boolean isActive() { return isActive; } - - public void setSensorId(int sensorId) { this.sensorId = sensorId; } - public void setSensorType(String sensorType) { this.sensorType = sensorType; } - public void setLocation(String location) { this.location = location; } - public void setStatus(String status) { this.status = status; } - public void setCurrentValue(double currentValue) { this.currentValue = currentValue; } - public void setActive(boolean active) { this.isActive = active; } - - @Override - public String toString() { - return "Sensor{id=" + sensorId + ", type=" + sensorType + ", location=" + location + - ", status=" + status + ", value=" + currentValue + ", active=" + isActive + "}"; - } -} diff --git a/src/main/java/org/Automation/entities/TemperatureSensor.java b/src/main/java/org/Automation/entities/TemperatureSensor.java deleted file mode 100644 index e8428f6..0000000 --- a/src/main/java/org/Automation/entities/TemperatureSensor.java +++ /dev/null @@ -1,223 +0,0 @@ -package org.Automation.entities; - -import org.Automation.controllers.SimulationClock; -import java.time.LocalDateTime; -import java.util.Timer; -import java.util.TimerTask; - -public class TemperatureSensor extends Sensor implements SimulationClock.ClockObserver { - - // ========== CORE TEMPERATURE FIELDS ========== - private double currentTemperature; - private double minTemperature; - private double maxTemperature; - private String temperatureUnit; - private double calibrationOffset; - private double temperatureIncrement; - - // ========== CONTROL SYSTEM FIELDS ========== - private double targetTemperature; - private double temperatureThreshold; - private boolean temperatureControlEnabled; - - // ========== SIMULATION FIELDS ========== - private double startThreshold; - private boolean maxReached; - private double coolingRate; - private LocalDateTime lastActionTime; - - // ========== CONSTRUCTOR ========== - public TemperatureSensor(String sensorType, String location, String status, - double minTemperature, double maxTemperature, String temperatureUnit) { - super(sensorType, location, status); - this.minTemperature = minTemperature; - this.maxTemperature = maxTemperature; - this.temperatureUnit = temperatureUnit; - this.currentTemperature = minTemperature; - - // Register with global simulation clock - SimulationClock.getInstance().register(this); - } - - public TemperatureSensor(String sensorType, int location, String status, - double minTemperature, double maxTemperature) { - this(sensorType, String.valueOf(location), status, minTemperature, maxTemperature, "°C"); - } - - @Override - public void onTick(LocalDateTime currentTime) { - if (lastActionTime == null || currentTime.minusSeconds(5).isAfter(lastActionTime)) { - if (isActive() && !maxReached) { - performTemperatureCycle(); - } - lastActionTime = currentTime; - } - } - - // ========== GETTERS ========== - public double getCurrentTemperature() { return currentTemperature; } - public String getTemperatureUnit() { return temperatureUnit; } - public double getTargetTemperature() { return targetTemperature; } - public boolean isTemperatureControlEnabled() { return temperatureControlEnabled; } - - public String getSensorInfo() { - return String.format("TemperatureSensor[ID=%d, Type=%s, Location=%s, Status=%s, " + - "Current=%.2f%s, Range=%.1f-%.1f%s, Target=%.1f%s, Control=%s]", - getSensorId(), getSensorType(), getLocation(), getStatus(), - currentTemperature, temperatureUnit, - minTemperature, maxTemperature, temperatureUnit, - targetTemperature, temperatureUnit, - temperatureControlEnabled ? "Enabled" : "Disabled"); - } - - // ========== ABSTRACT METHOD IMPLEMENTATIONS ========== - @Override - public void readValue() { - readSensorData(); - } - - @Override - public void updateValue() { - simulateTemperature(); - } - - @Override - public Object getValue() { - return currentTemperature; - } - - @Override - public void calibrateSensor() { - System.out.println("šŸ”§ Calibrating temperature sensor " + getSensorId()); - this.calibrationOffset = 0.5; - } - - @Override - public boolean validateReading() { - return currentTemperature >= minTemperature && currentTemperature <= maxTemperature; - } - - @Override - public void sendAlert() { - System.out.println("🚨 TEMPERATURE ALERT - Sensor " + getSensorId() + - ": " + currentTemperature + temperatureUnit); - updateStatus("Alert"); - } - - // ========== CORE TEMPERATURE METHODS ========== - public void readSensorData() { - double temp = simulateTemperature(); - this.currentTemperature = temp + calibrationOffset; - setCurrentValue(currentTemperature); - - System.out.println(getSensorInfo()); - - if (!validateReading()) { - sendAlert(); - } - } - - public double simulateTemperature() { - this.currentTemperature += temperatureIncrement; - - if (currentTemperature > maxTemperature) { - currentTemperature = maxTemperature; - } else if (currentTemperature < minTemperature) { - currentTemperature = minTemperature; - } - - this.currentTemperature = Math.round(currentTemperature); - setCurrentValue(currentTemperature); - return currentTemperature; - } - - // ========== CONTROL SYSTEM METHODS ========== - public void enableTemperatureControl(double targetTemp, double threshold) { - this.targetTemperature = targetTemp; - this.temperatureThreshold = threshold; - this.temperatureControlEnabled = true; - } - - public String getTemperatureStatus() { - if (!temperatureControlEnabled) { - return "Control Disabled"; - } - - double difference = Math.abs(currentTemperature - targetTemperature); - - if (difference <= temperatureThreshold) { - return "Within Target Range"; - } else if (currentTemperature > targetTemperature + temperatureThreshold) { - return "Too Hot"; - } else { - return "Too Cold"; - } - } - - // ========== SIMULATION CONTROL ========== - public void start() { - this.currentTemperature = startThreshold; - setCurrentValue(currentTemperature); - maxReached = false; - activateSensor(); - System.out.println("šŸŒ”ļø Starting temperature sensor " + getSensorId() + " simulation"); - System.out.println("Initial temperature: " + getCurrentTemperature() + temperatureUnit); - } - - public void stop() { - deactivateSensor(); - } - - public boolean isRunning() { - return isActive(); - } - - public void configureHeatingParameters(double startThreshold, double increment, double coolingRate) { - this.startThreshold = startThreshold; - this.coolingRate = coolingRate; - this.temperatureIncrement = increment; - } - - // ========== PRIVATE SIMULATION HELPERS ========== - private void performTemperatureCycle() { - if (isActive() && !maxReached) { - this.currentTemperature += temperatureIncrement; - setCurrentValue(currentTemperature); - System.out.println("šŸŒ”ļø Sensor " + getSensorId() + " heating: " + getCurrentTemperature() + temperatureUnit); - - if (currentTemperature >= maxTemperature) { - this.currentTemperature = maxTemperature; - setCurrentValue(currentTemperature); - maxReached = true; - deactivateSensor(); - System.out.println("šŸŒ”ļø Sensor " + getSensorId() + " reached max: " + maxTemperature + "°C - DEACTIVATED"); - System.out.println(getSensorInfo()); - startCoolingMonitor(); - } - } - } - - private void startCoolingMonitor() { - Timer coolingTimer = new Timer("Cooling-" + getSensorId(), true); - coolingTimer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - double cooledTemp = currentTemperature - coolingRate; - currentTemperature = Math.max(cooledTemp, startThreshold); - setCurrentValue(currentTemperature); - - System.out.println("ā„ļø Sensor " + getSensorId() + " cooling: " + getCurrentTemperature() + temperatureUnit); - - if (currentTemperature <= startThreshold + 5.0) { - coolingTimer.cancel(); - System.out.println("šŸ”„ Sensor " + getSensorId() + " temperature dropped - RESTARTING"); - maxReached = false; - activateSensor(); - start(); - } - } - }, 2000, 2000); - } -} - - diff --git a/src/main/java/org/Automation/entities/WeightSensor.java b/src/main/java/org/Automation/entities/WeightSensor.java deleted file mode 100644 index 0eda8b4..0000000 --- a/src/main/java/org/Automation/entities/WeightSensor.java +++ /dev/null @@ -1,204 +0,0 @@ -package org.Automation.entities; - -import org.Automation.controllers.SimulationClock; - -public class WeightSensor extends Sensor { - // ========== CORE WEIGHT FIELDS ========== - private double minWeight; - private double maxWeight; - private double currentWeight; - private String weightUnit; - private double calibrationFactor; - private double weightIncrement; - - // ========== CONTROL SYSTEM FIELDS ========== - private double machineCapacity; - private boolean weightControlEnabled; - - // ========== SIMULATION FIELDS ========== - private SimulationClock simulationClock; - private double startWeight; - private boolean maxReached; - - // ========== CONSTRUCTOR ========== - public WeightSensor(String sensorType, String location, String status, - double minWeight, double maxWeight, String weightUnit) { - super(sensorType, location, status); - this.minWeight = minWeight; - this.maxWeight = maxWeight; - this.weightUnit = weightUnit; - this.currentWeight = minWeight; - this.startWeight = minWeight; - - this.simulationClock = new SimulationClock("WeightSensor-" + getSensorId(), 1000) { - @Override - protected void tick() { - super.tick(); - performWeightCycle(); - } - }; - } - - // ========== GETTERS ========== - public double getCurrentWeight() { return currentWeight; } - public String getWeightUnit() { return weightUnit; } - public double getMachineCapacity() { return machineCapacity; } - public boolean isWeightControlEnabled() { return weightControlEnabled; } - - public String getSensorInfo() { - return String.format("WeightSensor[ID=%d, Type=%s, Location=%s, Status=%s, " + - "Current=%.2f%s, Range=%.1f-%.1f%s, Capacity=%.1f%s, Control=%s]", - getSensorId(), getSensorType(), getLocation(), getStatus(), - currentWeight, weightUnit, - minWeight, maxWeight, weightUnit, - machineCapacity, weightUnit, - weightControlEnabled ? "Enabled" : "Disabled"); - } - - // ========== ABSTRACT METHOD IMPLEMENTATIONS ========== - @Override - public void readValue() { - readSensorData(); - } - - @Override - public void updateValue() { - simulateWeight(); - } - - @Override - public Object getValue() { - return currentWeight; - } - - @Override - public void calibrateSensor() { - System.out.println("šŸ”§ Calibrating weight sensor " + getSensorId()); - this.calibrationFactor = 0.1; - } - - @Override - public boolean validateReading() { - return currentWeight >= minWeight && currentWeight <= maxWeight; - } - - @Override - public void sendAlert() { - System.out.println("🚨 WEIGHT ALERT - Sensor " + getSensorId() + - ": " + currentWeight + weightUnit); - updateStatus("Alert"); - } - - // ========== CORE WEIGHT METHODS ========== - public void readSensorData() { - double weight = simulateWeight(); - this.currentWeight = weight + calibrationFactor; - setCurrentValue(currentWeight); - - System.out.println(getSensorInfo()); - - if (!validateReading()) { - sendAlert(); - } - } - - public double simulateWeight() { - this.currentWeight += weightIncrement; - - if (currentWeight > maxWeight) { - currentWeight = maxWeight; - } else if (currentWeight < minWeight) { - currentWeight = minWeight; - } - - this.currentWeight = Math.round(currentWeight); - setCurrentValue(currentWeight); - return currentWeight; - } - - // ========== CONTROL SYSTEM METHODS ========== - public void enableWeightControl(double capacity) { - this.machineCapacity = capacity; - this.weightControlEnabled = true; - } - - public boolean addWeight(double weight) { - double currentWeightValue = getCurrentWeight(); - if (currentWeightValue + weight <= machineCapacity) { - this.currentWeight += weight; - setCurrentValue(currentWeight); - System.out.println("āš–ļø Added " + weight + weightUnit + " to sensor " + getSensorId() + - " (Total: " + getCurrentWeight() + weightUnit + ")"); - System.out.println(getSensorInfo()); - return true; - } else { - System.out.println("🚨 Cannot add " + weight + weightUnit + " - would exceed capacity!"); - System.out.println("Current: " + getCurrentWeight() + weightUnit + ", Capacity: " + machineCapacity + weightUnit); - return false; - } - } - - // ========== SIMULATION CONTROL ========== - public void start() { - this.currentWeight = startWeight; - setCurrentValue(currentWeight); - maxReached = false; - activateSensor(); - simulationClock.start(); - System.out.println("āš–ļø Starting weight sensor " + getSensorId() + " simulation"); - System.out.println("Initial weight: " + getCurrentWeight() + weightUnit); - } - - public void stop() { - simulationClock.stop(); - } - - public boolean isRunning() { - return simulationClock.isRunning(); - } - - public void setSimulationInterval(int intervalMs) { - calculateIncrementForInterval(intervalMs); - simulationClock.setInterval(intervalMs); - } - - public void configureWeightParameters(double startWeight, double increment, int intervalMs) { - this.startWeight = startWeight; - setSimulationInterval(intervalMs); - this.weightIncrement = increment; - } - - // ========== PRIVATE SIMULATION HELPERS ========== - private void performWeightCycle() { - if (isActive() && !maxReached) { - double currentWeightValue = getCurrentWeight(); - - while (currentWeightValue < machineCapacity && !maxReached) { - this.currentWeight += weightIncrement; - setCurrentValue(currentWeight); - currentWeightValue = getCurrentWeight(); - System.out.println("āš–ļø Sensor " + getSensorId() + " loading: " + currentWeightValue + weightUnit); - } - - this.currentWeight = machineCapacity; - setCurrentValue(currentWeight); - maxReached = true; - deactivateSensor(); - simulationClock.stop(); - System.out.println("āš–ļø Sensor " + getSensorId() + " reached capacity: " + machineCapacity + - "kg - DEACTIVATED & STOPPED"); - System.out.println(getSensorInfo()); - } - } - - private void calculateIncrementForInterval(int intervalMs) { - if (intervalMs <= 1000) this.weightIncrement = 5.0; - else if (intervalMs <= 2000) this.weightIncrement = 10.0; - else this.weightIncrement = 15.0; - } -} - - - - - diff --git a/src/main/java/org/Automation/repositories/EventLogRepository.java b/src/main/java/org/Automation/repositories/EventLogRepository.java deleted file mode 100644 index 925b7df..0000000 --- a/src/main/java/org/Automation/repositories/EventLogRepository.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.Automation.repositories; - -import java.sql.ResultSet; -import java.sql.SQLException; - -import org.Automation.DatabaseManager; -import org.Automation.entities.EventLog; - -public class EventLogRepository extends Repository { - public EventLogRepository(DatabaseManager db) { - super("EventLog", db); - } - - - @Override - public EventLog mapRow(ResultSet rs) throws SQLException { - return new EventLog( - rs.getInt("id"), - rs.getString("timestamp"), - rs.getString("componentType"), - rs.getInt("componentId"), - rs.getString("eventType"), - rs.getString("message")); - } - - @Override - public String createTableQuery() { - return """ - CREATE TABLE IF NOT EXISTS EventLog ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - timestamp TEXT NOT NULL, - componentType TEXT, - componentId INTEGER, - eventType TEXT, - message TEXT - ); - """; - } -} diff --git a/src/main/java/org/Automation/repositories/ProductRepository.java b/src/main/java/org/Automation/repositories/ProductRepository.java deleted file mode 100644 index 899bf5e..0000000 --- a/src/main/java/org/Automation/repositories/ProductRepository.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.Automation.repositories; -import org.Automation.entities.Product; - -import java.sql.ResultSet; -import java.sql.SQLException; - -import org.Automation.DatabaseManager; - -public class ProductRepository extends Repository { - public ProductRepository(DatabaseManager db) { - super("Product", db); - } - - @Override - public String createTableQuery() { - return """ - CREATE TABLE IF NOT EXISTS Product ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name TEXT NOT NULL, - status TEXT - ); - """; - } - - @Override - protected Product mapRow(ResultSet rs) throws SQLException { - return new Product( - rs.getInt("id"), - rs.getString("name"), - rs.getString("status")); - } -} \ No newline at end of file diff --git a/src/main/java/org/Automation/repositories/SensorRepository.java b/src/main/java/org/Automation/repositories/SensorRepository.java deleted file mode 100644 index 85b861b..0000000 --- a/src/main/java/org/Automation/repositories/SensorRepository.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.Automation.repositories; - -import java.sql.ResultSet; -import java.sql.SQLException; - -import org.Automation.DatabaseManager; -import org.Automation.entities.Sensor; - -public class SensorRepository extends Repository { - public SensorRepository(DatabaseManager db) { - super("Sensor", db); - } - - - @Override - public Sensor mapRow(ResultSet rs) throws SQLException { - return new Sensor( - rs.getInt("id"), - rs.getString("type"), - rs.getInt("machineId"), - rs.getString("status")); - } - - @Override - public String createTableQuery() { - return """ - CREATE TABLE IF NOT EXISTS Sensor ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - type TEXT NOT NULL, - machineId INTEGER, - status TEXT DEFAULT 'inactive', - FOREIGN KEY(machineId) REFERENCES Machine(id) - ); - """; - } -} diff --git a/src/main/java/org/automation/SensorDemo.java b/src/main/java/org/automation/SensorDemo.java new file mode 100644 index 0000000..ceaacc7 --- /dev/null +++ b/src/main/java/org/automation/SensorDemo.java @@ -0,0 +1,40 @@ +// package org.automation; + +// import org.automation.entities.*; + +// public class SensorDemo { +// public static void main(String[] args) { +// System.out.println("=== Factory Sensor Monitoring System ===\n"); + +// // Create Temperature and Weight sensors +// TemperatureSensor tempSensor = new TemperatureSensor("Temperature","Factory Floor A", "Active", 20.0,5, 80.0, "°C"); +// WeightSensor weightSensor = new WeightSensor("Weight", "Conveyor Belt 1", "Active", 50.0, 100.0, "kg"); + +// System.out.println("Initial State:"); +// System.out.println(tempSensor); +// System.out.println(weightSensor); + +// System.out.println("\n=== Updating Sensor Values ===\n"); + +// // Simulate 5 readings +// for (int i = 1; i <= 5; i++) { +// System.out.println("Reading #" + i + ":"); + +// tempSensor.updateValue(0.5); +// weightSensor.updateValue(1.0); + +// System.out.println(" " + tempSensor); +// System.out.println(" " + weightSensor); +// System.out.println(); + +// try { +// Thread.sleep(1000); // Wait 1 second between readings +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// } + +// System.out.println("=== Monitoring Complete ==="); +// } +// } + diff --git a/src/main/java/org/automation/SensorManagerDemo.java b/src/main/java/org/automation/SensorManagerDemo.java new file mode 100644 index 0000000..c29afaa --- /dev/null +++ b/src/main/java/org/automation/SensorManagerDemo.java @@ -0,0 +1,93 @@ +// package org.automation; + +// import org.automation.controllers.SensorManager; +// import org.automation.entities.*; +// import java.util.List; + +// /** +// * Demo showing SensorManager initialization and usage +// */ +// public class SensorManagerDemo { +// public static void main(String[] args) { +// System.out.println("=== SensorManager Initialization Demo ===\n"); + +// // Step 1: Create SensorManager (initializes empty list) +// System.out.println("Step 1: Creating SensorManager"); +// SensorManager manager = new SensorManager(); +// // System.out.println(" Sensor count: " + manager.getSensorCount()); + +// // Step 2: Add Temperature Sensors +// System.out.println("\nStep 2: Adding Temperature Sensors"); +// TemperatureSensor temp1 = new TemperatureSensor("Temperature", "Factory Floor A", "Active", 20.0, 5, 80.0, "°C"); +// TemperatureSensor temp2 = new TemperatureSensor("Temperature", "Factory Floor B", "Active", 15.0,6, 75.0, "°C"); + +// manager.addSensor(temp1); +// manager.addSensor(temp2); +// // System.out.println(" Sensor count: " + manager.getSensorCount()); + +// // Step 3: Add Weight Sensors +// System.out.println("\nStep 3: Adding Weight Sensors"); +// WeightSensor weight1 = new WeightSensor("Weight", "Conveyor Belt 1", "Active", 50.0, 100.0, "kg"); +// WeightSensor weight2 = new WeightSensor("Weight", "Conveyor Belt 2", "Active", 10.0, 50.0, "kg"); + +// manager.addSensor(weight1); +// manager.addSensor(weight2); +// // System.out.println(" Sensor count: " + manager.getSensorCount()); + +// // Step 4: Display all sensors +// manager.displayAllSensors(); + +// // Step 5: Update all sensors (simulate readings) +// // System.out.println("\nStep 5: Updating all sensors (3 readings)"); +// // for (int i = 1; i <= 3; i++) { +// // System.out.println("\n--- Reading #" + i + " ---"); +// // manager.updateAllSensors(); + +// // // Check for alerts +// // List alerts = manager.getAlertSensors(); +// // if (!alerts.isEmpty()) { +// // System.out.println("\nāš ļø ALERTS DETECTED:"); +// // for (Sensor sensor : alerts) { +// // System.out.println(" " + sensor); +// // } +// // } + +// // try { +// // Thread.sleep(1000); +// // } catch (InterruptedException e) { +// // e.printStackTrace(); +// // } +// // } + +// // Step 6: Find sensors by type +// // System.out.println("\n\nStep 6: Finding sensors by type"); +// // List tempSensors = manager.findSensorsByType("Temperature"); +// // System.out.println(" Temperature sensors: " + tempSensors.size()); +// // for (Sensor s : tempSensors) { +// // System.out.println(" " + s); +// // } + +// // List weightSensors = manager.findSensorsByType("Weight"); +// // System.out.println(" Weight sensors: " + weightSensors.size()); +// // for (Sensor s : weightSensors) { +// // System.out.println(" " + s); +// // } + +// // Step 7: Find sensor by ID +// System.out.println("\nStep 7: Finding sensor by ID"); +// Sensor found = manager.findSensorById(2); +// if (found != null) { +// System.out.println(" Found: " + found); +// } + +// // Step 8: Remove a sensor +// System.out.println("\nStep 8: Removing sensor with ID 3"); +// manager.removeSensor(3); +// // System.out.println(" Sensor count: " + manager.getSensorCount()); + +// manager.displayAllSensors(); + +// System.out.println("\n=== Demo Complete ==="); +// } +// } + diff --git a/src/main/java/org/automation/TestInitialization.java b/src/main/java/org/automation/TestInitialization.java new file mode 100644 index 0000000..3e88f34 --- /dev/null +++ b/src/main/java/org/automation/TestInitialization.java @@ -0,0 +1,35 @@ +// package org.automation; + +// import org.automation.entities.TemperatureSensor; + +// public class TestInitialization { +// public static void main(String[] args) { +// System.out.println("=== Testing Initialization ===\n"); + +// Create sensor with minTemp=20, maxTemp=80 +// TemperatureSensor sensor = new TemperatureSensor("Temperature", "Factory Floor A", "Active", 20.0, 5,80.0, "°C"); + +// // System.out.println("After constructor:"); +// // System.out.println(" minTemp = " + sensor.getMinTemp()); // Should be 20.0 +// // System.out.println(" maxTemp = " + sensor.getMaxTemp()); // Should be 80.0 + +// System.out.println("\nCalling updateValue() 5 times:"); +// for (int i = 1; i <= 5; i++) { +// sensor.updateValue(0.5); +// double temp = (Double) sensor.getValue(); +// System.out.println(" Reading #" + i + ": " + temp + "°C"); + +// // Verify temperature is using minTemp and maxTemp correctly +// if (temp >= 20.0 && temp <= 80.0) { +// System.out.println(" āœ… Within range [20.0 - 80.0]"); +// } else { +// System.out.println(" āš ļø Outside range (testing alert condition)"); +// } +// } + +// System.out.println("\n=== Conclusion ==="); +// System.out.println("minTemp and maxTemp ARE initialized in the constructor!"); +// System.out.println("They are used by simulateTemperature() to generate values."); +// } +// } + diff --git a/src/main/java/org/automation/TestSensorManager.java b/src/main/java/org/automation/TestSensorManager.java new file mode 100644 index 0000000..2119f02 --- /dev/null +++ b/src/main/java/org/automation/TestSensorManager.java @@ -0,0 +1,83 @@ +package org.automation; + +import org.automation.controllers.SensorManager; +import org.automation.entities.Sensor; +import org.automation.entities.TemperatureSensor; +import org.automation.entities.WeightSensor; + +import java.util.List; +import java.util.Scanner; + +public class TestSensorManager { + + private static final Scanner scanner = new Scanner(System.in); + + public static void main(String[] args) { + System.out.println("Initializing Sensor Management System..."); + SensorManager manager = new SensorManager(); + + boolean running = true; + while (running) { + printMenu(); + int choice = readInt("Select option: "); + switch (choice) { + case 1 -> listSensors(manager); + case 2 -> addTemperatureSensor(manager); + case 3 -> addWeightSensor(manager); + case 4 -> startSensor(manager); + case 5 -> stopSensor(manager); + case 6 -> readSensorValue(manager); + case 7 -> toggleAutomatic(manager); + case 8 -> setControl(manager); + case 9 -> removeSensor(manager); + case 10 -> findById(manager); + case 11 -> manager.startAll(); + case 12 -> manager.stopAll(); + case 0 -> { manager.shutdown(5); running = false; } + default -> System.out.println("Unknown option."); + } + } + } + + private static void printMenu() { + System.out.println("\n1-List 2-Add Temp 3-Add Weight 4-Start 5-Stop 6-Read 7-Auto 8-Control 9-Remove 10-Find 11-StartAll 12-StopAll 0-Exit"); + } + + private static int readInt(String prompt) { + System.out.print(prompt); + try { return Integer.parseInt(scanner.nextLine().trim()); } catch (Exception e) { return -1; } + } + + private static double readDouble(String prompt) { + System.out.print(prompt); + try { return Double.parseDouble(scanner.nextLine().trim()); } catch (Exception e) { return Double.NaN; } + } + + private static String prompt(String msg) { System.out.print(msg); return scanner.nextLine().trim(); } + + private static void listSensors(SensorManager manager) { + List infos = manager.listSensorInfo(); + infos.forEach(System.out::println); + } + + private static void addTemperatureSensor(SensorManager manager) { + TemperatureSensor t = new TemperatureSensor("Temperature", prompt("Location: "), "Init", readDouble("Start: "), readDouble("Tol: "), readDouble("Target: "), "°C"); + manager.addSensor(t); + } + + private static void addWeightSensor(SensorManager manager) { + WeightSensor w = new WeightSensor("Weight", prompt("Location: "), "Init", readDouble("Initial: "), readDouble("Capacity: "), "kg"); + manager.addSensor(w); + } + + private static void startSensor(SensorManager manager) { System.out.println(manager.startSensor(readInt("ID: ")) ? "Started" : "Failed"); } + private static void stopSensor(SensorManager manager) { System.out.println(manager.stopSensor(readInt("ID: ")) ? "Stopped" : "Failed"); } + private static void readSensorValue(SensorManager manager) { + Sensor s = manager.findSensorById(readInt("ID: ")); + if (s != null) s.readValue(); + } + private static void toggleAutomatic(SensorManager manager) { manager.setSensorAutomaticMode(readInt("ID: "), readInt("0/1: ") == 1); } + private static void setControl(SensorManager manager) { manager.setSensorControl(readInt("ID: "), readInt("0/1: ") == 1, readDouble("Target: "), readDouble("Tol: ")); } + private static void removeSensor(SensorManager manager) { manager.removeSensor(readInt("ID: ")); } + private static void findById(SensorManager manager) { System.out.println(manager.findSensorById(readInt("ID: ")).getSensorInfo()); } +} diff --git a/src/main/java/org/automation/controllers/ActuatorManager.java b/src/main/java/org/automation/controllers/ActuatorManager.java new file mode 100644 index 0000000..7e91f4d --- /dev/null +++ b/src/main/java/org/automation/controllers/ActuatorManager.java @@ -0,0 +1,5 @@ +package org.automation.controllers; + +public class ActuatorManager { + +} diff --git a/src/main/java/org/automation/controllers/ProductionLine.java b/src/main/java/org/automation/controllers/ProductionLine.java new file mode 100644 index 0000000..2b489eb --- /dev/null +++ b/src/main/java/org/automation/controllers/ProductionLine.java @@ -0,0 +1,5 @@ +package org.automation.controllers; + +public class ProductionLine { + +} diff --git a/src/main/java/org/automation/controllers/SensorManager.java b/src/main/java/org/automation/controllers/SensorManager.java new file mode 100644 index 0000000..b450ad3 --- /dev/null +++ b/src/main/java/org/automation/controllers/SensorManager.java @@ -0,0 +1,150 @@ +package org.automation.controllers; + +import org.automation.database.DatabaseManager; +import org.automation.entities.Sensor; +import org.automation.repositories.SensorRepository; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * SensorManager - Central controller for factory sensors + * - Add/remove sensors + * - Start/stop sensors + * - Bulk operations + * - Toggle automatic/control modes per sensor and in bulk + * - Graceful shutdown + */ +public class SensorManager { + + private final Map sensors = new ConcurrentHashMap<>(); + private final ExecutorService executor = Executors.newCachedThreadPool(); + private final DatabaseManager dbManager; + private final SensorRepository sensorRepo; + + public SensorManager() { + System.out.println("SensorManager initialized"); + // initialize database and repository + this.dbManager = new DatabaseManager(); + SensorRepository repo = null; + try { + if (this.dbManager.connect()) { + repo = new SensorRepository(this.dbManager); + repo.ensureTable(); + // load persisted sensors + List persisted = repo.findAll(); + for (Sensor s : persisted) { + sensors.putIfAbsent(s.getSensorId(), s); + System.out.println("Loaded sensor from DB: " + s.getSensorInfo()); + } + } + } catch (Exception e) { + System.err.println("Database init failed:"); + e.printStackTrace(); + + } + this.sensorRepo = repo; + } + + // ------------------------- + // Basic sensor management + // ------------------------- + public void addSensor(Sensor sensor) { + if (sensor == null) return; + sensors.putIfAbsent(sensor.getSensorId(), sensor); + System.out.println("Added sensor: " + sensor.getSensorInfo()); + if (sensorRepo != null) { + try { + sensorRepo.save(sensor); + } catch (Exception e) { + System.err.println("Failed to persist sensor: " + e.getMessage()); + } + } + } + + public boolean removeSensor(int sensorId) { + Sensor removed = sensors.remove(sensorId); + if (removed != null) { + System.out.println("Removed sensor: " + removed.getSensorInfo()); + if (sensorRepo != null) { + try { + sensorRepo.deleteById(sensorId); + } catch (Exception e) { + System.err.println("Failed to remove sensor from DB: " + e.getMessage()); + } + } + return true; + } else { + System.err.println("Sensor ID " + sensorId + " not found"); + return false; + } + } + + public Sensor findSensorById(int sensorId) { + return sensors.get(sensorId); + } + + public List listSensorInfo() { + List info = new ArrayList<>(); + for (Sensor s : sensors.values()) info.add(s.getSensorInfo()); + return info; + } + + public String getSensorInfo(int sensorId) { + Sensor s = findSensorById(sensorId); + return s == null ? null : s.getSensorInfo(); + } + + public void removeAllSensors() { + // Clear sensors from the database, then clear in-memory map + if (sensorRepo != null) { + try { + // delete all rows from Sensor table + sensorRepo.delete(null, null); + } catch (Exception e) { + System.err.println("Failed to clear sensors from DB: " + e.getMessage()); + } + } + sensors.clear(); + } + + public void updateSensors() { + if (sensorRepo == null) return; + for (Sensor s : sensors.values()) { + try { + sensorRepo.save(s); + } catch (Exception e) { + System.err.println("Failed to persist sensor (ID=" + s.getSensorId() + "): " + e.getMessage()); + } + } + } + + // ------------------------- + // Graceful shutdown + // ------------------------- + public void shutdown(long timeoutSeconds) { + // stop sensors first + + // shutdown executor + executor.shutdown(); + try { + if (!executor.awaitTermination(timeoutSeconds, TimeUnit.SECONDS)) { + executor.shutdownNow(); + } + } catch (InterruptedException e) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); + } + try { + // shutdown the simulation clock to avoid lingering threads + try { org.automation.engine.SimulationClock.getInstance().shutdown(); } catch (Exception ignored) {} + if (dbManager != null) dbManager.disconnect(); + } catch (Exception ignored) {} + System.out.println("SensorManager shutdown complete"); + } +} diff --git a/src/main/java/org/automation/database/DatabaseManager.java b/src/main/java/org/automation/database/DatabaseManager.java new file mode 100644 index 0000000..7dbe56b --- /dev/null +++ b/src/main/java/org/automation/database/DatabaseManager.java @@ -0,0 +1,153 @@ +package org.automation.database; + +import java.sql.*; + +public final class DatabaseManager implements AutoCloseable { + + private Connection connection; + private static final String URL = "jdbc:sqlite:automation.sqlite"; + + /** + * Connect to SQLite database + */ + public boolean connect() { + if (connection != null) return true; + + try { + // šŸ”“ REQUIRED: force SQLite JDBC driver to load + Class.forName("org.sqlite.JDBC"); + + connection = DriverManager.getConnection(URL); + System.out.println("Connection to SQLite established."); + return true; + } catch (Exception e) { + throw new RuntimeException("Failed to connect", e); + } + } + + public Connection getConnection() { + if (connection == null) { + throw new IllegalStateException("Database not connected"); + } + return connection; + } + + /** + * Close DB connection + */ + public boolean disconnect() { + try { + if (connection != null && !connection.isClosed()) { + connection.close(); + System.out.println("Connection closed."); + } + connection = null; + return true; + } catch (SQLException e) { + throw new RuntimeException("Failed to disconnect", e); + } + } + + /* ---------------- PARAM BINDING ---------------- */ + + private void bindParams(PreparedStatement pstmt, Object[] params) throws SQLException { + if (params == null) return; + for (int i = 0; i < params.length; i++) { + pstmt.setObject(i + 1, params[i]); + } + } + + /* ---------------- SELECT HELPERS ---------------- */ + + public java.util.List query( + String tableName, + String where, + Object[] params, + RowMapper mapper + ) { + String sql = "SELECT * FROM " + tableName + + (where != null && !where.trim().isEmpty() ? " WHERE " + where : ""); + + java.util.List result = new java.util.ArrayList<>(); + + try (PreparedStatement pstmt = getConnection().prepareStatement(sql)) { + bindParams(pstmt, params); + try (ResultSet rs = pstmt.executeQuery()) { + while (rs.next()) { + result.add(mapper.mapRow(rs)); + } + } + } catch (SQLException e) { + throw new RuntimeException("Query execution failed", e); + } + + return result; + } + + public T queryOne( + String tableName, + String where, + Object[] params, + RowMapper mapper + ) { + java.util.List list = query(tableName, where, params, mapper); + return list.isEmpty() ? null : list.get(0); + } + + /* ---------------- DDL ---------------- */ + + public boolean executeDDL(String sql) { + try (Statement stmt = getConnection().createStatement()) { + stmt.execute(sql); + return true; + } catch (SQLException e) { + throw new RuntimeException("DDL execution failed", e); + } + } + + /* ---------------- MUTATORS ---------------- */ + + private boolean executeMutator(String sql, Object[] params) { + if (connection == null) connect(); + try (PreparedStatement pstmt = getConnection().prepareStatement(sql)) { + bindParams(pstmt, params); + return pstmt.executeUpdate() > 0; + } catch (SQLException e) { + throw new RuntimeException("Mutator execution failed", e); + } + } + + + public boolean insert(String tableName, String[] columns, Object[] values) { + if (columns.length != values.length) { + throw new IllegalArgumentException("Columns and values length mismatch"); + } + + String cols = String.join(", ", columns); + String placeholders = String.join(", ", java.util.Collections.nCopies(values.length, "?")); + + String sql = "INSERT INTO " + tableName + + " (" + cols + ") VALUES (" + placeholders + ")"; + + return executeMutator(sql, values); + } + + public boolean update(String tableName, String setClause, String where, Object[] params) { + String sql = "UPDATE " + tableName + " SET " + setClause + + (where != null ? " WHERE " + where : ""); + return executeMutator(sql, params); + } + + public boolean delete(String tableName, String where, Object[] params) { + String sql = "DELETE FROM " + tableName + + (where != null ? " WHERE " + where : ""); + return executeMutator(sql, params); + } + + /* ---------------- CLEANUP ---------------- */ + + @Override + public void close() { + disconnect(); + } +} diff --git a/src/main/java/org/automation/database/RowMapper.java b/src/main/java/org/automation/database/RowMapper.java new file mode 100644 index 0000000..e9f60ee --- /dev/null +++ b/src/main/java/org/automation/database/RowMapper.java @@ -0,0 +1,12 @@ +package org.automation.database; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Functional interface for mapping a ResultSet row to a domain object. + */ +@FunctionalInterface +public interface RowMapper { + T mapRow(ResultSet rs) throws SQLException; +} diff --git a/src/main/java/org/automation/engine/ClockObserver.java b/src/main/java/org/automation/engine/ClockObserver.java new file mode 100644 index 0000000..9777b4b --- /dev/null +++ b/src/main/java/org/automation/engine/ClockObserver.java @@ -0,0 +1,8 @@ +package org.automation.engine; + +import java.time.LocalDateTime; + +public interface ClockObserver { + void onTick(LocalDateTime currentTime); +} + diff --git a/src/main/java/org/automation/engine/SimulationClock.java b/src/main/java/org/automation/engine/SimulationClock.java new file mode 100644 index 0000000..8147d40 --- /dev/null +++ b/src/main/java/org/automation/engine/SimulationClock.java @@ -0,0 +1,143 @@ +package org.automation.engine; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * SimulationClock + * + * - Singleton clock used by sensors + * - Notifies registered ClockObserver instances once per simulated second + * - Exposes getTickIntervalMs() for sensors to adapt increments + */ +public class SimulationClock { + + // Singleton instance + private static SimulationClock instance; + + // Simulation time state + private LocalDateTime simTime; + private LocalDateTime lastNotificationDate; + + // Speed and pause control + private volatile int speedFactor = 1; + private volatile boolean isPaused = false; + + // Scheduler and tick configuration + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r, "SimulationClock"); + t.setDaemon(true); + return t; + }); + private static final int TICK_PER_MS = 50; // base tick in milliseconds + + // Observers (thread-safe for iteration) + private final CopyOnWriteArrayList observers = new CopyOnWriteArrayList<>(); + + private SimulationClock() { + this.simTime = LocalDateTime.now(); + this.lastNotificationDate = this.simTime; + startIntegralTimer(); + } + + public static synchronized SimulationClock getInstance() { + if (instance == null) { + instance = new SimulationClock(); + } + return instance; + } + + private void startIntegralTimer() { + scheduler.scheduleAtFixedRate(() -> { + if (!isPaused) { + tick(); + } + }, 0, TICK_PER_MS, TimeUnit.MILLISECONDS); + } + + private void tick() { + long millisToAdd = (long) TICK_PER_MS * speedFactor; + simTime = simTime.plusNanos(millisToAdd * 1_000_000L); + + long secondsAfterPreviousNotification = ChronoUnit.SECONDS.between(lastNotificationDate, simTime); + if (secondsAfterPreviousNotification >= 1) { + notifyObservers(); + lastNotificationDate = lastNotificationDate.plusSeconds(secondsAfterPreviousNotification); + } + } + + public synchronized void register(ClockObserver observer) { + if (observer != null && !observers.contains(observer)) { + observers.add(observer); + } + } + + public synchronized void unregister(ClockObserver observer) { + observers.remove(observer); + } + + private void notifyObservers() { + for (ClockObserver observer : observers) { + try { + observer.onTick(simTime); + } catch (Throwable t) { + // keep clock running even if an observer throws + t.printStackTrace(); + } + } + } + + public synchronized void start() { + isPaused = false; + System.out.println("The Simulation has been started at time:\n" + simTime); + } + + public synchronized void stop() { + isPaused = true; + System.out.println("The Simulation has been stopped at time:\n" + simTime); + } + + public void setSpeedFactor(int speed) { + if (speed <= 0) throw new IllegalArgumentException("Speed must be > 0"); + this.speedFactor = speed; + System.out.println("Simulation speed set to: " + speedFactor); + } + + public LocalDateTime getCurrentTime() { + return simTime; + } + + /** + * Method expected by sensors: returns effective tick interval in milliseconds. + */ + public int getTickIntervalMs() { + return TICK_PER_MS * speedFactor; + } + + /** + * Graceful shutdown for the scheduler (call at application exit). + */ + public synchronized void shutdown() { + try { + // request orderly shutdown + scheduler.shutdown(); + // wait briefly for tasks to finish + if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { + // force shutdown if not finished + scheduler.shutdownNow(); + if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { + System.err.println("SimulationClock did not terminate"); + } + } + } catch (InterruptedException ie) { + scheduler.shutdownNow(); + Thread.currentThread().interrupt(); + } catch (Throwable t) { + t.printStackTrace(); + } + } +} diff --git a/src/main/java/org/Automation/Controllers/Simluators/SimulationEngine.java b/src/main/java/org/automation/engine/SimulationEngine.java similarity index 71% rename from src/main/java/org/Automation/Controllers/Simluators/SimulationEngine.java rename to src/main/java/org/automation/engine/SimulationEngine.java index c2dfc57..d0fc3fc 100644 --- a/src/main/java/org/Automation/Controllers/Simluators/SimulationEngine.java +++ b/src/main/java/org/automation/engine/SimulationEngine.java @@ -1,19 +1,14 @@ -package Sim_Engine; - -import java.time.LocalDateTime; - -import WorkflowController.WorkflowController; +package org.automation.engine; +// import java.time.LocalDateTime; +// import org.automation.controllers.WorkflowController; +// import org.automation.utils.Logger; public class SimulationEngine { //Instance Variables - WorkflowController controller; - Logger logger; + // WorkflowController controller; + // Logger logger; - //Instance Methods - public void runStep() { - - } public void startSimulation() { SimulationClock clock = SimulationClock.getInstance(); diff --git a/src/main/java/org/Automation/entities/ConveyorBelt.java b/src/main/java/org/automation/entities/ConveyorBelt.java similarity index 95% rename from src/main/java/org/Automation/entities/ConveyorBelt.java rename to src/main/java/org/automation/entities/ConveyorBelt.java index ea268c6..91df915 100644 --- a/src/main/java/org/Automation/entities/ConveyorBelt.java +++ b/src/main/java/org/automation/entities/ConveyorBelt.java @@ -1,4 +1,4 @@ -package org.Automation.entities; +package org.automation.entities; public class ConveyorBelt { public int id; diff --git a/src/main/java/org/Automation/entities/Machine.java b/src/main/java/org/automation/entities/Machine.java similarity index 94% rename from src/main/java/org/Automation/entities/Machine.java rename to src/main/java/org/automation/entities/Machine.java index 9582678..a6e3aaf 100644 --- a/src/main/java/org/Automation/entities/Machine.java +++ b/src/main/java/org/automation/entities/Machine.java @@ -1,4 +1,4 @@ -package org.Automation.entities; +package org.automation.entities; public class Machine { public int id; diff --git a/src/main/java/org/automation/entities/Product.java b/src/main/java/org/automation/entities/Product.java new file mode 100644 index 0000000..6e80551 --- /dev/null +++ b/src/main/java/org/automation/entities/Product.java @@ -0,0 +1,12 @@ +package org.automation.entities; + +/** + * DEPRECATED: Replaced by `ProductItem`. + * + * This class was kept for compatibility but should not be used anymore. + */ +@Deprecated +public final class Product { + private Product() { + /* prevent instantiation */ } +} diff --git a/src/main/java/org/automation/entities/ProductItem.java b/src/main/java/org/automation/entities/ProductItem.java new file mode 100644 index 0000000..4c6d49a --- /dev/null +++ b/src/main/java/org/automation/entities/ProductItem.java @@ -0,0 +1,74 @@ +package org.automation.entities; + +public class ProductItem { + public int id; + public String name; + public double weight; + public String status; + public int currentStationId; + public String createdAt; + + public ProductItem(int id, String name, double weight, String status, String createdAt, int currentStationId) { + this.id = id; + this.name = name; + this.weight = weight; + this.status = status; + this.createdAt = createdAt; + this.currentStationId = currentStationId; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public double getWeight() { + return weight; + } + + public void setWeight(double weight) { + this.weight = weight; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public int getCurrentStationId() { + return currentStationId; + } + + public void setCurrentStationId(int currentStationId) { + this.currentStationId = currentStationId; + } + + @Override + public String toString() { + return "ProductItem{id=" + id + ", name=" + name + ", weight=" + weight + ", status=" + status + ", createdAt=" + + createdAt + ", currentStationId=" + currentStationId + "}"; + } +} + diff --git a/src/main/java/org/automation/entities/Sensor.java b/src/main/java/org/automation/entities/Sensor.java new file mode 100644 index 0000000..d2a497f --- /dev/null +++ b/src/main/java/org/automation/entities/Sensor.java @@ -0,0 +1,152 @@ +package org.automation.entities; + +import java.time.LocalDateTime; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Abstract Sensor base class. + * - Centralizes lifecycle bookkeeping and status management + * - Final template method for interval -> increments mapping + * - Provides lightweight automatic/control flags and APIs used by concrete sensors + * + * Thread-safety: + * - start()/stop() are synchronized to protect lifecycle transitions. + * - primaryIncrement and coolingRate are volatile to ensure visibility across threads. + */ +public abstract class Sensor { + private static final AtomicInteger ID_GEN = new AtomicInteger(1); + + // identity / metadata + protected final int sensorId; + protected final String sensorType; + protected String location; + protected String status; + + // lifecycle + protected volatile boolean isActive; + protected LocalDateTime startTime; + protected LocalDateTime stopTime; + + // shared, clock-driven increments + protected volatile double primaryIncrement; + protected volatile double coolingRate; + + // automation flag (default: automatic enabled) + protected volatile boolean automaticMode = true; + + protected Sensor(String sensorType, String location, String status) { + this.sensorId = ID_GEN.getAndIncrement(); + this.sensorType = sensorType; + this.location = location; + this.status = status; + this.isActive = false; + this.primaryIncrement = getBaselineIncrement(); + this.coolingRate = getBaselineCooling(); + } + + /** + * Construct sensor with a forced id (used when loading from persistent storage). + * Ensures the global ID generator is advanced past the forced id to avoid collisions. + */ + protected Sensor(int forcedId, String sensorType, String location, String status) { + this.sensorId = forcedId; + this.sensorType = sensorType; + this.location = location; + this.status = status; + this.isActive = false; + this.primaryIncrement = getBaselineIncrement(); + this.coolingRate = getBaselineCooling(); + // advance ID generator to avoid future collisions + int next = forcedId + 1; + while (true) { + int cur = ID_GEN.get(); + if (cur >= next) break; + if (ID_GEN.compareAndSet(cur, next)) break; + } + } + + // ----------------------- + // Lifecycle (centralized) + // ----------------------- + protected void activateSensor() { isActive = true; setStatus("Active"); } + protected void deactivateSensor() { isActive = false; setStatus("Paused"); } + + public boolean isActive() { return isActive; } + public int getSensorId() { return sensorId; } + public String getSensorType() { return sensorType; } + public String getLocation() { return location; } + public String getStatus() { return status; } + + // ----------------------- + // Status helpers + // ----------------------- + protected synchronized void setStatus(String newStatus) { + this.status = newStatus; + } + + /** + * Update status after a read. Keeps statuses consistent across sensors. + * @param valid whether the last reading validated successfully + */ + protected synchronized void updateStatusAfterRead(boolean valid) { + if (!isActive) setStatus("Stopped"); + else if (!valid) setStatus("Error"); + else setStatus("OK"); + } + // ----------------------- + // Interval -> increment mapping (single place) + // ----------------------- + /** + * Final template method mapping clock interval -> increments. + */ + public final void setSimulationInterval(int intervalMs) { + double baseline = getBaselineIncrement(); + double baselineCooling = getBaselineCooling(); + + if (intervalMs <= 1000) { + primaryIncrement = baseline; + coolingRate = baselineCooling; + } else if (intervalMs <= 2000) { + primaryIncrement = baseline * 2.0; + coolingRate = baselineCooling * 2.0; + } else { + primaryIncrement = baseline * 4.0; + coolingRate = baselineCooling * 4.0; + } + + onIntervalUpdated(intervalMs); + } + + // Subclass hooks + protected abstract double getBaselineIncrement(); + protected double getBaselineCooling() { return 0.5; } + protected void onIntervalUpdated(int intervalMs) { /* optional override */ } + + // ----------------------- + // Shared helpers + // ----------------------- + protected void setCurrentValue(Object value) { /* telemetry hook */ } + + protected void raiseAlert(String title, String details) { + setStatus("Error"); + System.err.println("ALERT [" + sensorId + "] " + title + " - " + details); + } + + // ----------------------- + // Abstract contract + // ----------------------- + public abstract Object getValue(); + public abstract void readValue(); + public abstract void updateValue(double change); + public abstract void calibrateSensor(); + public abstract boolean validateReading(); + public abstract void sendAlert(double currentValue); + public abstract String getSensorInfo(); + public abstract void performCycle(); + + // helper to manually adjust next id (rarely needed) + public static void setNextId(int next) { + if (next <= 0) return; + ID_GEN.set(next); + } +} diff --git a/src/main/java/org/automation/entities/TemperatureSensor.java b/src/main/java/org/automation/entities/TemperatureSensor.java new file mode 100644 index 0000000..521bb95 --- /dev/null +++ b/src/main/java/org/automation/entities/TemperatureSensor.java @@ -0,0 +1,226 @@ +package org.automation.entities; + +import org.automation.engine.SimulationClock; +import org.automation.engine.ClockObserver; + +import java.time.LocalDateTime; + +/** + * TemperatureSensor + * - Implements baseline increment and cooling baseline + * - Registers/unregisters with SimulationClock in onStart/onStop hooks + * - Uses primaryIncrement and coolingRate set by Sensor.setSimulationInterval(...) + * - Uses Sensor's automaticMode and controlEnabled flags; provides a convenience wrapper + */ +public class TemperatureSensor extends Sensor implements ClockObserver { + + private double currentTemperature; + private final String temperatureUnit; + private double calibrationOffset; + private boolean calibrated = false; + + private double targetTemperature; + private double temperatureTolerance; + + private final double startThreshold; + private LocalDateTime lastActionTime; + + public TemperatureSensor(String sensorType, String location, String status, + double startThreshold, double temperatureTolerance, + double targetTemperature, String temperatureUnit) { + super(sensorType, location, status); + this.startThreshold = startThreshold; + this.temperatureTolerance = temperatureTolerance; + this.targetTemperature = targetTemperature; + this.temperatureUnit = temperatureUnit; + this.currentTemperature = startThreshold; + // initialize local targets only + } + + /** + * Construct a TemperatureSensor with an explicit sensor id (used when loading from DB). + */ + public TemperatureSensor(int sensorId, String sensorType, String location, String status, + double startThreshold, double temperatureTolerance, + double targetTemperature, String temperatureUnit) { + super(sensorId, sensorType, location, status); + this.startThreshold = startThreshold; + this.temperatureTolerance = temperatureTolerance; + this.targetTemperature = targetTemperature; + this.temperatureUnit = temperatureUnit; + this.currentTemperature = startThreshold; + // initialize local targets only + } + + public TemperatureSensor(String sensorType, int location, String status, + double startThreshold, double temperatureTolerance, + double targetTemperature) { + this(sensorType, String.valueOf(location), status, startThreshold, temperatureTolerance, targetTemperature, "°C"); + } + + @Override + protected double getBaselineIncrement() { return 0.5; } + + @Override + protected double getBaselineCooling() { return 0.25; } + + @Override + public void onTick(LocalDateTime currentTime) { + synchronized (this) { + if (!isActive()) return; + + if (lastActionTime == null || currentTime.minusSeconds(1).isAfter(lastActionTime)) { + try { + int intervalMs = SimulationClock.getInstance().getTickIntervalMs(); + setSimulationInterval(intervalMs); + // Always run cycle; automatic mode removed + performCycle(); + } catch (Exception e) { + sendAlert(currentTemperature + calibrationOffset); + setStatus("Error"); + } + lastActionTime = currentTime; + } + } + } + + // ----------------------- + // Abstract implementations + // ----------------------- + @Override + public Object getValue() { return currentTemperature; } + + @Override + public void readValue() { + calibrateSensor(); + double calibratedTemp = currentTemperature + calibrationOffset; + System.out.println(getSensorInfo() + " | Calibrated Temperature: " + String.format("%.2f%s", calibratedTemp, temperatureUnit)); + boolean valid = validateReading(calibratedTemp); + if (!valid) sendAlert(calibratedTemp); + updateStatusAfterRead(valid); + System.out.println("⚔ Status: " + getTemperatureStatus(calibratedTemp)); + System.out.println("Current: " + currentTemperature + ", Calibrated: " + (currentTemperature + calibrationOffset) + ", Target: " + targetTemperature + ", Tolerance: " + temperatureTolerance); + + } + + @Override + public void updateValue(double change) { + simulateTemperature(change); + readValue(); + } + + @Override + public void calibrateSensor() { + if (!calibrated) { + setStatus("Calibrating"); + System.out.println("šŸ”§ Calibrating temperature sensor " + getSensorId()); + this.calibrationOffset = 0.05 + Math.random() * 0.1; + calibrated = true; + setStatus("Calibrated"); + } + } + + @Override + public boolean validateReading() { + return validateReading(currentTemperature + calibrationOffset); + } + + public boolean validateReading(double calibratedTemp) { + return Math.abs(calibratedTemp - targetTemperature) <= temperatureTolerance; + } + + @Override + public void sendAlert(double currentTemp) { + double calibratedTemp = currentTemp + calibrationOffset; + raiseAlert("Temperature out of range", temperatureUnit + " (Calibrated: " + String.format("%.2f", calibratedTemp) + ")"); + } + + @Override + public String getSensorInfo() { + return String.format( + "TemperatureSensor[ID=%d, Type=%s, Location=%s, Status=%s, Current=%.2f%s, Start=%.2f%s, Target=%.2f%s, Tolerance=%.2f%s]", + getSensorId(), getSensorType(), getLocation(), getStatus(), + currentTemperature, temperatureUnit, + startThreshold, temperatureUnit, + targetTemperature, temperatureUnit, + temperatureTolerance, temperatureUnit + ); + } + + // ----------------------- + // Simulation logic + // ----------------------- + public double simulateTemperature(double change) { + currentTemperature += change; + setCurrentValue(currentTemperature); + return currentTemperature; + } + +public String getTemperatureStatus(double tempToCheck) { + // Too cold only if below the minimum allowed by start threshold and tolerance + if (tempToCheck < startThreshold - temperatureTolerance) { + return "Too Cold"; + } + + // Too hot only if above the maximum allowed by target temperature and tolerance + if (tempToCheck > targetTemperature + temperatureTolerance) { + return "Too Hot"; + } + + // Otherwise, within range + return "Within Target Range"; +} + + // ----------------------- + // Heating / Cooling cycle (uses primaryIncrement and coolingRate) + // ----------------------- +private void startHeating() { + updateValue(primaryIncrement); + if (currentTemperature >= targetTemperature) { + currentTemperature = targetTemperature; + setStatus("WithinTarget"); + } else { + setStatus("Heating"); + } +} + +private void startCooling() { + updateValue(-coolingRate); + if (currentTemperature <= startThreshold) { + currentTemperature = startThreshold; + setStatus("WithinTarget"); + } else { + setStatus("Cooling"); + } +} + + +@Override +public void performCycle() { + double calibrated = currentTemperature + calibrationOffset; + + double lowerLimit = targetTemperature - temperatureTolerance; // heat below this + double upperLimit = targetTemperature + temperatureTolerance; // cool above this + + if (calibrated < lowerLimit) { + startHeating(); + } else if (calibrated > upperLimit) { + startCooling(); + } else { + setStatus("WithinDeadband"); // do nothing + } + + // Safety alerts + if (calibrated < startThreshold - temperatureTolerance || calibrated > targetTemperature + temperatureTolerance) { + sendAlert(currentTemperature); + } +} + + + // getters + public double getCurrentTemperature() { return currentTemperature; } + public String getTemperatureUnit() { return temperatureUnit; } + public double getTargetTemperature() { return targetTemperature; } + public double getStartThreshold() { return startThreshold; } + public double getTemperatureTolerance() { return temperatureTolerance; } +} diff --git a/src/main/java/org/automation/entities/WeightSensor.java b/src/main/java/org/automation/entities/WeightSensor.java new file mode 100644 index 0000000..8241afa --- /dev/null +++ b/src/main/java/org/automation/entities/WeightSensor.java @@ -0,0 +1,210 @@ +package org.automation.entities; + +import org.automation.engine.SimulationClock; +import org.automation.engine.ClockObserver; + +import java.time.LocalDateTime; + +/** + * WeightSensor + * - Calibration offset is applied only when reporting/validating (Option 1) + * - Internal simulated value (currentWeight) remains the raw truth + * - Uses Sensor.primaryIncrement (clock-driven) for automatic per-tick weight changes + * - Uses Sensor's automaticMode and controlEnabled flags; provides convenience wrappers + */ +public class WeightSensor extends Sensor implements ClockObserver { + + private double currentWeight; + private final String weightUnit; + private double machineCapacity; + private double lastWeight; + + private double calibrationOffset; + private boolean calibrated = false; + + private volatile LocalDateTime lastActionTime; + // private SimulationClock simulationClock; + + public WeightSensor(String sensorType, String location, String status, + double initialWeight, double capacity, String weightUnit) { + super(sensorType, location, status); + this.currentWeight = initialWeight; + this.lastWeight = initialWeight; + this.machineCapacity = capacity; + this.weightUnit = weightUnit; + // this.simulationClock = SimulationClock.getInstance(); + // removed base control initialization + } + + /** + * Construct a WeightSensor with an explicit sensor id (used when loading from DB). + */ + public WeightSensor(int sensorId, String sensorType, String location, String status, + double initialWeight, double capacity, String weightUnit) { + super(sensorId, sensorType, location, status); + this.currentWeight = initialWeight; + this.lastWeight = initialWeight; + this.machineCapacity = capacity; + this.weightUnit = weightUnit; + // this.simulationClock = SimulationClock.getInstance(); + // removed base control initialization + } + + @Override + protected double getBaselineIncrement() { return 1.0; } + + @Override + protected double getBaselineCooling() { return 0.5; } + + // Removed onStart/onStop lifecycle overrides + + @Override + public void onTick(LocalDateTime currentTime) { + synchronized (this) { + if (!isActive()) return; + if (!automaticMode) return; // gate automatic behavior + if (lastActionTime == null || currentTime.minusSeconds(1).isAfter(lastActionTime)) { + try { + int intervalMs = SimulationClock.getInstance().getTickIntervalMs(); + setSimulationInterval(intervalMs); + // Simple drift without control logic + performCycle(); + } catch (IllegalArgumentException e) { + sendAlert(getCalibratedWeight()); + setStatus("Error"); + } + lastActionTime = currentTime; + } + } + } + + // ----------------------- + // Abstract implementations + // ----------------------- + @Override + public Object getValue() { return currentWeight; } + + @Override + public void readValue() { + calibrateSensor(); + double calibratedWeight = getCalibratedWeight(); + System.out.println(getSensorInfo() + " | Calibrated Weight: " + String.format("%.2f%s", calibratedWeight, weightUnit)); + boolean valid = validateReading(); + if (!valid) sendAlert(calibratedWeight); + updateStatusAfterRead(valid); + System.out.println("⚔ Status: " + (valid ? "Within Capacity" : "Out of Range")); + } + + @Override + public void updateValue(double change) { + try { + simulateWeight(change); + } catch (IllegalArgumentException e) { + sendAlert(getCalibratedWeight()); + setStatus("Error"); + return; + } + readValue(); + } + + @Override + public void calibrateSensor() { + if (!calibrated) { + setStatus("Calibrating"); + System.out.println("šŸ”§ Calibrating weight sensor " + getSensorId()); + this.calibrationOffset = 0.1 + Math.random() * 0.2; + calibrated = true; + setStatus("OK"); + } + } + + public double getCalibratedWeight() { + return currentWeight + calibrationOffset; + } + + @Override + public boolean validateReading() { + double calibrated = getCalibratedWeight(); + return calibrated > 0 && calibrated <= machineCapacity; + } + + @Override + public void sendAlert(double currentValue) { + raiseAlert("Weight out of range", String.format("%.2f%s", currentValue, weightUnit)); + } + + @Override + public String getSensorInfo() { + return String.format("WeightSensor[ID=%d, Type=%s, Location=%s, Status=%s, Current=%.2f%s, Capacity=%.2f%s, Auto=%s]", + getSensorId(), getSensorType(), getLocation(), getStatus(), + currentWeight, weightUnit, machineCapacity, weightUnit, automaticMode ? "On" : "Off"); + } + + // ----------------------- + // Simulation logic (raw value) + // ----------------------- + private synchronized void simulateWeight(double change) { + double newWeight = currentWeight + change; + + if (newWeight <= 0) { + throw new IllegalArgumentException("Load cannot be ≤ 0. Attempted: " + newWeight + weightUnit); + } + if (newWeight > machineCapacity) { + throw new IllegalArgumentException("Overload detected. Attempted: " + newWeight + weightUnit); + } + if (Math.abs(newWeight - lastWeight) > machineCapacity * 0.3) { + throw new IllegalArgumentException("Shock load detected. Change: " + (newWeight - lastWeight) + weightUnit); + } + + currentWeight = newWeight; + lastWeight = currentWeight; + setCurrentValue(currentWeight); + } + + // Manual control + public boolean addWeight(double weight) { + try { + updateValue(weight); + System.out.println("āš–ļø Added " + weight + weightUnit + " -> Current: " + currentWeight + weightUnit); + return true; + } catch (IllegalArgumentException e) { + sendAlert(getCalibratedWeight()); + setStatus("Error"); + return false; + } + } + + public boolean removeWeight(double weight) { + try { + updateValue(-weight); + System.out.println("āš–ļø Removed " + weight + weightUnit + " -> Current: " + currentWeight + weightUnit); + return true; + } catch (IllegalArgumentException e) { + sendAlert(getCalibratedWeight()); + setStatus("Error"); + return false; + } + } + + // Removed control enable/disable wrappers + + @Override + public void performCycle() { + // passive behavior: attempt small drift towards capacity without control targets + double calibrated = getCalibratedWeight(); + if (calibrated < machineCapacity) { + try { + updateValue(primaryIncrement); + } catch (Exception e) { + raiseAlert("Auto-adjust failed", e.getMessage()); + } + } else { + setStatus("WithinCapacity"); + } + } + + // getters + public double getCurrentWeight() { return currentWeight; } + public String getWeightUnit() { return weightUnit; } + public double getMachineCapacity() { return machineCapacity; } +} diff --git a/src/main/java/org/Automation/entities/Worker.java b/src/main/java/org/automation/entities/Worker.java similarity index 95% rename from src/main/java/org/Automation/entities/Worker.java rename to src/main/java/org/automation/entities/Worker.java index 1b122ba..30a1555 100644 --- a/src/main/java/org/Automation/entities/Worker.java +++ b/src/main/java/org/automation/entities/Worker.java @@ -1,4 +1,4 @@ -package org.Automation.entities; +package org.automation.entities; public class Worker { public int id; diff --git a/src/main/java/org/Automation/repositories/ConveyorRepository.java b/src/main/java/org/automation/repositories/ConveyorRepository.java similarity index 90% rename from src/main/java/org/Automation/repositories/ConveyorRepository.java rename to src/main/java/org/automation/repositories/ConveyorRepository.java index 93856b6..676563f 100644 --- a/src/main/java/org/Automation/repositories/ConveyorRepository.java +++ b/src/main/java/org/automation/repositories/ConveyorRepository.java @@ -1,10 +1,10 @@ -package org.Automation.repositories; +package org.automation.repositories; import java.sql.ResultSet; import java.sql.SQLException; -import org.Automation.DatabaseManager; -import org.Automation.entities.ConveyorBelt; +import org.automation.database.DatabaseManager; +import org.automation.entities.ConveyorBelt; public class ConveyorRepository extends Repository { public ConveyorRepository(DatabaseManager db) { diff --git a/src/main/java/org/Automation/repositories/MachineRepository.java b/src/main/java/org/automation/repositories/MachineRepository.java similarity index 88% rename from src/main/java/org/Automation/repositories/MachineRepository.java rename to src/main/java/org/automation/repositories/MachineRepository.java index d442f47..94b0166 100644 --- a/src/main/java/org/Automation/repositories/MachineRepository.java +++ b/src/main/java/org/automation/repositories/MachineRepository.java @@ -1,6 +1,6 @@ -package org.Automation.repositories; -import org.Automation.entities.Machine; -import org.Automation.DatabaseManager; +package org.automation.repositories; +import org.automation.entities.Machine; +import org.automation.database.DatabaseManager; import java.sql.ResultSet; import java.sql.SQLException; diff --git a/src/main/java/org/automation/repositories/ProductItemRepository.java b/src/main/java/org/automation/repositories/ProductItemRepository.java new file mode 100644 index 0000000..fe3d082 --- /dev/null +++ b/src/main/java/org/automation/repositories/ProductItemRepository.java @@ -0,0 +1,39 @@ +package org.automation.repositories; + +import org.automation.entities.ProductItem; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.automation.database.DatabaseManager; + +public class ProductItemRepository extends Repository { + public ProductItemRepository(DatabaseManager db) { + super("ProductItem", db); + } + + @Override + public String createTableQuery() { + return """ + CREATE TABLE IF NOT EXISTS ProductItem ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + weight REAL, + status TEXT, + createdAt TEXT, + currentStationId INTEGER + ); + """; + } + + @Override + protected ProductItem mapRow(ResultSet rs) throws SQLException { + return new ProductItem( + rs.getInt("id"), + rs.getString("name"), + rs.getDouble("weight"), + rs.getString("status"), + rs.getString("createdAt"), + rs.getInt("currentStationId")); + } +} \ No newline at end of file diff --git a/src/main/java/org/Automation/repositories/Repository.java b/src/main/java/org/automation/repositories/Repository.java similarity index 63% rename from src/main/java/org/Automation/repositories/Repository.java rename to src/main/java/org/automation/repositories/Repository.java index ca0dab9..fb3e94e 100644 --- a/src/main/java/org/Automation/repositories/Repository.java +++ b/src/main/java/org/automation/repositories/Repository.java @@ -1,9 +1,9 @@ -package org.Automation.repositories; -import org.Automation.DatabaseManager; +package org.automation.repositories; +import org.automation.database.DatabaseManager; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; +// import java.util.ArrayList; import java.util.List; public abstract class Repository { @@ -30,38 +30,27 @@ public boolean delete(String where, Object[] params) { } public T findOne(String where, Object[] params) { - try (ResultSet rs = db.find(tableName, where, params)) { - if (rs.next()) { - return mapRow(rs); - } - } catch (SQLException e) { + try { + return db.queryOne(tableName, where, params, rs -> mapRow(rs)); + } catch (RuntimeException e) { throw new RuntimeException("findOne failed: " + e.getMessage(), e); } - return null; } public List findAllWhere(String where, Object[] params) { - List result = new ArrayList<>(); - try (ResultSet rs = db.find(tableName, where, params)) { - while (rs.next()) { - result.add(mapRow(rs)); - } - } catch (SQLException e) { + try { + return db.query(tableName, where, params, rs -> mapRow(rs)); + } catch (RuntimeException e) { throw new RuntimeException("findAllWhere failed: " + e.getMessage(), e); } - return result; } public List findAll() { - List result = new ArrayList<>(); - try (ResultSet rs = db.find(tableName, null, null)) { - while (rs.next()) { - result.add(mapRow(rs)); - } - } catch (SQLException e) { + try { + return db.query(tableName, null, null, rs -> mapRow(rs)); + } catch (RuntimeException e) { throw new RuntimeException("findAll failed: " + e.getMessage(), e); } - return result; } // ---------- Maps a row from ResultSet into an entity ---------- diff --git a/src/main/java/org/automation/repositories/SensorRepository.java b/src/main/java/org/automation/repositories/SensorRepository.java new file mode 100644 index 0000000..5776f4d --- /dev/null +++ b/src/main/java/org/automation/repositories/SensorRepository.java @@ -0,0 +1,157 @@ +package org.automation.repositories; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.automation.database.DatabaseManager; +import org.automation.entities.Sensor; +import org.automation.entities.TemperatureSensor; +import org.automation.entities.WeightSensor; + +public class SensorRepository extends Repository { + + public SensorRepository(DatabaseManager db) { + super("Sensor", db); + } + + public boolean ensureTable() { + boolean created = db.executeDDL(createTableQuery()); + if (created) System.out.println("Sensor table ensured/created."); + return created; + } + + public boolean save(Sensor sensor) { + if (sensor == null) return false; + + boolean exists = findOne("id = ?", new Object[]{sensor.getSensorId()}) != null; + + if (sensor instanceof TemperatureSensor t) { + return exists ? updateTemperature(t) : insertTemperature(t); + } else if (sensor instanceof WeightSensor w) { + return exists ? updateWeight(w) : insertWeight(w); + } else { + return exists ? updateBase(sensor) : insertBase(sensor); + } + } + + /* ---------------- INSERT ---------------- */ + + private boolean insertTemperature(TemperatureSensor t) { + return insert( + new String[]{"type", "location", "status", "startThreshold", "tolerance", "targetTemperature", "temperatureUnit"}, + new Object[]{t.getSensorType(), t.getLocation(), t.getStatus(), t.getStartThreshold(), t.getTemperatureTolerance(), t.getTargetTemperature(), t.getTemperatureUnit()} + ); + } + + private boolean insertWeight(WeightSensor w) { + return insert( + new String[]{"type", "location", "status", "initialWeight", "capacity", "weightUnit"}, + new Object[]{w.getSensorType(), w.getLocation(), w.getStatus(), w.getCurrentWeight(), w.getMachineCapacity(), w.getWeightUnit()} + ); + } + + private boolean insertBase(Sensor s) { + return insert( + new String[]{"type", "location", "status"}, + new Object[]{s.getSensorType(), s.getLocation(), s.getStatus()} + ); + } + + /* ---------------- UPDATE ---------------- */ + + private boolean updateTemperature(TemperatureSensor t) { + return update( + "type = ?, location = ?, status = ?, startThreshold = ?, tolerance = ?, targetTemperature = ?, temperatureUnit = ?", + "id = ?", + new Object[]{t.getSensorType(), t.getLocation(), t.getStatus(), t.getStartThreshold(), t.getTemperatureTolerance(), t.getTargetTemperature(), t.getTemperatureUnit(), t.getSensorId()} + ); + } + + private boolean updateWeight(WeightSensor w) { + return update( + "type = ?, location = ?, status = ?, initialWeight = ?, capacity = ?, weightUnit = ?", + "id = ?", + new Object[]{w.getSensorType(), w.getLocation(), w.getStatus(), w.getCurrentWeight(), w.getMachineCapacity(), w.getWeightUnit(), w.getSensorId()} + ); + } + + private boolean updateBase(Sensor s) { + return update( + "type = ?, location = ?, status = ?", + "id = ?", + new Object[]{s.getSensorType(), s.getLocation(), s.getStatus(), s.getSensorId()} + ); + } + + public boolean deleteById(int id) { + return delete("id = ?", new Object[]{id}); + } + + /* ---------------- ROW MAPPING ---------------- */ + + @Override + public Sensor mapRow(ResultSet rs) throws SQLException { + int sensorId = rs.getInt("id"); + String type = safeGetString(rs, "type", ""); + String location = safeGetString(rs, "location", "Unknown"); + String status = safeGetString(rs, "status", "inactive"); + + return switch (type.toLowerCase()) { + case "temperature" -> new TemperatureSensor( + sensorId, type, location, status, + safeGetDouble(rs, "startThreshold", 0), + safeGetDouble(rs, "tolerance", 1), + safeGetDouble(rs, "targetTemperature", 25), + safeGetString(rs, "temperatureUnit", "°C") + ); + case "weight" -> new WeightSensor( + sensorId, type, location, status, + safeGetDouble(rs, "initialWeight", 0), + safeGetDouble(rs, "capacity", 100), + safeGetString(rs, "weightUnit", "kg") + ); + default -> throw new IllegalStateException("Unknown sensor type: " + type); + }; + } + + /* ---------------- SCHEMA ---------------- */ + + @Override + public String createTableQuery() { + return """ + CREATE TABLE IF NOT EXISTS Sensor ( + id INTEGER PRIMARY KEY, + type TEXT NOT NULL, + location TEXT, + status TEXT DEFAULT 'inactive', + startThreshold REAL, + tolerance REAL, + targetTemperature REAL, + temperatureUnit TEXT, + initialWeight REAL, + capacity REAL, + weightUnit TEXT + ); + """; + } + + /* ---------------- HELPERS ---------------- */ + + private String safeGetString(ResultSet rs, String column, String def) { + try { + String val = rs.getString(column); + return val != null ? val : def; + } catch (SQLException e) { + return def; + } + } + + private double safeGetDouble(ResultSet rs, String column, double def) { + try { + double val = rs.getDouble(column); + return rs.wasNull() ? def : val; + } catch (SQLException e) { + return def; + } + } +} diff --git a/src/main/java/org/Automation/repositories/WorkerRepository.java b/src/main/java/org/automation/repositories/WorkerRepository.java similarity index 89% rename from src/main/java/org/Automation/repositories/WorkerRepository.java rename to src/main/java/org/automation/repositories/WorkerRepository.java index 3c73d5a..5dfa9c8 100644 --- a/src/main/java/org/Automation/repositories/WorkerRepository.java +++ b/src/main/java/org/automation/repositories/WorkerRepository.java @@ -1,16 +1,15 @@ -package org.Automation.repositories; +package org.automation.repositories; import java.sql.ResultSet; import java.sql.SQLException; -import org.Automation.DatabaseManager; -import org.Automation.entities.Worker; +import org.automation.database.DatabaseManager; +import org.automation.entities.Worker; public class WorkerRepository extends Repository { public WorkerRepository(DatabaseManager db) { super("Worker", db); } - @Override public Worker mapRow(ResultSet rs) throws SQLException { diff --git a/src/main/java/org/automation/ui/ConsoleApp.java b/src/main/java/org/automation/ui/ConsoleApp.java new file mode 100644 index 0000000..313b460 --- /dev/null +++ b/src/main/java/org/automation/ui/ConsoleApp.java @@ -0,0 +1,343 @@ +// package org.automation.ui; + +// import org.automation.engine.SimulationEngine; +// import org.automation.controllers.WorkflowController; +// import org.automation.controllers.SensorManager; +// import org.automation.entities.Sensor; +// import org.automation.entities.TemperatureSensor; +// import org.automation.entities.WeightSensor; +// import org.automation.utils.Logger; + +// import java.util.List; +// import java.util.Scanner; + +// public class ConsoleApp extends ConsoleUI { +// //Instance Variables +// private SimulationEngine simulationEngine; +// private WorkflowController controller; +// private SensorManager sensorManager; +// private Logger logger; +// private Scanner scanner; +// private boolean running; + +// public ConsoleApp(){ +// simulationEngine = new SimulationEngine(); +// sensorManager = new SensorManager(); +// logger = new Logger(); +// scanner = new Scanner(System.in); +// running = false; +// } + +// //Instance Methods +// public void start() { +// running = true; +// printWelcomeMessage(); +// runMainMenu(); +// } + +// public void runMainMenu() { +// while (running) { +// printMainMenu(); +// String input = scanner.nextLine().trim(); +// handleUserInput(input); +// } +// } + +// private void printMainMenu() { +// System.out.println("\n╔═══════════════════════════════════════════════════════════════╗"); +// System.out.println("ā•‘ FACTORY AUTOMATION - SENSOR MANAGEMENT SYSTEM ā•‘"); +// System.out.println("╠═══════════════════════════════════════════════════════════════╣"); +// System.out.println("ā•‘ [1] Add New Sensor ā•‘"); +// System.out.println("ā•‘ [2] Remove Sensor ā•‘"); +// System.out.println("ā•‘ [3] List All Sensors ā•‘"); +// System.out.println("ā•‘ [4] View Sensor Details ā•‘"); +// System.out.println("ā•‘ [5] Start Sensor ā•‘"); +// System.out.println("ā•‘ [6] Stop Sensor ā•‘"); +// System.out.println("ā•‘ [7] Start All Sensors ā•‘"); +// System.out.println("ā•‘ [8] Stop All Sensors ā•‘"); +// System.out.println("ā•‘ [9] Enable Automatic Mode (Single Sensor) ā•‘"); +// System.out.println("ā•‘ [10] Disable Automatic Mode (Single Sensor) ā•‘"); +// System.out.println("ā•‘ [11] Enable Control Mode (Single Sensor) ā•‘"); +// System.out.println("ā•‘ [12] Disable Control Mode (Single Sensor) ā•‘"); +// System.out.println("ā•‘ [13] Enable Automatic Mode (All Sensors) ā•‘"); +// System.out.println("ā•‘ [14] Disable Automatic Mode (All Sensors) ā•‘"); +// System.out.println("ā•‘ [0] Exit ā•‘"); +// System.out.println("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•"); +// System.out.print("Select an option: "); +// } + +// public void handleUserInput(String input) { +// switch (input) { +// case "1" -> addSensorMenu(); +// case "2" -> removeSensorMenu(); +// case "3" -> listAllSensors(); +// case "4" -> viewSensorDetails(); +// case "5" -> startSensorMenu(); +// case "6" -> stopSensorMenu(); +// case "7" -> startAllSensors(); +// case "8" -> stopAllSensors(); +// case "9" -> enableAutomaticModeMenu(); +// case "10" -> disableAutomaticModeMenu(); +// case "11" -> enableControlModeMenu(); +// case "12" -> disableControlModeMenu(); +// case "13" -> enableAutomaticModeAll(); +// case "14" -> disableAutomaticModeAll(); +// case "0" -> exit(); +// default -> System.out.println("āŒ Invalid option. Please try again."); +// } +// } + +// // =========================== +// // Menu Options Implementation +// // =========================== + +// private void addSensorMenu() { +// System.out.println("\n--- Add New Sensor ---"); +// System.out.println("Select sensor type:"); +// System.out.println("[1] Temperature Sensor"); +// System.out.println("[2] Weight Sensor"); +// System.out.print("Choice: "); +// String choice = scanner.nextLine().trim(); + +// try { +// System.out.print("Enter Sensor ID: "); +// int id = Integer.parseInt(scanner.nextLine().trim()); + +// System.out.print("Enter Location: "); +// String location = scanner.nextLine().trim(); + +// Sensor sensor = null; + +// if (choice.equals("1")) { +// // Temperature Sensor +// System.out.print("Enter Start Threshold: "); +// double startThreshold = Double.parseDouble(scanner.nextLine().trim()); + +// System.out.print("Enter Tolerance: "); +// double tolerance = Double.parseDouble(scanner.nextLine().trim()); + +// System.out.print("Enter Target Temperature: "); +// double targetTemp = Double.parseDouble(scanner.nextLine().trim()); + +// System.out.print("Enter Temperature Unit (°C/°F): "); +// String unit = scanner.nextLine().trim(); + +// sensor = new TemperatureSensor(id, "Temperature", location, "inactive", +// startThreshold, tolerance, targetTemp, unit); +// } else if (choice.equals("2")) { +// // Weight Sensor +// System.out.print("Enter Initial Weight: "); +// double initialWeight = Double.parseDouble(scanner.nextLine().trim()); + +// System.out.print("Enter Capacity: "); +// double capacity = Double.parseDouble(scanner.nextLine().trim()); + +// System.out.print("Enter Weight Unit (kg/lb): "); +// String unit = scanner.nextLine().trim(); + +// sensor = new WeightSensor(id, "Weight", location, "inactive", +// initialWeight, capacity, unit); +// } else { +// System.out.println("āŒ Invalid sensor type."); +// return; +// } + +// sensorManager.addSensor(sensor); +// System.out.println("āœ… Sensor added successfully and saved to database!"); + +// } catch (NumberFormatException e) { +// System.out.println("āŒ Invalid input. Please enter valid numbers."); +// } catch (Exception e) { +// System.out.println("āŒ Error adding sensor: " + e.getMessage()); +// } +// } + +// private void removeSensorMenu() { +// System.out.println("\n--- Remove Sensor ---"); +// System.out.print("Enter Sensor ID to remove: "); +// try { +// int id = Integer.parseInt(scanner.nextLine().trim()); +// if (sensorManager.removeSensor(id)) { +// System.out.println("āœ… Sensor removed successfully from database!"); +// } else { +// System.out.println("āŒ Sensor not found."); +// } +// } catch (NumberFormatException e) { +// System.out.println("āŒ Invalid ID format."); +// } +// } + +// private void listAllSensors() { +// System.out.println("\n╔═════════════════════════════════════════════════════════╗"); +// System.out.println("ā•‘ ALL SENSORS LIST ā•‘"); +// System.out.println("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•"); + +// List sensorInfo = sensorManager.listSensorInfo(); +// if (sensorInfo.isEmpty()) { +// System.out.println("šŸ“­ No sensors found in the system."); +// } else { +// for (int i = 0; i < sensorInfo.size(); i++) { +// System.out.println((i + 1) + ". " + sensorInfo.get(i)); +// } +// } +// } + +// private void viewSensorDetails() { +// System.out.println("\n--- View Sensor Details ---"); +// System.out.print("Enter Sensor ID: "); +// try { +// int id = Integer.parseInt(scanner.nextLine().trim()); +// String info = sensorManager.getSensorInfo(id); +// if (info != null) { +// System.out.println("\nšŸ“Š Sensor Details:"); +// System.out.println(info); +// } else { +// System.out.println("āŒ Sensor not found."); +// } +// } catch (NumberFormatException e) { +// System.out.println("āŒ Invalid ID format."); +// } +// } + +// private void startSensorMenu() { +// System.out.println("\n--- Start Sensor ---"); +// System.out.print("Enter Sensor ID: "); +// try { +// int id = Integer.parseInt(scanner.nextLine().trim()); +// if (sensorManager.startSensor(id)) { +// System.out.println("āœ… Sensor started successfully!"); +// } else { +// System.out.println("āŒ Failed to start sensor. It may already be running or not exist."); +// } +// } catch (NumberFormatException e) { +// System.out.println("āŒ Invalid ID format."); +// } +// } + +// private void stopSensorMenu() { +// System.out.println("\n--- Stop Sensor ---"); +// System.out.print("Enter Sensor ID: "); +// try { +// int id = Integer.parseInt(scanner.nextLine().trim()); +// if (sensorManager.stopSensor(id)) { +// System.out.println("āœ… Sensor stopped successfully!"); +// } else { +// System.out.println("āŒ Failed to stop sensor. It may already be stopped or not exist."); +// } +// } catch (NumberFormatException e) { +// System.out.println("āŒ Invalid ID format."); +// } +// } + +// private void startAllSensors() { +// System.out.println("\nāš™ļø Starting all sensors..."); +// sensorManager.startAll(); +// System.out.println("āœ… All sensors have been started!"); +// } + +// private void stopAllSensors() { +// System.out.println("\nāš™ļø Stopping all sensors..."); +// sensorManager.stopAll(); +// System.out.println("āœ… All sensors have been stopped!"); +// } + +// private void enableAutomaticModeMenu() { +// System.out.println("\n--- Enable Automatic Mode ---"); +// System.out.print("Enter Sensor ID: "); +// try { +// int id = Integer.parseInt(scanner.nextLine().trim()); +// if (sensorManager.setSensorAutomaticMode(id, true)) { +// System.out.println("āœ… Automatic mode enabled for sensor!"); +// } else { +// System.out.println("āŒ Sensor not found."); +// } +// } catch (NumberFormatException e) { +// System.out.println("āŒ Invalid ID format."); +// } +// } + +// private void disableAutomaticModeMenu() { +// System.out.println("\n--- Disable Automatic Mode ---"); +// System.out.print("Enter Sensor ID: "); +// try { +// int id = Integer.parseInt(scanner.nextLine().trim()); +// if (sensorManager.setSensorAutomaticMode(id, false)) { +// System.out.println("āœ… Automatic mode disabled for sensor!"); +// } else { +// System.out.println("āŒ Sensor not found."); +// } +// } catch (NumberFormatException e) { +// System.out.println("āŒ Invalid ID format."); +// } +// } + +// private void enableControlModeMenu() { +// System.out.println("\n--- Enable Control Mode ---"); +// System.out.print("Enter Sensor ID: "); +// try { +// int id = Integer.parseInt(scanner.nextLine().trim()); +// System.out.print("Enter Target Value: "); +// double target = Double.parseDouble(scanner.nextLine().trim()); +// System.out.print("Enter Tolerance: "); +// double tolerance = Double.parseDouble(scanner.nextLine().trim()); + +// if (sensorManager.setSensorControl(id, true, target, tolerance)) { +// System.out.println("āœ… Control mode enabled for sensor!"); +// } else { +// System.out.println("āŒ Sensor not found."); +// } +// } catch (NumberFormatException e) { +// System.out.println("āŒ Invalid input format."); +// } +// } + +// private void disableControlModeMenu() { +// System.out.println("\n--- Disable Control Mode ---"); +// System.out.print("Enter Sensor ID: "); +// try { +// int id = Integer.parseInt(scanner.nextLine().trim()); +// if (sensorManager.setSensorControl(id, false, 0, 0)) { +// System.out.println("āœ… Control mode disabled for sensor!"); +// } else { +// System.out.println("āŒ Sensor not found."); +// } +// } catch (NumberFormatException e) { +// System.out.println("āŒ Invalid ID format."); +// } +// } + +// private void enableAutomaticModeAll() { +// System.out.println("\nāš™ļø Enabling automatic mode for all sensors..."); +// sensorManager.setAllAutomaticMode(true); +// System.out.println("āœ… Automatic mode enabled for all sensors!"); +// } + +// private void disableAutomaticModeAll() { +// System.out.println("\nāš™ļø Disabling automatic mode for all sensors..."); +// sensorManager.setAllAutomaticMode(false); +// System.out.println("āœ… Automatic mode disabled for all sensors!"); +// } + +// public void printWelcomeMessage() { +// System.out.println("\n"); +// System.out.println("╔════════════════════════════════════════════════════════════════════╗"); +// System.out.println("ā•‘ ā•‘"); +// System.out.println("ā•‘ šŸ­ FACTORY AUTOMATION - SENSOR MANAGEMENT SYSTEM šŸ­ ā•‘"); +// System.out.println("ā•‘ ā•‘"); +// System.out.println("ā•‘ Integrated Database-Driven Sensor Control Interface ā•‘"); +// System.out.println("ā•‘ ā•‘"); +// System.out.println("ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•"); +// System.out.println("\n✨ Welcome! All sensors are automatically loaded from the database."); +// System.out.println("šŸ’¾ All changes are persisted to the database in real-time.\n"); +// } + +// public void exit() { +// System.out.println("\nšŸ›‘ Shutting down system..."); +// System.out.println("ā³ Stopping all sensors..."); +// sensorManager.shutdown(5); +// System.out.println("šŸ’¾ Database disconnected."); +// System.out.println("āœ… System shutdown complete. Goodbye! šŸ‘‹\n"); +// scanner.close(); +// running = false; +// } +// } diff --git a/src/main/java/org/Automation/ConsoleUI/ConsoleUI.java b/src/main/java/org/automation/ui/ConsoleUI.java similarity index 92% rename from src/main/java/org/Automation/ConsoleUI/ConsoleUI.java rename to src/main/java/org/automation/ui/ConsoleUI.java index 7af809e..0028227 100644 --- a/src/main/java/org/Automation/ConsoleUI/ConsoleUI.java +++ b/src/main/java/org/automation/ui/ConsoleUI.java @@ -1,11 +1,10 @@ -package ConsoleUI; +package org.automation.ui; import java.util.*; public class ConsoleUI { // Low-Level Menu print lines public void printHeader(String title) { } - public void printMenu(ArrayList options) { }