diff --git a/.gitignore b/.gitignore
index f69985ef1f..d992eab43c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,10 +8,15 @@
/build/
src/main/resources/docs/
+
# MacOS custom attributes files created by Finder
.DS_Store
*.iml
bin/
/text-ui-test/ACTUAL.txt
-text-ui-test/EXPECTED-UNIX.TXT
+
+# Data file
+/data/SmartHomeBot.txt
+/log/SmartHomeBotLog.txt
+/log/SmartHomeBotLog.txt.lck
diff --git a/README.md b/README.md
index 698b938529..2f8e104f31 100644
--- a/README.md
+++ b/README.md
@@ -1,64 +1,5 @@
-# Duke project template
+#
SmartHomeBot
-This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.
+SmartHomeBot is a desktop application that consolidates all home appliances control into a centralized system via a Command Line Interface (CLI). Users can switch on or off appliances using this application and record electricity usage; having a clearer picture of their electrical usage patterns. SmartHomeBot has an auto-save feature that will automatically save all the appliances' data and export it to a text file. Upon the start of the [application](https://github.com/AY2021S1-CS2113-T14-1/tp/releases/latest), it will import the data from the text file and loads the appliances' data back.
-## Setting up in Intellij
-
-Prerequisites: JDK 11 (use the exact version), update Intellij to the most recent version.
-
-1. **Configure Intellij for JDK 11**, as described [here](https://se-education.org/guides/tutorials/intellijJdk.html).
-1. **Import the project _as a Gradle project_**, as described [here](https://se-education.org/guides/tutorials/intellijImportGradleProject.html).
-1. **Verify the set up**: After the importing is complete, locate the `src/main/java/seedu/duke/Duke.java` file, right-click it, and choose `Run Duke.main()`. If the setup is correct, you should see something like the below:
- ```
- > Task :compileJava
- > Task :processResources NO-SOURCE
- > Task :classes
-
- > Task :Duke.main()
- Hello from
- ____ _
- | _ \ _ _| | _____
- | | | | | | | |/ / _ \
- | |_| | |_| | < __/
- |____/ \__,_|_|\_\___|
-
- What is your name?
- ```
- Type some word and press enter to let the execution proceed to the end.
-
-## Build automation using Gradle
-
-* This project uses Gradle for build automation and dependency management. It includes a basic build script as well (i.e. the `build.gradle` file).
-* If you are new to Gradle, refer to the [Gradle Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/gradle.html).
-
-## Testing
-
-### I/O redirection tests
-
-* To run _I/O redirection_ tests (aka _Text UI tests_), navigate to the `text-ui-test` and run the `runtest(.bat/.sh)` script.
-
-### JUnit tests
-
-* A skeleton JUnit test (`src/test/java/seedu/duke/DukeTest.java`) is provided with this project template.
-* If you are new to JUnit, refer to the [JUnit Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/junit.html).
-
-## Checkstyle
-
-* A sample CheckStyle rule configuration is provided in this project.
-* If you are new to Checkstyle, refer to the [Checkstyle Tutorial at se-education.org/guides](https://se-education.org/guides/tutorials/checkstyle.html).
-
-## CI using GitHub Actions
-
-The project uses [GitHub actions](https://github.com/features/actions) for CI. When you push a commit to this repo or PR against it, GitHub actions will run automatically to build and verify the code as updated by the commit/PR.
-
-## Documentation
-
-`/docs` folder contains a skeleton version of the project documentation.
-
-Steps for publishing documentation to the public:
-1. If you are using this project template for an individual project, go your fork on GitHub.
- If you are using this project template for a team project, go to the team fork on GitHub.
-1. Click on the `settings` tab.
-1. Scroll down to the `GitHub Pages` section.
-1. Set the `source` as `master branch /docs folder`.
-1. Optionally, use the `choose a theme` button to choose a theme for your documentation.
+[
](https://ay2021s1-cs2113-t14-1.github.io/tp/)
diff --git a/build.gradle b/build.gradle
index b0c5528fb5..69886b17d7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -12,6 +12,7 @@ repositories {
dependencies {
testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0'
testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0'
+ compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.11'
}
test {
@@ -19,7 +20,6 @@ test {
testLogging {
events "passed", "skipped", "failed"
-
showExceptions true
exceptionFormat "full"
showCauses true
@@ -29,11 +29,11 @@ test {
}
application {
- mainClassName = "seedu.duke.Duke"
+ mainClassName = "seedu.smarthomebot.Main"
}
shadowJar {
- archiveBaseName = "duke"
+ archiveBaseName = "SmartHomeBot"
archiveClassifier = null
}
@@ -43,4 +43,5 @@ checkstyle {
run{
standardInput = System.in
+ enableAssertions = true
}
diff --git a/docs/AboutUs.md b/docs/AboutUs.md
index 0f072953ea..403dadc96a 100644
--- a/docs/AboutUs.md
+++ b/docs/AboutUs.md
@@ -1,9 +1,11 @@
# About us
+* [RepoSense](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=AY2021S1-CS2113-T14-1%2Ftp%5Bmaster%5D&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=functional-code~test-code~other~docs)
+
Display | Name | Github Profile | Portfolio
--------|:----:|:--------------:|:---------:
- | John Doe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Don Joe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Ron John | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | John Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
- | Don Roe | [Github](https://github.com/) | [Portfolio](docs/team/johndoe.md)
+
| Ang Cheng Jun | [Github](https://github.com/Ang-Cheng-Jun) | [Portfolio](https://ay2021s1-cs2113-t14-1.github.io/tp/team/ang-cheng-jun.html)
+
| Leon Low | [Github](https://github.com/leonlowzd) | [Portfolio](team/leonlowzd.md)
+
| Ong Zong Xian | [Github](https://github.com/zongxian-ctrl) | [Portfolio](team/zongxian-ctrl.md)
+
| Tan Lee Wei | [Github](https://github.com/TanLeeWei) | [Portfolio](team/tanleewei.md)
+
| Yang Fan | [Github](https://github.com/fanceso) | [Portfolio](team/fanceso.md)
diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index 0ec3db103d..75d1325cd8 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -1,34 +1,661 @@
-# Developer Guide
+#
Developer Guide
-## Design & implementation
+## Table of Contents
+* [Setting up](#setting-up)
+ * [Prerequisites](#prerequisites)
+ * [Get Started](#get-started)
+* [Design](#design)
+ * [Architecture](#architecture)
+ * [UI Component](#ui-component)
+ * [Logic Component](#logic-component)
+* [Implementation](#implementation)
+ * [Detailed Data Component](#detailed-data-component)
+ * [Command Component](#command-component)
+ * [Storage Component](#storage-component)
+ * [Parser Component](#parser-component)
+* [Appendix A: Product scope](#appendix-a-product-scope)
+ * [Target user profile](#target-user-profile)
+ * [Value proposition](#value-proposition)
+* [Appendix B: User Stories](#appendix-b-user-stories)
+* [Appendix C: Non Functional Requirements](#appendix-c-non-functional-requirements)
+* [Appendix D: Glossary](#appendix-d-glossary)
+* [Appendix E: Instructions for manual testing](#appendix-e-instructions-for-manual-testing)
-{Describe the design and implementation of the product. Use UML diagrams and short code snippets where applicable.}
+
+## **Introduction**
+SmartHomeBot is a desktop application tailored for users who are comfortable using a Command Line Interface (CLI), it
+allows users to control their smart devices at home and record all appliance power usage.
+
+## **Setting up**
+
+### Prerequisites
+
++ *JDK `11`* or above
++ Permission rights to create a file and folder in machine
++ At least 10Mb of free space on disk
+
+### **Get Started**
+
+Fork this repo and clone it into your computer.
+
+Intellij IDEA User (highly recommended):
+1. Configure the JDK to JDK 11.
+2. Make sure you have enabled Grade extension, if disable please re-enable it back by going to `File`>`Settings`>`Plugins`.
+3. Import the project as a Gradle project by selecting *build.gradle*
+4. Verify the setup:
+ Run the seedu.smarthomebot.Main and try a few commands.
+ Run the Tests to ensure they all pass.
+- - -
+
+## Design
+### Project overview
+
+SmartHomeBot is built using java. SmartHomeBot can be built on any platform including Windows, MAC-OS and Linux. When
+running locally on these systems, SmartHomeBot has the ability to keep track of all the appliances registered into the
+program and control their operating systems through the program. SmartHomeBot also has a storage file that allows the
+saving and loading of data. This allows the SmartHomeBot to keep the information of the appliance and its parameters
+even after the program is turned off.
+
+### Architecture
+
+
+
+The *Architecture Diagram* shown above explains the high-level design of SmortHomeBot Application. Given below is a brief overview of each component.
+
+`Main` is responsible for initializing other components in correct sequence, and connects them up with each other.
+
+`Commons` represents a collection of classes used by multiple components.
+
+The rest of the App consists of four components.
+* `Ui`: The user interface where user can enter instructions and view output.
+* `Logic` The command executor which consists of,
+ * `Paser`: Extract the keyword from user input
+ * `Commands`: Execute the specific command according to the keyword
+* `Data` Holds the data in-app-memory while the program is running.
+* `Storage` Reads and writes data from and to a text file.
+
+How the architecture components interact with each other
+
+The *Sequence Diagram* below shows how the components interact with each other for the scenario where the user issues the command `create br1`.
+
+
+
+The sections below give more details of each component.
+
+### Ui Component
+
+The class diagram of `TextUi` is shown below together with `Main`:
+
+
+
+The sequence diagram of `TextUi` is shown below:
+
+
+
+**API** : [TextUI.java](https://github.com/AY2021S1-CS2113-T14-1/tp/blob/master/src/main/java/seedu/smarthomebot/ui/TextUi.java)
+
+The UI component which consists of TextUi,
+* Prompt commands from the user.
+* Execute user commands using the *Logic component*.
+* Displays information based on changes to *Data*.
+* Prints the SmartHomeBot appliance in a well-formatted form.
+
+### Logic Component
+
+The class diagram of `Logic Component` is shown below together with an example:
+
+
+
+**API** : [Logic](https://github.com/AY2021S1-CS2113-T14-1/tp/tree/master/src/main/java/seedu/smarthomebot/logic)
+
+1. Logic uses the **Parser class** to parse the user command.
+2. This results in a **Command object**.
+3. The command execution can affect the *Data* (e.g. adding a new location “br1” into its **LocationList**).
+4. The result of the command execution is encapsulated as a **CommandResult object** which is passed back to the Ui.
+5. In addition, the **CommandResult object** can also instruct the *Ui* to perform certain actions, such as displaying help to the user.
+6. Shown above is the Sequence Diagram for interactions within the *Logic component* for the when user enter "create br1" and how the API call.
+
+### Data Component
+
+The class diagram of `Data Component` is shown below:
+
+
+
+**API** : [Data](https://github.com/AY2021S1-CS2113-T14-1/tp/blob/master/src/main/java/seedu/smarthomebot/data)
+
+
+The *Data Component Diagram* shown above explains the high-level design of the Data which consists of `LocationList` which stores all the locations created by user, `ApplianceList` stores all the appliance which can be created from one of the types - `Fan`, `AirConditioner`,`Light`, or `SmartPlug`. Each appliance creates `Power` which used for computation of power usage.
+
+---
+
+
+## Implementation
+
+### Detailed Data Component
+
+The *Detailed Data Component* shown above explains the summarised data of SmartHomeBot. The four appliances classes are extended
+from the abstract appliance class.
+
+
+
+To create an Appliance, we pass the name, location, wattage, power and the entire locationList. We first check from the
+locationList if the name of the appliance is inside the locationList, and the location exists within the locationList.
+If all these conditions are met, the Appliance will be created. It will be appended into the ApplianceList with the
+`addAppliance()` method.
+
+The Power class is responsible for computing the appliance’s power consumption.
+
+The public methods in the Appliances accessible via the ApplianceList are used to manipulate the appliances such as
+turning `ON` and `OFF`. From the appliance class, the program will be able to retrieving the name, location, statuses of
+the appliances.
+
+### Parser Component
+
+This section will describe how the Parser feature is implemented as well as the design consideration and rational.
+
+The main purpose of the Parser Class is to interpret the user inputs so that the correct command can be executed.
+
+Sequence Diagram when `parseCommand(userCommandText)` is initially called.
+
+
+The `userCommandText` is first capture by TextUi and then passed into parseCommand(userCommandText) method in Parser.
+As shown in the Sequence Diagram above, different userCommandText will result in different paths being taken.
+
+Below is the list of commands available.
+* Help: `help`
+* Create a location: `create`
+* Remove a location: `remove`
+* Add an appliance: `add`
+* Delete an appliance: `delete`
+* Switch ON an appliance: `on`
+* Switch OFF an appliance: `off`
+* Listing appliance/location: `list`
+* Displaying usage of appliance: `usage`
+* Resetting usage of appliance: `p_reset`
+* Exiting the application: `exit`
+
+#### Sequence Diagram for `create`
+
+
+
+When the user enters the `create` command, the `prepareCreateCommand(argument)` is called.
+It will reject the input provided by the user if the `argument` is empty or contain characters such as `/` or `|` or if the argument contains `spaces` in between.
+If the argument is not rejected, it will return and construct a new CreateCommand object with argument as the parameter to be created.
+
+
+#### Sequence Diagram for `remove`
+
+
+
+When the user enters the `remove` command, the `prepareRemoveCommand(argument)` is called.
+It will reject the input provided by the user if the `argument` is empty.
+If the argument is not rejected, it will return a new RemoveCommand object with argument as the parameter to be used to remove a location in the LocationList.
+
+
+#### Sequence Diagram for `add`
+
+
+
+When the user enters the `add` command, the `prepareAddCommand(argument)` is called.
+It will reject the input provided by the user if the l/[LOCATION_NAME] w/[WATTAGE] t/[APPLIANCE_TYPE] is not in this particular order.
+If the `argument` entered are in the right order, it will split and reject if any of the parameters entered by the user is empty.
+Next, it will check to ensure that the [APPLIANCE_NAME] parameter does not contain characters such as `/` or `|` or `spaces` in between and [WATTAGE] is a valid int number from 1-9999.
+If all these conditions are fulfilled, it will return and construct a new AddCommand object with name, location, wattage and type as the parameters to be used to add an appliance to the ApplianceList.
+
+#### Sequence Diagram for `delete`
+
+
+
+When the user enters the `delete` command, the `prepareDeleteCommand(argument)` is called.
+It will reject the input provided by the user if the `argument` is empty. If the argument is not rejected, it will return a new DeleteCommand object with arguments as the parameter to be used to delete an appliance from the ApplianceList.
+
+#### Sequence Diagram for `on`
+
+
+
+When the user enters the ‘on’ command, the
+`prepareOnCommand(argument)` is called. It will check if the user inputs a p/ for the argument.
+
+The name can either be a Location, or an Appliance name. If there is a parameter, the program will then check if the command is an integer,
+if it isn’t an error is thrown. If there is no parameter inputted, an empty string. Finally, a new OnCommand(name,parameter) will be returned.
+
+#### Sequence Diagram for `off`
+
+
+
+When the user enters the ‘on’ command, the
+`prepareOffCommand(argument)` is called. The name can be an Appliance or a Location. A new OffCommand is created: OffCommand(name) and returned.
+
+#### Sequence Diagram for `list`
+
+
+When the user enters the `list` command, the
+`prepareListCommand(argument)` is called. It will check if the argument contains “appliance’ or ‘location”.
+1. If the argument contains “location”, a new `ListCommand(LOCATION_TYPE, ““)` will be returned.
+
+2. If the argument contains “appliance”, it will check if it contains a “l/” parameter. If it exist, it
+means there is a filteredLocation, thus a new `ListCommand(APPLIANCE_TYPE, filteredLocation)` will be returned.
+Else, a new `ListCommand(APPLIANCE_TYPE, ““)` will be returned.
+
+3. Any argument that do not contain “location” and “appliance” or contains “appliance” with a wrong
+format will return a `InvalidCommand` class with their respective error messages.
+
+#### Sequence Diagram for `commandword`
+
+
+
+`commandword` refers to the following commands `help`, `usage`, `p_reset`, `exit`.
+As these 4 commands does not require any additional parsing. The sequence diagram referred above will return their
+respective CommandObject to execute the command.
+
+
+#### Sequence Diagram for `default`
+
+
+
+When input provided by the User is not any of the commands available, it will return a new `InvalidCommand(MESSAGE_INVALID_COMMAND_FORMAT)`
+that will be executed to inform the user that it is a ‘Invalid Command Format’.
+
+### Command Component
+#### Help Command
+To see the help usage for the commands in SmartHomeBot, the `HelpCommand` class is used. This class' object is
+first created by the `Parser` class, where it is then returned to the `Main` class to have its `execute()`
+function called. When the `Main` class calls the `execute()` function, the `HelpCommand`
+will then return a new `CommandResult` class (which stores the Help message)
+
+The sequence diagram for `HelpCommand` is shown below:
+
+
+
+#### Create Command
+To create a new location, the `CreateCommand` class is used.
+This class object is first created by the `Parser` class, where it is then returned to the `Main` class to have its `execute()` function called.
+The userEnteredLocation which was the argument parsed by the `Parser` will be used in LocationList’s addLocation(userEnteredLocation) function to create the location in the LocationList.
+After the location is created, it will then return a new CommandResult class to indicate the result of this process.
+
+If the userEnteredLocation already exists in the LocationList, it will return a new CommandResult class to indicate that the location already exists and could not be created.
+Likewise, if the userEnterLocation already exists in the ApplianceList, it will return a new CommandResult class to indicate that as such.
+This is to prevent duplicates name in both the ApplianceList and LocationList.
+
+The sequence diagram for `CreateCommand` is shown below:
+
+
+
+
+#### Remove Command
+To remove a location, the `RemoveCommand` class is used. The class object is first created by the `Parser` class, where
+it is then returned to the `Main` class to have its `execute()` method called. The name of the location to be removed
+will be parsed into the `RemoveCommand` class. The `RemoveCommand` class will call the `removeLocation` method in
+`LocationList`, which will loop until the name of the location to be removed is found in the `LocationList`.
+
+Next, the `RemoveCommand` class will call the `deleteByLocation` method in `ApplianceList`, which will loop to look for all the appliance in the location to be removed and delete the appliance.
+If the name of the location to be removed is not found, the `RemoveCommand` will return the “Location does not exist.” message.
+
+The sequence diagram for `RemoveCommand` is shown below:
+
+
+
+
+#### Add Command
+
+To add a new appliance, the `AddCommand` class is used. This class object is first created by the `Parser` class, where
+it is then returned to the `Main` class to have its `execute()` method called. The name,location,wattage, and type of
+the appliance will be parsed into the AddCommand class. The `AddCommand` class will perform the `execute()` method to
+convert the appliance into static (`Fan`, `AirConditioner`, `Lights`, `SmartPlug`) depending on their type. Then the
+appliance will be added into the ApplianceList. The name of the appliance has to be unique.
+
+The sequence diagram for `AddCommand` is shown below:
+
+
+
+#### Delete Command
+
+To delete an appliance, the `DeleteCommand` class is used. This class object is first created by the `Parser` class
+where it is then returned to the `Main` class to have its `execute()` method called. The name of the appliance to be
+deleted will be parsed into the `DeleteCommand` class. The `DeleteCommand` class will call the deleteAppliance method
+in the `ApplianceList` class, which will loop until the name of the appliance to be deleted is found in the
+`ApplianceList` and remove the appliance from the `ApplianceList`. If the name of the appliance to be deleted is not
+found, the `DeleteCommand` will return “appliance does not exist” message.
+
+The sequence diagram for `DeleteCommand` is shown below:
+
+
+
+#### On Command
+
+The `OnCommand` shown below explains the Sequence Diagram of the OnCommand. When the Main class calls the execute() function there will be are 2 cases for on command to flow:
+1. `onByLocation`
+2. `onByAppliance`
+
+The sequence diagram for `OnCommand` is shown below:
+
+
+
+The program will determine if the user inputted: key is a name of an appliance, or a location.This is done by checking
+the key in the `LocationList`, if it exists, the program will deem it as `OnByLocation` vice versa.
+
+1. `onByLocation`
+The first condition checks if the user types in any parameter into the command, if so, the program will be unable to turn on
+the appliances in the location. This is done as not all parameters are accepted by every appliance, for example,
+`setTemperature` is only accepted for Air Conditioner. Thus, the parameter option is only opened to the `OnByAppliance` method.
+Then, `onByApplianceLoop` will be called to turn on all appliances in the location.
+
+2. `onByAppliance`
+The first condition checks the index of the tagged appliance in the applianceList. If the index is negative, this signifies
+that that key does not exist in the location or appliance list. Else, we will call the `onAppliance` method.
+
+
+#### Off Command
+
+When the Main class calls the `execute()` function there are 2 cases for off command:
+1. `offByLocation`
+2. `offByAppliance`
+
+The sequence diagram for `OffCommand` is shown below:
+
+
+
+The program will determine if the user inputted: key is a name of an appliance or a location. This is done by checking
+the key in the LocationList, if it exists, the program will deem it as `OffByLocation` vice versa.
+
+1. `offByLocation`
+This method will call offByApplianceLoop which turns off every appliance in that location.
+
+2. `offByAppliance`
+The first condition checks the index of the tagged appliance in the applianceList. If the index is negative, this
+signifies that that key does not exist in the location or appliance list. Else, we will call the `offAppliance` method.
+
+#### List Command
+
+To list appliances or locations, the `ListCommand` class is used. This class' object is first created by the `Parser` class,
+where it is then returned to the `Main` class to have its `execute()` function be called.When the Main class calls the `execute()`
+function, ListCommand will call upon the function “list appliance” or “list location” in `ListCommand` class to
+determine whether to list the appliances or location, then return a new `CommandResult` class (which stores the list)
+
+The sequence diagram for `ListCommand` is shown below:
+
+
+
+
+
+As depicted from the diagram, there are 2 cases for `ListCommand`:
+
+1) `listAppliance`
+This method checks for the user's key in a filteredLocation together with the “list appliance”. If there is no filteredLocation,
+it will just create a list of all the appliances in all the locations. Vice versa, if it exists a filteredLocation,it will
+just create a list of all the appliances in filteredLocation.
+
+2) `listLocation`
+This method creates a list of all the locations that stores in the locationList.
+
+#### Usage Command
+
+To find out the power consumption of each appliance and total power usage. This class object is first created by the `Parser` class, where it is then returned to the `Main` class to have its `execute()` method called.
+When the `Main` class calls the `execute()` function, `UsageCommand` will get the appliance’s details such as name, location, status and power usage as shown in the sequence diagram. Power consumption will be computed based on the appliance usage time with respect to the system time. If the appliance status is **on** it will get its time used with respect to the current system time. Thus, the power consumption will be calculated and displayed auto-formatted content to the user which returns a new `CommandResults` class.
+
+The sequence diagram of `UsageCommand` is shown below when user enters *usage*:
+
+
+
+#### Reset Command
+
+To reset the power consumption of each appliance and total power usage of SmartHomeBot back to zero. This class object is first created by the `Parser` class, where it is then returned to the `Main` class to have its `execute()`
+method called. When the `Main` class calls the `execute()` function, `ResetCommand` will then access the power class
+and reset the appliance power. A new `CommandResult` class will be returned to the main with a feedback message.
+
+The sequence diagram of `ResetCommand` is shown below when user enters *p_reset*:
+
+
+
+#### Invalid Command
+
+If users key in the wrong command, the `InvalidCommand` class is used.This class' object is
+first created by the `Parser` class, where it is then returned to the `Main` class to have its `execute()`
+function be called. When the `Main` class calls the `execute()` function, `InvalidCommand` will
+return a new `CommandResult` class (which stores the Invalid message)
+
+The sequence diagram for `InvalidCommand` is shown below:
+
+
+
+#### Exit Command
+To exit SmartHomeBot, the `ExitCommand` class is used. For this `ExitCommand` class. This class' object
+is first created by the `Parser` class, where it is then returned to the Main class to have its `execute()`
+function be called. When the `Main` class calls the `execute()` function, the `ExitCommand` will off all the
+appliance and ,then return a new `CommandResult` class (which stores the Exit message)
+
+The sequence diagram for `ExitCommand` is shown below:
+
+
+#### CommandResult Command
+The `CommandResult` class is used to store feedback to users and will interact with `UI` in the `Main`.
+
+### Storage Component
+
+#### Storage Module
+The Storage module manages the load and save operations of the SmartHomeBot. It consist of two different classes,
+the `ReadStorageFile` class, and the `WriteToFile` class. As of the name stated, the function of `WriteStorageFile` class
+is to store the data into a .txt file for future usage. The `ReadStorageFile` class is to load the previously stored data
+from the .txt file back into the SmartHomeBot when it start up.
+
+The class diagram for storage module is shown below:
+
+
+
+##### Process of writing data into Storage File
+After each command input by the user, SmartHomeBot will perform the `execute()` method in SaveStorageFile. This allows
+the program to continuously save the changes made by the user into the .txt file and prevent the lost of updates made
+by the user.
+
+Within the `execute()` method, the `createFile()` method will be performed to create a new .txt file if there is no .txt
+file exist. Then the `clearFile()` method will be performed to empty .txt file. After that all the data updated by the
+user will be written into the .txt file. This process will be carried out each time the user input a command. The first
+line in the .txt file will always be the LocationList and subsequent lines will be all the appliances, each occupying
+one line each. The appliances will be written together with their parameters in each line.
+
+The sequence diagram for `WriteStorageFile` is shown below:
+
+
+
+##### Process of retrieving data back into the program
+On startup, SmartHomeBot will perform the `execute()` method in ReadStorageFile. This allows the program to retrieve all
+stored data saved previously from the .txt file back into the program to be used again.
+
+Within the `execute()` method, a Scanner object will be created to parse individual lines in the .txt file back into the
+program and converting them into String. The first line parsed into the program will be the locationlist, which will
+then be parse into the `readToLocationList(locations)` method. In the `readToLocationList(locations)` method, the
+locations will be added back into the `LocationList` one by one. Then the program will return back to execute().
+
+The second line onwards in the .txt file will be the appliances. These appliances will be converted into String and
+parse into the `readToApplianceList` method. In the `readToApplianceList(appliance)` method, each line will be split up
+into their specific parameters(name,location, power, type, powerConsumption and parameter). Then the appliance will be
+converted into static (`Fan`, `AirConditioner`, `Lights`, `SmartPlug`) depending on their types. Then the appliance will
+be added back to the `ApplianceList`. The powerConsumption of each appliance will also be updated to keep track of the
+powerUsage of each appliance.
+
+The sequence diagram for `ReadStorageFile` is shown below:
+
+
+
+
+
+## Appendix A: Product scope
-## Product scope
### Target user profile
-{Describe the target user profile}
+Disabled individuals with mobility issues to perform tasks like switching On/Off Appliances at home.
+While allowing them to automate/monitor their home with smart home devices.
### Value proposition
-{Describe the value proposition: what problem does it solve?}
+This program consolidates all the home appliance’s control into a centralised system. Users with mobility difficulties can easily ON/OFF appliances.
+They can also review and monitor electricity usage; having a clearer picture of their electrical usage patterns. A backlog of the usage can also be recorded.
-## User Stories
+## Appendix B: User Stories
-|Version| As a ... | I want to ... | So that I can ...|
+|Version| As a(n) ... | I want to ... | So that I can ...|
|--------|----------|---------------|------------------|
-|v1.0|new user|see usage instructions|refer to them when I forget how to use the application|
-|v2.0|user|find a to-do item by name|locate a to-do without having to go through the entire list|
+|v1.0|Inexperienced user|list all the functions of the app |To see what he can do. |
+|v1.0|New user |add new locations into SmartHomeBot|Tag these locations into appliances |
+|v1.0|New user |add new appliances|Manipulate and view his appliances usage|
+|v1.0|disabled user |On/Off appliances|Turn on and off appliances without moving much|
+|v1.0|Lazy user|list all the appliances in SmartHomeBot|Remove unnecessary locations and appliances|
+|v1.0|Calculative user |View usage of his appliances|View all the appliances and see their status|
+|v2.0|Lazy user|Change the temperature of the air-conditioner and the speed of the fan from SmartHomeBot|Monitor his smart home appliances|
+|v2.0|Experienced SmartHomeBot user|On/OFF appliances by location and list appliances by location|Easily view and manipulate appliances by location|
+
+## Appendix C: Non-Functional Requirements
+
+1. Should work on any mainstream OS as long as it has Java 11 or above installed.
+
+2. Should be able to hold up to 1000 appliances without a noticeable sluggishness in performance for typical usage.
+
+3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.
+
+## Appendix D: Glossary
+
+*Mainstream OS*
+
+ **Windows, Linux, Unix, OS-X**
+
+*Home appliance details*
+
+ **House appliance that meant to be recorded and use with SmartHomeBot**
+
+
+## Appendix E: Instructions for Manual Testing
+
+Given below are instructions to test the application manually.
+
+**Starting the program:**
+
+ i. Download the jar file from the latest release and copy into an empty folder
+ ii. Run the jar file with java -jar SmartHomeBot.jar
+ Expected: Shows the GUI with some welcome messages.
+
+
+### Creating new location:
+
+Prerequisites: List all appliances and locations using the `list location` and `list appliance` command.
+Making sure the name of the new location is not found in both the list.
+
+1. Test case: `create Bedroom1`
+ Expected-printout: Creating Location "Bedroom1".....CREATED!
+2. Test case: `create Bedroom|2`
+ Expected-printout: Illegal Character space or / or | detected in [LOCATION_NAME].
+3. Test case: `create`
+ Expected-printout: Empty Parameter detected! Please follow format and enter required parameters.
+
+
+### Removing existing location:
+
+Prerequisites: List all locations using the `list location` command.
+Making sure the name of the location is found in the list.
+
+1. Test case: `remove Bedroom1`
+ Expected-printout: Removing LOCATION "Bedroom1"......REMOVED!
+2. Test case: `remove`
+ Expected-printout: Empty Parameter detected! Please follow format and enter required parameters.
+3. Test case: `remove Balcony` , assume `Balcony` was not created.
+ Expected-printout: Location does not exist. Nothing will be deleted.
+
+### Adding new Appliance:
+
+Prerequisites: List all appliances and locations using the `list location` and `list appliance` command.
+Making sure the name of the new appliance is not found in both the list.
+
+1. Test case: `add Light l/Bedroom1 w/10 t/light`
+ Expected-printout: ADDING Light(10W), located at Bedroom1 ......ADDED!
+2. Test case: `add Light 2 l/Bedroom1 w/10 t/light`
+ Expected-printout: Illegal Character space or / or | detected in [APPLIANCE_NAME].
+3. Test case: `add Light_2 w/10 l/Bedroom1 t/light`
+ Expected-printout: Please follow this order, add NAME l/[LOCATION_NAME] w/[WATTS] t/[TYPE_OF_APPLIANCE]
+4. Test case: `add Light_2 l/Bedroom2 w/10 t/light`, as Bedroom2 was not created as a location.
+ Expected-printout: Location does not exist.
+5. Test case: `add Light_2 l/Bedroom1 w/10000 t/light`
+ Expected-printout: Appliance wattage is not supported. Please enter between 1 to 9999.
+6. Test case: `add Light_2 l/Bedroom1 w/5000 t/yellowbulbs`
+ Expected-printout: Invalid appliance type is detected. Only aircon, fan, light and smartplug are accepted as type.
+
+### Deleting existing appliance:
+
+Prerequisites: List all appliances using the `list appliance` command.
+Making sure the name of the appliance is found in the list.
+
+1. Test case: `delete Light`
+ Expected-printout: Deleting Light(10W), located at Bedroom1 .......DELETED.
+2. Test case: `delete`
+ Expected-printout: Empty Parameter detected! Please follow format and enter required parameters.
+3. Test case: `delete Light2` , assume `Light2` was not added.
+ Expected-printout: Light2 does not exist.
+
+### Switching On Appliance:
+
+Prerequisites:
+Ensure that Bedroom1 is created: `create Bedroom1` and ac Appliance is added: `add ac l/Bedroom1 w/5000 t/aircon`.
+
+1. Test case: `on ac`
+ Expected-printout: Switching ac(5000W), located at Bedroom1 @ 25 Degrees.....ON
+2. Test case: `on ac2`
+ Expected-printout: Appliance or Location does not exist in the list.
+3. Test case: `on ac p/`
+ Expected-printout: Empty Parameter detected! Please follow format and enter required parameters.
+4. Test case: `on ac p/21` , assume `ac` was not on.
+ Expected-printout: Switching ac(5000W), located at Bedroom1 @ 21 Degrees.....ON
+5. Test case: `on Bedroom1` , assume `ac` was on.
+ Expected-printout: All Appliances in "Bedroom1" are turned on
+6. Test case: `on ac p/hundred`
+ Expected-printout: Please enter a valid numerical value.
+
+### Switching Off Appliance:
+
+Prerequisites:
+Ensure that Bedroom1 is created: `create Bedroom1` and ac Appliance is added: `add ac l/Bedroom1 w/5000 t/aircon`. Lastly, ensure that ac is turned on for every test: `on ac`
+
+1. Test case: `off ac`
+ Expected-printout: Switching: ac(5000W), located at Bedroom1 ......OFF
+2. Test case: `off ac2`
+ Expected-printout: Appliance or Location does not exist in the list.
+3. Test case: `off ac p/21`
+ Expected-printout: There should be no parameter for this command, please refer to 'help' command.
+4. Test case: `off Bedroom1`
+ Expected-printout: All Appliances in "Bedroom1" are turned off
+
+### Listing Appliances or Locations
+
+1. Test case: `list location`, assume no location is created.
+ Expected-printout: There is currently no Location in the list.
+2. Test case: `list appliance`, assume no appliance is added.
+ Expected-printout: There is currently no Appliance in the list.
+3. Test case: `list Bedroom1`, only `list appliance` or `list location` or `list appliance l/[LOCATION_NAME]` is valid for command.
+ Expected-printout: Please enter either 'list appliance' or 'list location' or 'list appliance l/[LOCATION_NAME]'
+4. Test case: `list appliance l/Bedroom1`, assume that `Bedroom1` is not created
+ Expected-printout: Location: "Bedroom1" does not exist.
+5. Test case: `list appliance l/Bedroom1`, assume that `Bedroom1` is created but no Appliance is added to `Bedroom1`.
+ Expected-printout: There is no Appliance in "Bedroom1".
+
+
+### Saving data to disk
+#### Dealing with missing data files:
+
+When the program is started for the first time, the directory "data" and the text file "data/SmartHomeBot.txt" should be
+automatically created to store all the data when the user start entering commands into the application.
+There are two ways that will cause missing data files:
-## Non-Functional Requirements
+1. When the "data" directory folder is missing.
+2. When the text file "data/SmartHomeBot.txt" is missing from the "data" directory folder.
-{Give non-functional requirements}
+These can be stimulated by deleting either the "data" directory folder or the text file "data/SmartHomeBot.txt".
+Expected-printout: Load File does not exist. No contents will be loaded.
-## Glossary
+#### Dealing with corrupted data files:
-* *glossary item* - Definition
+Corrupted data files usually happen when some of the appliance parameters are missing from the .txt storage file.
+When corrupted data files error occurred, some of the data will not be loaded back into the program when the program
+start up the next time.
-## Instructions for manual testing
+This can be stimulated by removing one of the appliance parameters(Example: the power of the appliance) from the
+text file "data/SmartHomeBot.txt".
+Expected-printout: Data file is corrupted, some data entry will not be entered.
-{Give instructions on how to do a manual product testing e.g., how to load sample data to be used for testing}
diff --git a/docs/README.md b/docs/README.md
index bbcc99c1e7..e32e5e573f 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,8 +1,11 @@
-# Duke
+#
SmartHomeBot
-{Give product intro here}
+SmartHomeBot is a desktop application that consolidates all the home appliance's control into a centralized system via Command Line Interface (CLI).
Useful links:
* [User Guide](UserGuide.md)
* [Developer Guide](DeveloperGuide.md)
* [About Us](AboutUs.md)
+
+
+
\ No newline at end of file
diff --git a/docs/Untitled Diagram.drawio b/docs/Untitled Diagram.drawio
new file mode 100644
index 0000000000..676abd5f63
--- /dev/null
+++ b/docs/Untitled Diagram.drawio
@@ -0,0 +1 @@
+7ZjLcpswFIafhmU6RhgbL2Pn0kU6yTSdSbOU4QTUCMQIEeM+fSUQYC5OcGrctNOVpV8XxP/pnMPYsFZhds1xHHxhHlADTbzMsC4MhEyELPmjlK1WTAcVis+Jp7VauCc/QYsTrabEg6QxUTBGBYmbosuiCFzR0DDnbNOc9sRo86kx9qEj3LuYdtUH4omgUB17UuufgfhB+WRzokdCXE7WQhJgj212JOvSsFacMVG0wmwFVLlX+lKsu9ozWh2MQySGLLCidHmV8YW7vZnE0e3DN4Svz/QuL5im+oUN6/x2/UNZWZxabEsr5AvEqpmG9IY8ASWR7C1j4CQEAVyOUC3f1dpSghFYamrczPuU4jgh63zbiVQ4uClPyAt8haTgn6ssjTzwdK8yL+8Izp4rHGpT/RbABWR77TEr0+V1BSYPyLdySnVXNSd9Ux3d3dTUK7bBDnGrFLG+aX61dQ1DNjSPA9igLps2kpiRSOTPtZeGfdHCwbgImM8iTHeBHN/Y/Tdrr9tTu2H2vM/srtfmYiyvrY7XHkliLNyg47kyg8gEcU6JH0lpzYRgYe4e5uJc5RzlvdxKahB5pbKmzH0up+lE5wwlAF4nTQ3xXyZLzH14bR7q58SBYiFjsplQe2zXS+/UTaz5npn9gMsdEpZyF/SiFrvqFO/HOf2HQ8du5qkqb70RO85YoWP/LyFZqxR8mBIy+6vjwD6khPSa3VNCZmN5Pe94zUGkPBpeQHaKBYtBDi09nAS5z2YxvFM2ICPiuzZdtR9V+9PCfndFKVLy25dpWEUZFDe/WWTQvHkFkDVrblEcdbQq4xzho6HnA0G6xrcVWtV5PCTSDgeLBoKd/SmwnaAd+fNh0QEr0dE1lniOAtY8EdihETs9Gdhps0KiduUbGWxZEU6dpM2TJenph4vlNnJ7fqQkLbv1vyfF9PpPKOvyFw==
\ No newline at end of file
diff --git a/docs/UserGuide.md b/docs/UserGuide.md
index abd9fbe891..ddf4575e95 100644
--- a/docs/UserGuide.md
+++ b/docs/UserGuide.md
@@ -1,42 +1,304 @@
-# User Guide
+#
SmartHomeBot User Guide
-## Introduction
+SmartHomeBot is a **desktop application that consolidates all home appliance’s control into a
+centralized system via a Command Line Interface (CLI)**. It is designed to assist disabled individuals with
+difficulties to perform tasks like switching On/Off Appliances at home. Users can also
+review and monitor electricity usage; having a clearer picture of their electrical usage patterns.
+SmartHomeBot has an auto-save feature that will automatically save all the appliances' data
+and export it to a text file. Upon the start of the application, it will import the data
+from the text file and loads the appliances' data back.
-{Give a product intro}
-## Quick Start
+##### Disclaimer: SmartHomeBot V2.1 does not interface with actual Appliances. Instead, Appliances are simulated in this program.
-{Give steps to get started quickly}
+## Table of Contents
+* [Quick start](#quick-start)
+* [Features](#features)
+ * [Viewing help: `help`](#viewing-help-help)
+ * [Creating a location: `create`](#creating-a-location-create)
+ * [Removing a location: `remove`](#removing-a-location-remove)
+ * [Adding an appliance : `add`](#adding-an-appliance-add)
+ * [Deleting an appliance: `delete`](#deleting-an-appliance-delete)
+ * [Switching on an appliance: `on`](#switching-on-an-appliance-on)
+ * [Switching off an appliance: `off`](#switching-off-an-appliance-off)
+ * [Listing all the locations/appliances: `list`](#listing-all-the-locations-or-appliances-list)
+ * [Displaying the recorded usage of appliance: `usage`](#displaying-the-recorded-usage-of-appliance-usage)
+ * [Resetting all power usage in application: `p_reset`](#resetting-all-power-usage-in-application-p_reset)
+ * [Exiting the application: `exit`](#exiting-the-application-exit)
+ * [Saving the data](#saving-the-data)
+* [Command summary](#command-summary)
-1. Ensure that you have Java 11 or above installed.
-1. Down the latest version of `Duke` from [here](http://link.to/duke).
+
+## Quick start
+
+1. Ensure you have Java `11` or above installed in your Computer.
+
+2. Download the latest `SmartHomeBot.jar` from [here](https://github.com/AY2021S1-CS2113-T14-1/tp/releases/latest).
+
+3. Copy the file to the folder you want to use as the home folder for your SmartHomeBot.
+
+4. Open your Command Prompt/Terminal. Navigate to the folder which you place the SmartHomeBot.jar. Then input `java -jar SmartHomeBot.jar` and
+press ENTER. The display similar to the below should appear in a few seconds.
+
+ 
+
+5. Type the command in the command box and press Enter to execute it.
+e.g. typing `exit` and pressing Enter, it will exit the program.
+Some example commands you can try:
+ * `create Bedroom1`:
+ Creates a 'location' named "Bedroom1" in SmartHomeBot.
+
+ * `remove Bedroom1`:
+ Remove a 'location' named "Bedroom1" in SmartHomeBot.
+
+ * `list location`:
+ Lists all the location.
+
+6. Refer to the Features below for details of each command.
## Features
-{Give detailed description of each feature}
+ **Notes about the command format**
+
+ * Words in **[UPPER_CASE]** are the parameters to be supplied by the user.
+
e.g. `create [LOCATION_NAME]`, LOCATION_NAME is a parameter which can be used as
+ `create Bedroom1`.
+ * Words in **[UPPER_CASE]** are case-sensitive.
+ * Words in **[LOCATION_NAME]** and **[APPLIANCE_NAME]** has to be unique and not duplicate of each other.
+ * Words in **[LOCATION_NAME]** and **[APPLIANCE_NAME]** cannot contain `space` or `/` or `|` when `create` or `add`
+ * Caution: Please do not type `Ctrl-C or Ctrl-Z` as it may cause the application to terminate due the in-build function
+ on command prompt
+
+### Viewing help: `help`
+Shows all available commands to the user
+
+Format: `help`
+
+Example: `help`
+
+Output:
+
+ 
+
+### Creating a location: `create`
+Adds a new location with a name.
+
+Format: `create [LOCATION_NAME]`
+* `LOCATION_NAME` must be a unique name.
+* `Space` cannot be included in `LOCATION_NAME`. However `_` can be used to replace `space` if you want to create a
+`LOCATION_NAME` with more than one word.
+
+Example: `create Bedroom1`
+
+Output:
+
+ 
+
+
+### Removing a location: `remove`
+Removes an added location with its name in the list.
+
+Format: `remove [LOCATION_NAME]`
+
+Example: `remove Bedroom1`
+
+Output:
+
+ 
+
+> Note: If there are appliances in the Location of 'LOCATION_NAME' when removing, it will be deleted as well.
+
+
+### Adding an appliance: `add`
+Adds an appliance to the location created previously.
+
+Format: `add [APPLIANCE_NAME] l/[LOCATION_NAME] w/[WATTAGE] t/[TYPE_OF_APPLIANCE]`
+* `[APPLIANCE_NAME]` must be a unique name.
+* `[LOCATION_NAME]` must be an existing location created by `create` command.
+* `[WATTAGE]` must be an `int` value between 1-9999.
+* `[TYPE_OF_APPLIANCE]` must be one of the type in the following list.
+
+List of `TYPE_OF_APPLIANCE`
+1. `fan`
+2. `light`
+2. `aircon`
+3. `smartplug`
+
+Example: `add AIRCON1 l/Bedroom1 w/3500 t/aircon`
+
+Output:
+
+ 
+
+
+### Deleting an appliance: `delete`
+Deletes an appliance base on its name in the list.
+
+Format: `delete [APPLIANCE_NAME]`
+
+Example: `delete AIRCON1`
+
+Output:
+
+ 
+
+
+### Switching on an appliance: `on`
+Switches ON an appliance base on its name in the list.
+
+Format: `on [APPLIANCE_NAME]` or `on [APPLIANCE_NAME] p/[PARAMETER]` or `on [LOCATION_NAME]`
+
+1. `on [APPLIANCE_NAME]`: Switch ON the appliance by its name.
+2. `on [APPLIANCE_NAME] p/[TEMPERATURE]`: Switch ON the appliance by its name with parameter for air-conditioner.
+3. `on [APPLIANCE_NAME] p/[SPEED]`: Switch ON the appliance by its name with parameter for fan.
+4. `on [LOCATION]`: Switch ON every appliance in the location.
+
+* Range for `TEMPERATURE`: 16 - 30
+* Range for `SPEED`: 1-3
+* If no `PARAMETER` is provided, the appliance will turn on with their default parameter, which are: 25 for `TEMPERATURE` and 1 for `SPEED`
+
+Example: `on AIRCON1`
-### Adding a todo: `todo`
-Adds a new item to the list of todo items.
+Output:
+
+ 
+
+Example: `on AIRCON1 p/27`
-Format: `todo n/TODO_NAME d/DEADLINE`
+Output:
+
+ 
-* The `DEADLINE` can be in a natural language format.
-* The `TODO_NAME` cannot contain punctuation.
+When Appliance is already ON, we can still change the Appliance's parameter:
-Example of usage:
+Example: `on AIRCON1 p/16`
-`todo n/Write the rest of the User Guide d/next week`
+Output:
-`todo n/Refactor the User Guide to remove passive voice d/13/04/2020`
+ 
+
+Example: `on FAN1 p/3`
+
+Output:
+
+ 
+
+Example: `on Bedroom1`
+
+Output:
+
+ 
+
+
+### Switching off an appliance: `off`
+Switches OFF an appliance base on its name in the list.
+
+Format: `off [APPLIANCE_NAME]` or `off [LOCATION]`
+
+Example: `off AIRCON1`
+
+Output:
+
+ 
+
+
+Example: `off Bedroom1`
+
+Output:
+
+ 
+
+
+### Listing all the locations OR appliances: `list`
+List out all the appliances or all the location currently stored.
+
+Format: `list appliance` or `list location` or `list appliance l/[LOCATION_NAME]`
+* `list appliance` will list all the appliances entered by the user.
+* `list location` will list all the locations entered by the user.
+* `list appliance l/[LOCATION_NAME]` will list all the appliances in the location entered by the user.
+
+Example: `list location`
+
+Output:
+
+ 
+
+
+Example: `list appliance`
+
+Output:
+
+ 
+
+Example: `list appliance l/Bedroom1`
+
+Output:
+
+ 
+
+
+### Displaying the recorded usage of appliance: `usage`
+Display the current power usage of all appliances and total power consumption monitored within SmartHomeBot.
+
+Format: `usage`
+
+Output:
+
+ 
+
+
+### Resetting all power usage in application: `p_reset`
+Reset the previous recorded power usage of all appliances and total power consumption to zero. Note that if appliance remains **ON**, its usage will be reset to zero, monitoring process continues, as the appliance remains running.
+
+
+Format: `p_reset`
+
+Output:
+
+ 
+
+
+### Exiting the application: `exit`
+Exits the application and switch off all appliances within SmartHomeBot. The monitoring of all appliances will be stop.
+
+Format: `exit`
+
+Output:
+
+ 
+
+
+
+## Saving the data
+SmartHomeBot will auto-save the task list data in the hard disk after
+any command that changes the data. There is no need to save manually.
+
+
## FAQ
-**Q**: How do I transfer my data to another computer?
+**Q**: How do I transfer my data to another Computer?
+
+**A**: Install the app in the other computer and overwrite the empty data file it creates with the file
+that contains the data of your previous SmartHomeBot folder.
-**A**: {your answer here}
+**Q**: Does the program interface with the appliance?
-## Command Summary
+**A**: Current SmartHomeBot v2.1 does not interface with actual Appliances. Instead the Appliances are simulated
+as a proof of concept for future implementation.
-{Give a 'cheat sheet' of commands here}
+## Command summary
-* Add todo `todo n/TODO_NAME d/DEADLINE`
+Function | Format | Example
+-------- |--------|--------
+Help|`help`
+Create location|`create [LOCATION_NAME]`|`create Bedroom1`
+Remove location|`remove [LOCATION_NAME]`|`remove Bedroom1`
+Add appliance|`add [APPLIANCE_NAME] l/[LOCATION_NAME] w/[WATTAGE] t/[TYPE_OF_APPLIANCE]`|`add AIRCON1 l/Bedroom1 w/3500 t/aircon`
+Delete appliance|`delete [APPLIANCE_NAME]`|`delete AIRCON1`
+Switch On|`on [APPLIANCE_NAME]` or `on [APPLIANCE_NAME] p/[PARAMETER]` or `on [LOCATION_NAME]`|`on AIRCON1` or `on AIRCON1 p/27` or `on Bedroom1`
+Switch Off|`off [APPLIANCE_NAME]` or `off [LOCATION]`|`off AIRCON1` or `off Bedroom1`
+List|`list appliance` or `list location` or `list appliance l/[LOCATION_NAME]`|`list appliance l/Bedroom1`
+Usage|`usage`
+Reset|`p_reset`
+Exit|`exit`
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..4215cf3256
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1,4 @@
+theme: jekyll-theme-slate
+favicon: docs/images/favicon.ico
+title: SmartHomeBot
+description: SmartHomeBot - Java CLI Application that monitor your smart home.
\ No newline at end of file
diff --git a/docs/images/diagrams/Architecture.png b/docs/images/diagrams/Architecture.png
new file mode 100644
index 0000000000..1809ad01ab
Binary files /dev/null and b/docs/images/diagrams/Architecture.png differ
diff --git a/docs/images/diagrams/ClassDiagram_DataOverview.png b/docs/images/diagrams/ClassDiagram_DataOverview.png
new file mode 100644
index 0000000000..cf75e9ab49
Binary files /dev/null and b/docs/images/diagrams/ClassDiagram_DataOverview.png differ
diff --git a/docs/images/diagrams/ClassDiagram_DetailedData.png b/docs/images/diagrams/ClassDiagram_DetailedData.png
new file mode 100644
index 0000000000..217fd426c0
Binary files /dev/null and b/docs/images/diagrams/ClassDiagram_DetailedData.png differ
diff --git a/docs/images/diagrams/ClassDiagram_Power.png b/docs/images/diagrams/ClassDiagram_Power.png
new file mode 100644
index 0000000000..201773a80b
Binary files /dev/null and b/docs/images/diagrams/ClassDiagram_Power.png differ
diff --git a/docs/images/diagrams/ClassDiagram_Storage.png b/docs/images/diagrams/ClassDiagram_Storage.png
new file mode 100644
index 0000000000..22f27868d5
Binary files /dev/null and b/docs/images/diagrams/ClassDiagram_Storage.png differ
diff --git a/docs/images/diagrams/ClassDiagram_UI.png b/docs/images/diagrams/ClassDiagram_UI.png
new file mode 100644
index 0000000000..3d3a6d33ef
Binary files /dev/null and b/docs/images/diagrams/ClassDiagram_UI.png differ
diff --git a/docs/images/diagrams/Sequence_AddCommand.png b/docs/images/diagrams/Sequence_AddCommand.png
new file mode 100644
index 0000000000..6a68296c94
Binary files /dev/null and b/docs/images/diagrams/Sequence_AddCommand.png differ
diff --git a/docs/images/diagrams/Sequence_CommandResult.png b/docs/images/diagrams/Sequence_CommandResult.png
new file mode 100644
index 0000000000..17ddc7f10a
Binary files /dev/null and b/docs/images/diagrams/Sequence_CommandResult.png differ
diff --git a/docs/images/diagrams/Sequence_CreateCommand.png b/docs/images/diagrams/Sequence_CreateCommand.png
new file mode 100644
index 0000000000..b530cadbfa
Binary files /dev/null and b/docs/images/diagrams/Sequence_CreateCommand.png differ
diff --git a/docs/images/diagrams/Sequence_DeleteCommand.png b/docs/images/diagrams/Sequence_DeleteCommand.png
new file mode 100644
index 0000000000..598d013568
Binary files /dev/null and b/docs/images/diagrams/Sequence_DeleteCommand.png differ
diff --git a/docs/images/diagrams/Sequence_ExitCommand.png b/docs/images/diagrams/Sequence_ExitCommand.png
new file mode 100644
index 0000000000..389b68d657
Binary files /dev/null and b/docs/images/diagrams/Sequence_ExitCommand.png differ
diff --git a/docs/images/diagrams/Sequence_HelpCommand.png b/docs/images/diagrams/Sequence_HelpCommand.png
new file mode 100644
index 0000000000..7878b29684
Binary files /dev/null and b/docs/images/diagrams/Sequence_HelpCommand.png differ
diff --git a/docs/images/diagrams/Sequence_InvalidCommand.png b/docs/images/diagrams/Sequence_InvalidCommand.png
new file mode 100644
index 0000000000..565bd34774
Binary files /dev/null and b/docs/images/diagrams/Sequence_InvalidCommand.png differ
diff --git a/docs/images/diagrams/Sequence_ListCommand.png b/docs/images/diagrams/Sequence_ListCommand.png
new file mode 100644
index 0000000000..be8846ccaa
Binary files /dev/null and b/docs/images/diagrams/Sequence_ListCommand.png differ
diff --git a/docs/images/diagrams/Sequence_LogicComponent.png b/docs/images/diagrams/Sequence_LogicComponent.png
new file mode 100644
index 0000000000..a0bd22280d
Binary files /dev/null and b/docs/images/diagrams/Sequence_LogicComponent.png differ
diff --git a/docs/images/diagrams/Sequence_MainParser.png b/docs/images/diagrams/Sequence_MainParser.png
new file mode 100644
index 0000000000..085e715f9d
Binary files /dev/null and b/docs/images/diagrams/Sequence_MainParser.png differ
diff --git a/docs/images/diagrams/Sequence_OffCommand.png b/docs/images/diagrams/Sequence_OffCommand.png
new file mode 100644
index 0000000000..cbc14305d7
Binary files /dev/null and b/docs/images/diagrams/Sequence_OffCommand.png differ
diff --git a/docs/images/diagrams/Sequence_OnCommand.png b/docs/images/diagrams/Sequence_OnCommand.png
new file mode 100644
index 0000000000..5d56cc1be5
Binary files /dev/null and b/docs/images/diagrams/Sequence_OnCommand.png differ
diff --git a/docs/images/diagrams/Sequence_Parser_Add.png b/docs/images/diagrams/Sequence_Parser_Add.png
new file mode 100644
index 0000000000..f6be951807
Binary files /dev/null and b/docs/images/diagrams/Sequence_Parser_Add.png differ
diff --git a/docs/images/diagrams/Sequence_Parser_Commandword.png b/docs/images/diagrams/Sequence_Parser_Commandword.png
new file mode 100644
index 0000000000..1333b7be46
Binary files /dev/null and b/docs/images/diagrams/Sequence_Parser_Commandword.png differ
diff --git a/docs/images/diagrams/Sequence_Parser_Create.png b/docs/images/diagrams/Sequence_Parser_Create.png
new file mode 100644
index 0000000000..6e620c9dcd
Binary files /dev/null and b/docs/images/diagrams/Sequence_Parser_Create.png differ
diff --git a/docs/images/diagrams/Sequence_Parser_Default.png b/docs/images/diagrams/Sequence_Parser_Default.png
new file mode 100644
index 0000000000..ef832d710c
Binary files /dev/null and b/docs/images/diagrams/Sequence_Parser_Default.png differ
diff --git a/docs/images/diagrams/Sequence_Parser_Delete.png b/docs/images/diagrams/Sequence_Parser_Delete.png
new file mode 100644
index 0000000000..8e30dc792a
Binary files /dev/null and b/docs/images/diagrams/Sequence_Parser_Delete.png differ
diff --git a/docs/images/diagrams/Sequence_Parser_List.png b/docs/images/diagrams/Sequence_Parser_List.png
new file mode 100644
index 0000000000..3d8d7ba322
Binary files /dev/null and b/docs/images/diagrams/Sequence_Parser_List.png differ
diff --git a/docs/images/diagrams/Sequence_Parser_Off.png b/docs/images/diagrams/Sequence_Parser_Off.png
new file mode 100644
index 0000000000..33fe3a67c9
Binary files /dev/null and b/docs/images/diagrams/Sequence_Parser_Off.png differ
diff --git a/docs/images/diagrams/Sequence_Parser_On.png b/docs/images/diagrams/Sequence_Parser_On.png
new file mode 100644
index 0000000000..7f0b943e55
Binary files /dev/null and b/docs/images/diagrams/Sequence_Parser_On.png differ
diff --git a/docs/images/diagrams/Sequence_Parser_Remove.png b/docs/images/diagrams/Sequence_Parser_Remove.png
new file mode 100644
index 0000000000..41a2d37d54
Binary files /dev/null and b/docs/images/diagrams/Sequence_Parser_Remove.png differ
diff --git a/docs/images/diagrams/Sequence_ReadStorageFile.png b/docs/images/diagrams/Sequence_ReadStorageFile.png
new file mode 100644
index 0000000000..81681420a1
Binary files /dev/null and b/docs/images/diagrams/Sequence_ReadStorageFile.png differ
diff --git a/docs/images/diagrams/Sequence_RemoveCommand.png b/docs/images/diagrams/Sequence_RemoveCommand.png
new file mode 100644
index 0000000000..222695babd
Binary files /dev/null and b/docs/images/diagrams/Sequence_RemoveCommand.png differ
diff --git a/docs/images/diagrams/Sequence_ResetCommand.png b/docs/images/diagrams/Sequence_ResetCommand.png
new file mode 100644
index 0000000000..1b469d82c5
Binary files /dev/null and b/docs/images/diagrams/Sequence_ResetCommand.png differ
diff --git a/docs/images/diagrams/Sequence_TextUi.png b/docs/images/diagrams/Sequence_TextUi.png
new file mode 100644
index 0000000000..076e752bd0
Binary files /dev/null and b/docs/images/diagrams/Sequence_TextUi.png differ
diff --git a/docs/images/diagrams/Sequence_UsageCommand.png b/docs/images/diagrams/Sequence_UsageCommand.png
new file mode 100644
index 0000000000..f04ae9b527
Binary files /dev/null and b/docs/images/diagrams/Sequence_UsageCommand.png differ
diff --git a/docs/images/diagrams/Sequence_WriteStorageFile.png b/docs/images/diagrams/Sequence_WriteStorageFile.png
new file mode 100644
index 0000000000..09a7f96ddc
Binary files /dev/null and b/docs/images/diagrams/Sequence_WriteStorageFile.png differ
diff --git a/docs/images/diagrams/Sequence_overview.png b/docs/images/diagrams/Sequence_overview.png
new file mode 100644
index 0000000000..2039dab36c
Binary files /dev/null and b/docs/images/diagrams/Sequence_overview.png differ
diff --git a/docs/images/diagrams/SummarisedClassDiagram.png b/docs/images/diagrams/SummarisedClassDiagram.png
new file mode 100644
index 0000000000..4164224777
Binary files /dev/null and b/docs/images/diagrams/SummarisedClassDiagram.png differ
diff --git a/docs/images/favicon.ico b/docs/images/favicon.ico
new file mode 100644
index 0000000000..13116eb62f
Binary files /dev/null and b/docs/images/favicon.ico differ
diff --git a/docs/images/findoutmore.png b/docs/images/findoutmore.png
new file mode 100644
index 0000000000..c2d15d2e89
Binary files /dev/null and b/docs/images/findoutmore.png differ
diff --git a/docs/images/smarthomebot-logo.png b/docs/images/smarthomebot-logo.png
new file mode 100644
index 0000000000..f4c2027401
Binary files /dev/null and b/docs/images/smarthomebot-logo.png differ
diff --git a/docs/images/smarthomebot.jpg b/docs/images/smarthomebot.jpg
new file mode 100644
index 0000000000..b866476003
Binary files /dev/null and b/docs/images/smarthomebot.jpg differ
diff --git a/docs/images/user_guide/ExitMessage.png b/docs/images/user_guide/ExitMessage.png
new file mode 100644
index 0000000000..b88edf2666
Binary files /dev/null and b/docs/images/user_guide/ExitMessage.png differ
diff --git a/docs/images/user_guide/addCommand.png b/docs/images/user_guide/addCommand.png
new file mode 100644
index 0000000000..004574088f
Binary files /dev/null and b/docs/images/user_guide/addCommand.png differ
diff --git a/docs/images/user_guide/autoformatting_screenshot.JPG b/docs/images/user_guide/autoformatting_screenshot.JPG
new file mode 100644
index 0000000000..902042b536
Binary files /dev/null and b/docs/images/user_guide/autoformatting_screenshot.JPG differ
diff --git a/docs/images/user_guide/createCommand.png b/docs/images/user_guide/createCommand.png
new file mode 100644
index 0000000000..d075d8162a
Binary files /dev/null and b/docs/images/user_guide/createCommand.png differ
diff --git a/docs/images/user_guide/deleteCommand.png b/docs/images/user_guide/deleteCommand.png
new file mode 100644
index 0000000000..72a5deb96e
Binary files /dev/null and b/docs/images/user_guide/deleteCommand.png differ
diff --git a/docs/images/user_guide/exitCommand.png b/docs/images/user_guide/exitCommand.png
new file mode 100644
index 0000000000..60e3d1f6cb
Binary files /dev/null and b/docs/images/user_guide/exitCommand.png differ
diff --git a/docs/images/user_guide/helpCommand.png b/docs/images/user_guide/helpCommand.png
new file mode 100644
index 0000000000..f1e689f261
Binary files /dev/null and b/docs/images/user_guide/helpCommand.png differ
diff --git a/docs/images/user_guide/listCommand1.png b/docs/images/user_guide/listCommand1.png
new file mode 100644
index 0000000000..ee1b39974c
Binary files /dev/null and b/docs/images/user_guide/listCommand1.png differ
diff --git a/docs/images/user_guide/listCommand2.png b/docs/images/user_guide/listCommand2.png
new file mode 100644
index 0000000000..3691393d9c
Binary files /dev/null and b/docs/images/user_guide/listCommand2.png differ
diff --git a/docs/images/user_guide/listCommand3.png b/docs/images/user_guide/listCommand3.png
new file mode 100644
index 0000000000..88c4561f38
Binary files /dev/null and b/docs/images/user_guide/listCommand3.png differ
diff --git a/docs/images/user_guide/offCommand1.png b/docs/images/user_guide/offCommand1.png
new file mode 100644
index 0000000000..69eadabbda
Binary files /dev/null and b/docs/images/user_guide/offCommand1.png differ
diff --git a/docs/images/user_guide/offCommand2.png b/docs/images/user_guide/offCommand2.png
new file mode 100644
index 0000000000..84d98408d8
Binary files /dev/null and b/docs/images/user_guide/offCommand2.png differ
diff --git a/docs/images/user_guide/onCommand1.png b/docs/images/user_guide/onCommand1.png
new file mode 100644
index 0000000000..f68d718db2
Binary files /dev/null and b/docs/images/user_guide/onCommand1.png differ
diff --git a/docs/images/user_guide/onCommand2.png b/docs/images/user_guide/onCommand2.png
new file mode 100644
index 0000000000..a4868242f3
Binary files /dev/null and b/docs/images/user_guide/onCommand2.png differ
diff --git a/docs/images/user_guide/onCommand3.png b/docs/images/user_guide/onCommand3.png
new file mode 100644
index 0000000000..ba1c088a17
Binary files /dev/null and b/docs/images/user_guide/onCommand3.png differ
diff --git a/docs/images/user_guide/onCommand4.png b/docs/images/user_guide/onCommand4.png
new file mode 100644
index 0000000000..e0dfdc9163
Binary files /dev/null and b/docs/images/user_guide/onCommand4.png differ
diff --git a/docs/images/user_guide/onCommand6.png b/docs/images/user_guide/onCommand6.png
new file mode 100644
index 0000000000..65284cd3b4
Binary files /dev/null and b/docs/images/user_guide/onCommand6.png differ
diff --git a/docs/images/user_guide/p_resetCommand.png b/docs/images/user_guide/p_resetCommand.png
new file mode 100644
index 0000000000..3c50c7692f
Binary files /dev/null and b/docs/images/user_guide/p_resetCommand.png differ
diff --git a/docs/images/user_guide/removeCommand.png b/docs/images/user_guide/removeCommand.png
new file mode 100644
index 0000000000..3ed2b2509f
Binary files /dev/null and b/docs/images/user_guide/removeCommand.png differ
diff --git a/docs/images/user_guide/startMessage.png b/docs/images/user_guide/startMessage.png
new file mode 100644
index 0000000000..be592c399c
Binary files /dev/null and b/docs/images/user_guide/startMessage.png differ
diff --git a/docs/images/user_guide/startupScreenshot.png b/docs/images/user_guide/startupScreenshot.png
new file mode 100644
index 0000000000..1c143b2c04
Binary files /dev/null and b/docs/images/user_guide/startupScreenshot.png differ
diff --git a/docs/images/user_guide/usageCommand.png b/docs/images/user_guide/usageCommand.png
new file mode 100644
index 0000000000..6deed76d95
Binary files /dev/null and b/docs/images/user_guide/usageCommand.png differ
diff --git a/docs/team/ang-cheng-jun.md b/docs/team/ang-cheng-jun.md
new file mode 100644
index 0000000000..4e0032757a
--- /dev/null
+++ b/docs/team/ang-cheng-jun.md
@@ -0,0 +1,72 @@
+# Ang Cheng Jun - Project Portfolio Page
+
+## Overview
+SmartHomeBot is a **desktop application that consolidates all home appliance’s control into a
+centralized system via a Command Line Interface (CLI)**. Users can switch on or off appliances by using this application
+and review and monitor electricity usage; having a clearer picture of their electrical usage patterns. They will need to
+create a location and add appliances into the particular location to enable the on/off feature. There is
+a AutoSave feature which will save all your location, appliances and appliances' electrical usage into a text file. All the
+appliances will be switch off when the user exit the application. Upon the start of the application, the data of the text file
+will be imported to the application.
+
+### Summary of Contributions
+#### Code Contributed
+Below is the link to view all the codes that I contributed to SmartHomeBot Project. Click on RepoSense to direct you to the page
+
+* [RepoSense](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=ang-cheng-jun&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+#### Enhancements implemented
+1. I created a ListCommand filter which allows the users to list all the appliances in that particular location.
+ * Implementation of ListCommand filter
+ * I used stream method to store all the Appliance Class which stores the filtered location into a new ArrayList and display the list to user.
+
+2. In addition, to add ease to the typing of command, I design a logic function in OnCommand which allows users to key you `on [APPLIANCE_NAME]` or
+`on [APPLIANCE_NAME]` which allows user to switch on an appliance or a group of appliance in the location.This logic function is
+also implement in the OffCommand.
+ * Implementation of logic function which ease the typing of command for OnCommand and OffCommand
+ * For the logic function, I assume that argument that the user typed is an appliance initially. In the function, it will check if any of the Appliance Class in
+ the ApplianceList has the location similar to the argument that user typed.
+ * If there is similar location in the Appliance Class, then we know that the argument is a location. All Appliance Class with the similar location will store in a new ArrayList
+ and turn on/off all the appliance in the ArrayList. Then, it will display the corresponding message to user.
+ * If there is no Appliance Class' location is similar to the argument, then we check if the location exists in the LocationList or not. If
+ it exists, then we know that the argument is a location. This means that there is no appliance in that location, and it will display the corresponding message to user.
+ * If both check failed, then we can assume that the argument is an appliance. Then the function will look for the Appliance Class' name which is similar to the argument
+ and turn on/off the appliance and display the corresponding message to the user.
+ * If argument cannot be found in both LocationList and ApplianceList, we can conclude that the argument is invalid and display the corresponding message to the user.
+
+#### Contributions to the UserGuide
+Initially, I did the overall layout of the UserGuide which allowing all the team member including me to know where to input their content of the function that they have implemented.
+In addition, I have added images to the UserGuide for better illustration to the users.
+When all the team members have completed their subsection, I reviewed their content to check for any wrong information in the content.
+Refer to the link below to view the UserGuide.
+
+* [UserGuide](https://ay2021s1-cs2113-t14-1.github.io/tp/UserGuide.html)
+
+#### Contributions to the DeveloperGuide
+Initially, the whole group including me brainstormed to decide on the user stories which is used in the DeveloperGuide. You can refer to the link below on Trello to see the contribution,
+in the user stories.
+
+* [Trello](https://trello.com/b/s32JQHmK/cs2113-storyboard)
+
+
+I also write and design the Sequence Diagram for ListCommand, HelpCommand, InvalidCommand and ExitCommand. All the information and design
+follow the textbook standard provided to us. And also, I did the Test Cases for list command which is in the Appendix E. You can refer
+the link below on DeveloperGuide to view the contribution.
+
+* [DeveloperGuide](https://ay2021s1-cs2113-t14-1.github.io/tp/DeveloperGuide.html)
+
+#### Review/mentoring contributions:
+Provided feedbacks to team members on their code through pull request and also private messaging. Refer the links below on some of my feedback
+to the team members through pull request.
+
+* [Pull Request 1](https://github.com/AY2021S1-CS2113-T14-1/tp/pull/201)
+* [Pull Request 2](https://github.com/AY2021S1-CS2113-T14-1/tp/pull/208)
+
+In addition, I always get involved in discussion on a better implementation of method in the function. Most of our discussion is on Zoom.
+
+#### Contributions beyond the project team:
+Provided post feedbacks to other project teams on the bug i encountered during the PE Dry Run. Refer the links below on some of my post feedback
+to other project team through the issue tracker.
+
+* [Bug Issue 1](https://github.com/Ang-Cheng-Jun/ped/issues/9)
+* [Bug Issue 2](https://github.com/AY2021S1-CS2113-T13-2/tp/issues/220)
\ No newline at end of file
diff --git a/docs/team/fanceso.md b/docs/team/fanceso.md
new file mode 100644
index 0000000000..27773d4e9a
--- /dev/null
+++ b/docs/team/fanceso.md
@@ -0,0 +1,52 @@
+# Yang Fan - Project Portfolio Page
+
+## Overview
+SmartHomeBot is a **desktop application that consolidates all home appliance’s control into a
+centralized system via a Command Line Interface (CLI)**. SmartHomeBot is a National University of Singapore team project, *JAVA* is the main language used, under module
+**CS2113: Software Engineering & Object Oriented Programming**. This application is a simulation of control panel for home appliances. Smart Home gadgets like Smart Switch, Smart WiFi LED, Fan and Air Conditional can be integrated in the future. This appliance allows user to control four main types of appliances such as Fan, Light, Air Conditional and SmartPlug. User able to add the appliances as their own configuration of their house and data will be saved locally. Control on and off of the appliances allows user to monitor the power usage of the smart devices.
+
+### Summary of Contributions
+
+#### Code Contributed
+Click on [RepoSense](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=fanceso&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=functional-code~test-code~other~docs) to find out more about my contribution to the project on Github.
+
+
+##### Main Functions Implemented
+I am mainly responsible for the monitoring of power usage of all Appliances within SmartHomeBot. Which consists of:
+
+###### *Data*
+- `Power`: Data which stores as appliance's status and its power consumption usage.
+
+ 
+
+The class diagram above shows how power is been stored and computed. The calculation of kWh requires time and here the system time from the machine is used. Whenever user is using the appliance, the monitor of the power consumption will be always calculating with the appliance's respective `ON/OFF` status and its wattage.
+
+###### *Logic*
+- `Usage` : Command to compute and display total power consumption usage.
+- `Reset` : Command to reset all previous recorded power consumption usage.
+
+The functionalities and manipulation of above mentioned are under my responsibilities, I will have to seek feedbacks from my fellow teammates for bugs and functionalities requests.
+
+#### Enhancements implemented
+I implemented the Usage command which will record and monitor the actual usage according to the Local System Time from the Machine, this will give an accurate usage from real life. Upon user leaving the program, all appliances will be turn off asn stop its monitoring as program was terminated. In order to have a good user experience, I have implemented *Auto-Formatting* for the printing out result. Every new appliance and location is added or delete to the application, the longest length of these string will be found out as the required printing index. The format of printing is showing in the screenshot below.
+
+ 
+
+#### Contributions to the DeveloperGuide:
+Write up about the introduction and appendix of SmartHomeBot, in charge of overall styling and alignments of the contents and diagrams. Provided Sequence Diagrams for the Architecture, Overview with example, UI, Usage Command and Reset Command. Also, provide class diagram for TextUi.
+
+#### Review/mentoring contributions:
+
+I also actively take part in reviewing my teammates code through GitHub:
+* [Pull Request 1](https://github.com/AY2021S1-CS2113-T14-1/tp/pull/31)
+* [Pull Request 2](https://github.com/AY2021S1-CS2113-T14-1/tp/pull/223)
+
+In addition, we often meet up on Zoom and other communication channels. I will be the one who takes care of admin issues and note down the to do list for the team.
+
+#### Contributions beyond the project team:
+
+I also actively take part in other group's project development by reviewing their program for tutorials and PE dry runs.
+* [Bug Issue 1](https://github.com/fanceso/ped/issues)
+* [Comments 1](https://github.com/nus-cs2113-AY2021S1/tp/pull/19)
+* [Comments 2](https://github.com/nus-cs2113-AY2021S1/tp/pull/3)
+* [Comments 3](https://github.com/nus-cs2113-AY2021S1/tp/pull/15)
diff --git a/docs/team/johndoe.md b/docs/team/johndoe.md
deleted file mode 100644
index ab75b391b8..0000000000
--- a/docs/team/johndoe.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# John Doe - Project Portfolio Page
-
-## Overview
-
-
-### Summary of Contributions
diff --git a/docs/team/leonlowzd.md b/docs/team/leonlowzd.md
new file mode 100644
index 0000000000..bd0977e474
--- /dev/null
+++ b/docs/team/leonlowzd.md
@@ -0,0 +1,49 @@
+# Leon Low - Project Portfolio Page
+
+## Overview
+SmartHomeBot is a **desktop application that consolidates all home appliance’s control into a
+centralized system via a Command Line Interface (CLI)**. SmartHomeBot is our team project submission for
+**CS2113: Software Engineering & Object Oriented Programming** Module.
+
+### Summary of Contributions
+
+#### Code Contributed
+Below is the link to view all the codes that I contributed to SmartHomeBot Project. Click on RepoSense to direct you to
+the page:
+
+* [RepoSense](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=leonlowzd&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+##### Main Functions Implemented
+I am mainly responsible for the data package of SmartHomeBot. Which consists of:
+
+1. ApplianceList: Data Structure storing the Appliances.
+2. LocationList: List of stored locations.
+3. Types of Appliances:
+ 1. Air-Conditioner
+ 2. Fan
+ 3. Lights
+ 4. Smart Plug
+
+The functionalities and manipulation of data are under my responsibilities, I will have to seek feedbacks from my fellow
+teammates for bugs and functionalities requests.
+
+#### Enhancements implemented
+I implemented the ON/OFF by parameters function for SmartHomeBot which enabled the program to change temperature and speed
+for Air-Conditioner and Fan type appliances.
+
+#### Contributions to the DeveloperGuide:
+Provided Class Diagrams for the data package and Sequence Diagrams ON/OFF Commands.
+
+#### Review/mentoring contributions:
+
+I also actively take part in reviewing my teammates code through GitHub:
+* [Pull Request 1](https://github.com/AY2021S1-CS2113-T14-1/tp/pull/193)
+* [Pull Request 2](https://github.com/AY2021S1-CS2113-T14-1/tp/pull/203)
+
+In addition, we meetup and discuss regularly on the developments of SmartHomeBot through Zoom and other messaging platforms like WhatsApp and Telegram.
+
+#### Contributions beyond the project team:
+
+I also actively take part in other group's project development by reviewing their program for tutorials and PE dry runs.
+* [Bug Issue 1](https://github.com/leonlowzd/ped/issues/1)
+* [Bug Issue 2](https://github.com/nus-cs2113-AY2021S1/tp/pull/28)
diff --git a/docs/team/tanleewei.md b/docs/team/tanleewei.md
new file mode 100644
index 0000000000..5c39690b1e
--- /dev/null
+++ b/docs/team/tanleewei.md
@@ -0,0 +1,61 @@
+# Tan Lee Wei - Project Portfolio Page
+
+## Overview
+SmartHomeBot is a **desktop application that consolidates all home appliance’s control into a
+centralized system via a Command Line Interface (CLI)**. Even though the main target of the
+SmartHomeBot is disabled home users with mobility issues, it can be used by anyone that wants to have
+a bot to help in controlling household appliances but prefer typing than speaking to the bot. The main goal
+of this application is to help to make the life of the user easier and more convenient by allowing the user to add
+their household appliances into the SmartHomeBot, allowing the user to switch on and off their appliances through the
+application and also monitor their electrical power usage.
+
+### Summary of Contributions
+
+## Code Contributed
+
+Below is the link to view all the codes that I contributed to SmartHomeBot Project. Click on
+RepoSense to direct you to the page:
+
+* [RepoSense](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=TanLeeWei&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+#### Main Function implemented
+I am mainly responsible for the storage package and some of the data package for SmartHomeBot.
+
+1. LocationList: list of stored locations.
+2. StorageFile
+ 1. ReadStorageFile: Read the data is the .txt storage file back into the program.
+ 2. WriteStorageFile: Write the data in the program into the .txt storage file.
+
+##### Enhancement implemented
+I implemented the WriteStorageFile in such a way that each time the user entered a command, the program
+will automatically save the updates and overwrites all the data in the storage file with the new contents, so that
+this will prevent any lost of data even if the program crashes halfway.
+
+#### Contributions to UserGuide
+I have provided explanations and examples for some of the SmartHomeBot functions. I have also added some images as
+examples on how to use the application to give a better illustration on how to use the application to the users. After
+my team members and I have complete our parts of the UserGuide, we will come together to review the UserGuide
+to find out any mistakes we have made and parts we are lacking in the UserGuide.
+
+* [UserGuide](https://ay2021s1-cs2113-t14-1.github.io/tp/UserGuide.html)
+
+#### Contributions to DeveloperGuide
+I have done explanations and designs for the sequence and class diagrams of storage components. I have also done
+explanations and designs for the sequence diagrams of AddCommand and DeleteCommand. Refer to the link below to view
+the DeveloperGuide.
+
+* [DeveloperGuide](https://ay2021s1-cs2113-t14-1.github.io/tp/DeveloperGuide.html)
+
+#### Contributions to team-based tasks
+
+* Help to review teammates pull requests for any errors before their merge.
+* Provided feedbacks to UserGuide and DeveloperGuide when my teammates done their sections.
+* Meet up regularly in project discussion through zoom sessions and telegram group to update on our progress.
+* Provided suggestions and questions to improve the project during project meetings.
+
+#### Contributions beyond the project team
+I have also provided in other group's project development by reviewing the products during tutorials and PE dry runs.
+
+* [Bug Issue 1](https://github.com/TanLeeWei/ped/issues/4)
+* [Bug Issue 2](https://github.com/TanLeeWei/ped/issues/1)
+
diff --git a/docs/team/zongxian-ctrl.md b/docs/team/zongxian-ctrl.md
new file mode 100644
index 0000000000..03495997dd
--- /dev/null
+++ b/docs/team/zongxian-ctrl.md
@@ -0,0 +1,73 @@
+# Ong Zong Xian - Project Portfolio Page
+
+## Overview
+SmartHomeBot is a **desktop application that consolidates all home appliance’s control into a
+centralized system via a Command Line Interface (CLI)**. SmartHomeBot is our team project submission for
+**CS2113: Software Engineering & Object Oriented Programming** Module.
+
+### Summary of Contributions
+
+#### Code contributed:
+Below is the link to my code contribution for this project:
+* Code Contribution: [RepoSense](https://nus-cs2113-ay2021s1.github.io/tp-dashboard/#breakdown=true&search=zongxian-ctrl&sort=groupTitle&sortWithin=title&since=2020-09-27&timeframe=commit&mergegroup=&groupSelect=groupByRepos&checkedFileTypes=docs~functional-code~test-code~other)
+
+#### Main Function implemented:
+I am mainly responsible for the Parser class and some Commands the following commands for SmartHomeBot.
+
+**Logic**
+* `Parser`: Responsible for ensuring that all User input are parser correctly as well as acting
+as the first filter to detect any error in the user input to prevent further error in the program.
+* `CreateCommand`: Command to add new Location to SmartHomeBot.
+* `RemoveCommand`: Command to remove specified Location from SmartHomeBot.
+* `AddCommand`: Command to add a new Appliance to a certain location in SmartHomeBot.
+* `DeleteCommand`: Command to delete specified Appliance from SmartHomeBot.
+
+#### Enhancements implemented:
+
+Implemented the `Parser` to ensure that User entered the correct format for Commands into SmartHomeBot.
+Functions include:
+1. Ensuring that User enter the correct format as stated in User Guide.
+2. Ensuring that User does not give empty parameter or illegal parameter if the command requires it.
+3. Detecting any Illegal character such as `spaces` or `|` or `/` which might ensure in error of the CLI program.
+4. Implemented `StringUtils.replaceOnce` to prevent special character from ending the program, as Java String Library .replaceFirst
+only supports regex.
+* Implementation of Parser involved frequent updates from v1.0 to v2.1 as any changes to the implementation and functions
+of SmartHomeBot normally involve needing to parse the command differently to prevent bugs and error.
+
+Implemented the `CreateCommand` to make sure User does not create duplicate Location of the same name with existing Locations
+as well as Appliance name.
+
+Implemented the `RemoveCommand` to make sure User does not remove a Location that does not exist.
+As well as deleting appliances in the Location that is being removed as well.
+
+Implemented the `AddCommand` to make sure User add an Appliance with the type available specified in the UserGuide.
+Furthermore, making sure it is added to a Location that is available in SmartHomeBot with the name specified not being a duplicate.
+
+Implemented the `DeleteCommand` to make sure User does not delete an Appliance that does not exist.
+
+Minor enhancement: Wrote the logger setup to allow teammates to perform logging in their respective sections.
+
+#### Contribution to User Guide:
+
+1. I have written the documentation explaining on how to use the Commands available as well as the Format to ensure standardisation.
+2. I am also responsible for updating table for Command Summary in UserGuide and making sure the content in UserGuide are in order.
+
+#### Contribution to Developer Guide:
+1. Added UML Sequence Diagrams for Parser, CreateCommand and RemoveCommand.
+2. Wrote documentation for Parser, CreateCommand and RemoveCommand.
+
+#### Contributions to team-based tasks:
+* Set up Team repo's issue tracker and milestones for `v1.0`, `v2.0` and `v2.1`.
+* Some examples of providing feedback to team member's pull requests: e.g [#208](https://github.com/AY2021S1-CS2113-T14-1/tp/pull/208), [#210](https://github.com/AY2021S1-CS2113-T14-1/tp/pull/210)
+* In addition, meets up regularly with my team to update and discuss the developments of SmartHomeBot
+through Zoom, and our group personal Telegram group.
+
+#### Contributions beyond the project team:
+Provided feedback to other CS2113 project teams on the bug encounterd during the semester.
+Links below are some feedback to other project teams.
+
+1. [PE Dry Run](https://github.com/zongxian-ctrl/ped/issues)
+2. [Review DG of Peer Team #1](https://github.com/nus-cs2113-AY2021S1/tp/pull/131)
+3. [Review DG of Peer Team #1](https://github.com/nus-cs2113-AY2021S1/tp/pull/4)
+4. [Review Peer IP PRs #1](https://github.com/nus-cs2113-AY2021S1/ip/pull/28)
+5. [Review Peer IP PRs #2](https://github.com/nus-cs2113-AY2021S1/ip/pull/151)
diff --git a/src/main/java/resources/META-INF/MANIFEST.MF b/src/main/java/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..a7578479ee
--- /dev/null
+++ b/src/main/java/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: seedu.smarthomebot.Main
+
diff --git a/src/main/java/seedu/duke/Duke.java b/src/main/java/seedu/duke/Duke.java
deleted file mode 100644
index 5c74e68d59..0000000000
--- a/src/main/java/seedu/duke/Duke.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package seedu.duke;
-
-import java.util.Scanner;
-
-public class Duke {
- /**
- * Main entry-point for the java.duke.Duke application.
- */
- public static void main(String[] args) {
- String logo = " ____ _ \n"
- + "| _ \\ _ _| | _____ \n"
- + "| | | | | | | |/ / _ \\\n"
- + "| |_| | |_| | < __/\n"
- + "|____/ \\__,_|_|\\_\\___|\n";
- System.out.println("Hello from\n" + logo);
- System.out.println("What is your name?");
-
- Scanner in = new Scanner(System.in);
- System.out.println("Hello " + in.nextLine());
- }
-}
diff --git a/src/main/java/seedu/smarthomebot/Main.java b/src/main/java/seedu/smarthomebot/Main.java
new file mode 100644
index 0000000000..f2c9eb3619
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/Main.java
@@ -0,0 +1,120 @@
+package seedu.smarthomebot;
+
+import seedu.smarthomebot.logic.commands.Command;
+import seedu.smarthomebot.logic.commands.CommandResult;
+import seedu.smarthomebot.logic.commands.ExitCommand;
+import seedu.smarthomebot.logic.parser.Parser;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.storage.ReadStorageFile;
+import seedu.smarthomebot.storage.WriteStorageFile;
+import seedu.smarthomebot.ui.TextUi;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.logging.FileHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.logging.SimpleFormatter;
+
+//@@author Ang-Cheng-Jun
+
+//Solution below adapted from https://github.com/nus-cs2113-AY2021S1/personbook
+/**
+ * Entry point of the SmartHome application.
+ * Initializes the application and starts the interaction with the user.
+ */
+public class Main {
+
+ private TextUi ui = new TextUi();
+ private static final String FILE_PATH = "data/SmartHomeBot.txt";
+ private final ApplianceList applianceList = new ApplianceList();
+ private final LocationList locationList = new LocationList();
+ private final Parser parser = new Parser();
+ private WriteStorageFile writeFile = new WriteStorageFile(FILE_PATH, applianceList, locationList);
+ private ReadStorageFile readFile = new ReadStorageFile(FILE_PATH, applianceList, locationList);
+ private final Logger logger = Logger.getLogger("SmartHomeBotLogger");
+
+ public static void main(String[] args) {
+ new Main().run();
+ }
+
+ /**
+ * Runs the program until termination.
+ */
+ private void run() {
+ start();
+ runCommandLoopUntilExitCommand();
+ exit();
+ }
+
+ /**
+ * Initialises the import of data from the text file,
+ * and prints the Welcome message.
+ */
+ private void start() {
+ this.ui = new TextUi();
+ ui.showWelcomeMessage();
+ setupLogger();
+ readFile.execute();
+ }
+
+ /**
+ * Prints the Goodbye message and exits.
+ */
+ private void exit() {
+ ui.showGoodByeMessage();
+ System.exit(0);
+ }
+
+ /**
+ * Reads the user command and executes it, until the user issues the bye command.
+ */
+ private void runCommandLoopUntilExitCommand() {
+ Command command;
+ do {
+ String userCommandText = ui.getUserCommand();
+ command = parser.parseCommand(userCommandText);
+ CommandResult result = executeCommand(command);
+ writeFile.execute();
+ if (result != null) {
+ ui.printResultToUser(result);
+ }
+ } while (!ExitCommand.isExit(command));
+ }
+
+ /**
+ * Executes the user command and prints the result.
+ */
+ private CommandResult executeCommand(Command command) {
+ try {
+ command.setData(applianceList, locationList);
+ CommandResult result = command.execute();
+ return result;
+ } catch (Exception e) {
+ ui.printToUser(e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+
+ //@@author zongxian-ctrl
+ /**
+ * Creates the default logger with level and initialise log file.
+ */
+ private void setupLogger() {
+ File myObj = new File("./log");
+ logger.setUseParentHandlers(false);
+ logger.setLevel(Level.INFO);
+ try {
+ if (!myObj.exists()) {
+ myObj.mkdir();
+ }
+ FileHandler fileHandler = new FileHandler("log/SmartHomeBotLog.txt", false);
+ fileHandler.setFormatter(new SimpleFormatter());
+ logger.addHandler(fileHandler);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/smarthomebot/commons/Messages.java b/src/main/java/seedu/smarthomebot/commons/Messages.java
new file mode 100644
index 0000000000..d75467f59b
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/commons/Messages.java
@@ -0,0 +1,64 @@
+package seedu.smarthomebot.commons;
+
+/**
+ * Class for all the user visible messages.
+ */
+public class Messages {
+
+ public static final String LINE = "-".repeat(Math.max(0, 52)) + "\n";
+ public static final String DIVIDER = "=".repeat(Math.max(0, 52));
+ public static final String MESSAGE_WELCOME = "Welcome to your SmartHomeBot V2.1!";
+ public static final String MESSAGE_GOODBYE = "Good bye!";
+ public static final String MESSAGE_IMPORT = "Importing data........Completed!";
+ public static final String MESSAGE_EXPORT = "Exporting data........Completed!";
+ public static final String MESSAGE_APPLIANCE_TYPE_NOT_EXIST =
+ "Invalid appliance type is detected. Only aircon, fan, light and smartplug are accepted as type.";
+ public static final String MESSAGE_APPLIANCE_EXIST = "Appliance name already exists.";
+ public static final String MESSAGE_LOCATION_NOT_EXIST = "Location does not exist.";
+ public static final String MESSAGE_APPLIANCE_LOCATION_CONFLICT =
+ "Appliance name already exist in the location list.";
+ public static final String MESSAGE_TOTAL_POWER_USAGE = "\n\nTotal power consumption: ";
+ public static final String MESSAGE_LIST_LOCATIONS = "Here are the Location in your list:";
+ public static final String MESSAGE_LIST_APPLIANCES = "Here are the Appliances in your list:";
+ public static final String MESSAGE_POWER_USAGE = "Here are the recorded power usage consumption:";
+ public static final String MESSAGE_LIST_NO_LOCATIONS = "There is currently no Location in the list.";
+ public static final String MESSAGE_LIST_NO_APPLIANCES = "There is currently no Appliance in the list.";
+ public static final String MESSAGE_USAGE_RESET = "Previous recorded power usage has been reset!";
+ public static final String MESSAGE_INVALID_COMMAND_FORMAT = "Invalid Command Format";
+ public static final String MESSAGE_INVALID_ADD_COMMAND =
+ "Please follow this order, add NAME l/[LOCATION_NAME] w/[WATTS] t/[TYPE_OF_APPLIANCE]";
+ public static final String MESSAGE_INVALID_LIST_COMMAND =
+ "Please enter either 'list appliance' or 'list location' or 'list appliance l/LOCATION_NAME'";
+ public static final String MESSAGE_VALUE_NOT_NUMBER =
+ "Please enter a valid numerical value ranging from 1-9999 for the wattage.";
+ public static final String MESSAGE_PARAMETER_INVALID =
+ "Please enter a valid numerical value.";
+ public static final String MESSAGE_POWER_EXCEEDED =
+ "Appliance wattage is not supported. Please enter between 1 to 9999.";
+ public static final String MESSAGE_TIME_FORMAT_ERROR = "Time format is wrong.";
+ public static final String MESSAGE_APPLIANCE_PREVIOUSLY_ON = " is already ON. ";
+ public static final String MESSAGE_APPLIANCE_PREVIOUSLY_OFF = " is already OFF. ";
+ public static final String MESSAGE_NO_PARAMETER_IN_ON_BY_LOCATION =
+ "There should be no parameter for this command, please refer to 'help' command.";
+ public static final String MESSAGE_FILE_CORRUPTED = "Data file is corrupted, some data entry will not be entered.";
+ public static final String MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST =
+ "Appliance or Location does not exist in the list.";
+ public static final String MESSAGE_INVALID_TEMPERATURE_AC =
+ "Invalid Temperature is detected, ensure that it is within 16-30 degrees.\n"
+ + "Previous set temperature will be set. ";
+ public static final String MESSAGE_INVALID_FAN_SPEED =
+ "Invalid speed is detected, ensure that it is within 1-3 speed.\n"
+ + "Previous set speed will be set.";
+ public static final String MESSAGE_ILLEGAL_CHARACTER = "Illegal Character space or / or | detected in";
+ public static final String MESSAGE_EMPTY_PARAMETER =
+ "Empty Parameter detected! Please follow format and enter required parameters.";
+ public static final String MESSAGE_LOCATION_EXIST = "Location already exist";
+ public static final String MESSAGE_EXIT_ACKNOWLEDGEMENT =
+ "Exiting SmartHomeBot as requested, all Appliances are switched off.";
+ public static final String MESSAGE_FILE_DOES_NOT_EXIST = "Load File does not exist. No contents will be loaded.";
+ public static final String MESSAGE_WRITE_FILE_ERROR = "An error occurred while writing storage file.";
+ public static final String MESSAGE_FILE_CREATION_ERROR = "Something went wrong. Unable to create file.";
+ public static final String MESSAGE_CLEAR_FILE_ERROR = "Storage file does not exist";
+ public static final String MESSAGE_EMPTY_FILE = "The storage file is empty. No contents will be loaded.";
+
+}
diff --git a/src/main/java/seedu/smarthomebot/commons/exceptions/ApplianceNotFoundException.java b/src/main/java/seedu/smarthomebot/commons/exceptions/ApplianceNotFoundException.java
new file mode 100644
index 0000000000..c1bd8f93a4
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/commons/exceptions/ApplianceNotFoundException.java
@@ -0,0 +1,7 @@
+package seedu.smarthomebot.commons.exceptions;
+
+/**
+ * Signals an error when the user entered a appliance that does not exist in the ApplianceList.
+ */
+public class ApplianceNotFoundException extends Exception{
+}
diff --git a/src/main/java/seedu/smarthomebot/commons/exceptions/DuplicateDataException.java b/src/main/java/seedu/smarthomebot/commons/exceptions/DuplicateDataException.java
new file mode 100644
index 0000000000..5befb80017
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/commons/exceptions/DuplicateDataException.java
@@ -0,0 +1,7 @@
+package seedu.smarthomebot.commons.exceptions;
+
+/**
+ * Signals an error when the user enter a duplicate data.
+ */
+public class DuplicateDataException extends Exception {
+}
diff --git a/src/main/java/seedu/smarthomebot/commons/exceptions/InvalidLocationException.java b/src/main/java/seedu/smarthomebot/commons/exceptions/InvalidLocationException.java
new file mode 100644
index 0000000000..2bdf2973c3
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/commons/exceptions/InvalidLocationException.java
@@ -0,0 +1,7 @@
+package seedu.smarthomebot.commons.exceptions;
+
+/**
+ * Signals an error when the user enter a location that does not exist or wrong format.
+ */
+public class InvalidLocationException extends Exception{
+}
diff --git a/src/main/java/seedu/smarthomebot/commons/exceptions/InvalidNumericalValueException.java b/src/main/java/seedu/smarthomebot/commons/exceptions/InvalidNumericalValueException.java
new file mode 100644
index 0000000000..65579e096a
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/commons/exceptions/InvalidNumericalValueException.java
@@ -0,0 +1,7 @@
+package seedu.smarthomebot.commons.exceptions;
+
+/**
+ * Signals an error when the user entered an non-numerical value as power input.
+ */
+public class InvalidNumericalValueException extends Exception{
+}
diff --git a/src/main/java/seedu/smarthomebot/commons/exceptions/NoApplianceInLocationException.java b/src/main/java/seedu/smarthomebot/commons/exceptions/NoApplianceInLocationException.java
new file mode 100644
index 0000000000..f7f8cd82e9
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/commons/exceptions/NoApplianceInLocationException.java
@@ -0,0 +1,7 @@
+package seedu.smarthomebot.commons.exceptions;
+
+/**
+ * Signals an error when the user calls list appliance command in a location with no appliance.
+ */
+public class NoApplianceInLocationException extends Exception {
+}
diff --git a/src/main/java/seedu/smarthomebot/data/appliance/Appliance.java b/src/main/java/seedu/smarthomebot/data/appliance/Appliance.java
new file mode 100644
index 0000000000..699681b89c
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/data/appliance/Appliance.java
@@ -0,0 +1,202 @@
+package seedu.smarthomebot.data.appliance;
+
+import seedu.smarthomebot.commons.exceptions.InvalidNumericalValueException;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+//@@author leonlowzd
+
+/**
+ * Abstract Class representing the appliances for SmartHomeBot.
+ */
+public abstract class Appliance {
+ private static final String ON = "ON";
+ private static final String OFF = "OFF";
+ private static LocationList locationList;
+ protected String name;
+ protected String location;
+ protected String wattage;
+ protected Power appliancePower;
+
+ /**
+ * Constructor for Appliance.
+ *
+ * @param name name of appliance.
+ * @param location location of appliance.
+ * @param wattage wattage of appliance.
+ * @param locationList locations available in SmartHomeBot, appliance will only be created:
+ * Appliance will only be created when:
+ * 1. location inputted is present in the locationList.
+ * 2. User inputted name does not exist in locationList.
+ * @throws InvalidApplianceNameException When name already exists in LocationList.
+ * @throws LocationNotFoundException When Location does not exist in LocationList.
+ */
+ public Appliance(String name, String location, String wattage, LocationList locationList)
+ throws LocationNotFoundException, InvalidApplianceNameException {
+
+ this.locationList = locationList;
+ if (locationList.isLocationCreated(location) && (!locationList.isLocationCreated(name))) {
+ this.name = name;
+ this.location = location;
+ this.wattage = wattage;
+ appliancePower = new Power(wattage);
+ } else {
+ if (locationList.isLocationCreated(name)) {
+ throw new InvalidApplianceNameException();
+ } else {
+ throw new LocationNotFoundException();
+ }
+ }
+
+ }
+
+ /**
+ * Converts String value into integer.
+ *
+ * @return the parameter in integer.
+ */
+ private static int convertParameterToInt(String parameter) throws InvalidNumericalValueException {
+ try {
+ return Integer.parseInt(parameter);
+ } catch (NumberFormatException e) {
+ throw new InvalidNumericalValueException();
+ }
+
+ }
+
+ /**
+ * Sets the status of Appliance to on.
+ *
+ * @return the outcome of the operation.
+ */
+ public boolean switchOn() {
+ return appliancePower.onAppliance();
+ }
+
+ /**
+ * Sets the status of Appliance to off.
+ *
+ * @return the outcome of the operation.
+ */
+ public boolean switchOff() {
+ return appliancePower.offAppliance();
+ }
+
+ public void resetPowerUsage() {
+ appliancePower.resetPower();
+ }
+
+ /**
+ * Gets the status of the appliance.
+ *
+ * @return the status of the appliance.
+ */
+ public String getStatus() {
+ return (appliancePower.getStatus() ? ON : OFF);
+ }
+
+ /**
+ * Compute the power consumption of the appliance.
+ *
+ * @return the power consumption of the appliance in double.
+ */
+ public double getPowerInDouble() {
+ return appliancePower.getPower();
+ }
+
+ /**
+ * Gets the power consumption of the appliance in String.
+ *
+ * @return the power consumption of the appliance in String.
+ */
+ public String getPowerInString() {
+ return appliancePower.toString();
+ }
+
+ /**
+ * Recomputes the power consumption of the appliance.
+ */
+ public void loadDataFromFile(String powerConsumption) {
+ appliancePower.loadDataFromFile(Double.parseDouble(powerConsumption));
+ }
+
+ /**
+ * Gets the power rating of the appliance in String.
+ *
+ * @return the power rating of the appliance in String.
+ */
+ public String getWattage() {
+ return wattage;
+ }
+
+ /**
+ * Method to gets the name of appliance.
+ *
+ * @return the type of the appliance in String.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Method to gets the location of appliance.
+ *
+ * @return the location of the appliance in String.
+ */
+ public String getLocation() {
+ return location;
+ }
+
+ /**
+ * Abstract method to gets the type of appliance.
+ *
+ * @return the type of the appliance in String.
+ */
+ public abstract String getType();
+
+ /**
+ * Abstract method to gets the parameter of appliance.
+ *
+ * @return the type of the appliance in String.
+ */
+ public abstract String getParameter(boolean isList);
+
+ /**
+ * Method to gets the printout for the appliance.
+ *
+ * @return the printout for appliance.
+ */
+ public String toString() {
+ return getName() + "(" + getWattage() + "W)" + ", located at " + getLocation() + " ";
+ }
+
+ /**
+ * Method to save the printout for the appliance to text file.
+ *
+ * @return the printout for appliance.
+ */
+ public String writeFileFormat() {
+ return location + "|" + name + "|" + wattage + "|" + getType()
+ + "|" + getPowerInString() + "|" + getParameter(false);
+ }
+
+ /**
+ * Method to check validity of inputted parameter.
+ *
+ * @param lowerBound parameter must be larger than lowerBound.
+ * @param upperBound parameter must be smaller than upperBound.
+ * @return true if parameter is valid.
+ */
+ protected boolean isParameterValid(String parameter, int lowerBound, int upperBound) {
+ try {
+ int parameterValue = convertParameterToInt(parameter);
+ if ((parameterValue < upperBound) && (parameterValue > lowerBound)) {
+ return true;
+ }
+ } catch (InvalidNumericalValueException e) {
+ return false;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/seedu/smarthomebot/data/appliance/ApplianceList.java b/src/main/java/seedu/smarthomebot/data/appliance/ApplianceList.java
new file mode 100644
index 0000000000..9b420e01c7
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/data/appliance/ApplianceList.java
@@ -0,0 +1,117 @@
+package seedu.smarthomebot.data.appliance;
+
+import seedu.smarthomebot.commons.exceptions.ApplianceNotFoundException;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+
+import java.util.ArrayList;
+
+//@@author leonlowzd
+
+/**
+ * Represents the Appliances of SmartHomeBot.
+ */
+public class ApplianceList {
+
+ private static ArrayList applianceList;
+
+ /**
+ * Constructor of ApplianceList.
+ */
+ public ApplianceList() {
+ applianceList = new ArrayList<>();
+ }
+
+ /**
+ * Method to add a new Appliance to the ApplianceList.
+ *
+ * @param appliance Appliance to add.
+ * @throws DuplicateDataException Appliance name is already in the List.
+ */
+ public void addAppliance(Appliance appliance) throws DuplicateDataException {
+ if (!isApplianceExist(appliance.getName())) {
+ applianceList.add(appliance);
+ } else {
+ throw new DuplicateDataException();
+ }
+ }
+
+ /**
+ * Method to delete a Appliance from the ApplianceList.
+ *
+ * @param userEnteredName Appliance to remove.
+ * @throws ApplianceNotFoundException When keyed name is not found in ApplianceList.
+ */
+ public Appliance deleteAppliance(String userEnteredName) throws ApplianceNotFoundException {
+ for (Appliance appliance : getAllAppliance()) {
+ if (appliance.getName().equals(userEnteredName)) {
+ applianceList.remove(appliance);
+ return appliance;
+ }
+ }
+ throw new ApplianceNotFoundException();
+ }
+
+ /**
+ * Method to retrieve the Appliance from the ApplianceList.
+ *
+ * @param index Appliance to retrieve.
+ */
+ public Appliance getAppliance(int index) {
+ return applianceList.get(index);
+ }
+
+ /**
+ * Method to retrieve all of the Appliances from the ApplianceList.
+ *
+ * @return the full list of the Appliances.
+ */
+ public ArrayList getAllAppliance() {
+ return applianceList;
+ }
+
+ /**
+ * Method to check if the Appliance exists in the ApplianceList.
+ *
+ * @param toAddApplianceName Appliance to check.
+ */
+ public Boolean isApplianceExist(String toAddApplianceName) {
+ boolean isExist = false;
+ for (Appliance a : applianceList) {
+ if (a.getName().equals(toAddApplianceName)) {
+ isExist = true;
+ break;
+ }
+ }
+ return isExist;
+ }
+
+ /**
+ * Method to remove Appliances located in the user selected location in the ApplianceList.
+ *
+ * @param usersEnteredLocation Appliance to check.
+ * @throws ApplianceNotFoundException When keyed name is not found in ApplianceList.
+ */
+ public void deleteByLocation(String usersEnteredLocation) throws ApplianceNotFoundException {
+ for (int x = getAllAppliance().size() - 1; x >= 0; x--) {
+ if (getAppliance(x).getLocation().equals(usersEnteredLocation)) {
+ deleteAppliance((getAppliance(x).getName()));
+ }
+ }
+ }
+
+ /**
+ * Method to return the index of the Appliance from the input argument.
+ *
+ * @param argument Name of Appliance to find in the List.
+ * @throws ApplianceNotFoundException When keyed name is not found in ApplianceList.
+ */
+ public int getApplianceIndex(String argument)
+ throws ApplianceNotFoundException {
+ for (Appliance appliance : applianceList) {
+ if (appliance.getName().equals((argument))) {
+ return applianceList.indexOf(appliance);
+ }
+ }
+ throw new ApplianceNotFoundException();
+ }
+}
diff --git a/src/main/java/seedu/smarthomebot/data/appliance/Power.java b/src/main/java/seedu/smarthomebot/data/appliance/Power.java
new file mode 100644
index 0000000000..dddbd46de2
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/data/appliance/Power.java
@@ -0,0 +1,189 @@
+package seedu.smarthomebot.data.appliance;
+
+import seedu.smarthomebot.ui.TextUi;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.Locale;
+
+import static seedu.smarthomebot.commons.Messages.LINE;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_TIME_FORMAT_ERROR;
+
+//@@author fanceso
+
+/**
+ * Class representing the power consumption of appliances.
+ */
+public class Power {
+
+ private static final String DATE_TIME_FORMAT = "dd/MM/yyyy-HH:mm:ss";
+ private final int wattage;
+ private String offTime;
+ private String onTime;
+ private Boolean status;
+ private double powerUsed;
+ private double totalPowerConsumption;
+
+ /**
+ * Constructor for Power Class.
+ *
+ * @param wattage Wattage of appliance.
+ */
+ public Power(String wattage) {
+ this.wattage = Integer.parseInt(wattage);
+ this.status = false;
+ this.totalPowerConsumption = 0.00;
+ }
+
+ /**
+ * Gets the status of the appliance.
+ *
+ * @return the status of the appliance in Boolean.
+ */
+ public Boolean getStatus() {
+ return status;
+ }
+
+ /**
+ * Appliance only can be switched on if it was 'off' previously.
+ *
+ * @return true if appliance has not been turned on before.
+ */
+ public boolean onAppliance() {
+ if (!status) {
+ status = true;
+ onTime = getCurrentTime();
+ assert !onTime.isEmpty() : "onTime must not accept empty value";
+ return true;
+ } else {
+ // Appliance has been turned ON previously
+ return false;
+ }
+ }
+
+ /**
+ * Appliance only can be switched off if it was 'on' previously.
+ * Compute the total power consumption once appliance is off.
+ *
+ * @return true if appliance has not been turned off before.
+ */
+ public boolean offAppliance() {
+ if (status) {
+ status = false;
+ offTime = getCurrentTime();
+ computeTotalPower();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Reset all the appliance power usage and the total power consumption.
+ */
+ public void resetPower() {
+ powerUsed = 0.00;
+ totalPowerConsumption = 0.00;
+ }
+
+ /**
+ * Gets the power consumption of appliance.
+ *
+ * @return the power consumption in double.
+ */
+ public double getPower() {
+ computeTotalPower();
+ if (totalPowerConsumption < 0) {
+ return 0;
+ }
+ return totalPowerConsumption;
+ }
+
+ /**
+ * Gets the current system time from local machine.
+ *
+ * @return formatted current time with given format "dd/MM/yyyy-HH:mm:ss".
+ */
+ private String getCurrentTime() {
+ LocalDateTime currentTime;
+ DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT, Locale.ENGLISH);
+ currentTime = LocalDateTime.now();
+ return dateTimeFormatter.format(currentTime);
+ }
+
+ /**
+ * Computes power consumption from loaded file.
+ *
+ * @param powerConsumption of each appliance used within a day
+ */
+ public void loadDataFromFile(double powerConsumption) {
+ powerUsed = powerConsumption;
+ totalPowerConsumption += powerUsed;
+ }
+
+ /**
+ * Calculate time used while is appliance on.
+ */
+ private double calculateTimeUsed() throws ParseException {
+ double totalHours;
+ SimpleDateFormat timeFormat = new SimpleDateFormat(DATE_TIME_FORMAT, Locale.ENGLISH);
+ Date onTimeValue;
+ Date offTimeValue;
+ double timeUsed = 0;
+
+ if (onTime != null) {
+ assert !onTime.isEmpty() : "onTime must not accept empty value";
+ onTimeValue = timeFormat.parse(onTime);
+ if (!status) {
+ offTimeValue = timeFormat.parse(offTime);
+ timeUsed = offTimeValue.getTime() - onTimeValue.getTime();
+ assert timeUsed >= 0 : "System Time is not correct! " + timeUsed;
+ onTime = offTime;
+ } else {
+ Date currentUsedTime = timeFormat.parse(getCurrentTime());
+ timeUsed = currentUsedTime.getTime() - onTimeValue.getTime();
+ onTime = getCurrentTime();
+ }
+ }
+
+ totalHours = timeUsed / (1000 * 60 * 60);
+ return totalHours;
+ }
+
+ /**
+ * Computes power of Appliance to latest instance of duration where Appliance is on.
+ */
+ private void computePower() {
+ try {
+ double totalTimeUsed = calculateTimeUsed();
+ // Convert power unit to kWh
+ powerUsed = totalTimeUsed * wattage / 1000.00;
+ } catch (ParseException e) {
+ TextUi ui = new TextUi();
+ ui.printToUser(LINE + MESSAGE_TIME_FORMAT_ERROR);
+ }
+ assert powerUsed >= 0 : "Power usage cannot be negative! " + powerUsed;
+ }
+
+ /**
+ * Increment the total Power consumption of the Appliance.
+ */
+ private void computeTotalPower() {
+ computePower();
+ totalPowerConsumption += Math.round(powerUsed * 100.0) / 100.0;
+ assert totalPowerConsumption >= 0 : "totalPowerConsumption cannot be negative";
+ }
+
+ /**
+ * Gets the power consumption in String.
+ *
+ * @return the power consumption with only 2 decimal places in String.
+ */
+ public String toString() {
+ return String.format("%.2f", totalPowerConsumption);
+ }
+
+}
diff --git a/src/main/java/seedu/smarthomebot/data/appliance/type/AirConditioner.java b/src/main/java/seedu/smarthomebot/data/appliance/type/AirConditioner.java
new file mode 100644
index 0000000000..583cb7ef20
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/data/appliance/type/AirConditioner.java
@@ -0,0 +1,108 @@
+package seedu.smarthomebot.data.appliance.type;
+
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+//@@author leonlowzd
+
+/**
+ * Represents Air Conditioner type extended from Appliance.
+ */
+public class AirConditioner extends Appliance {
+
+ public static final String TYPE_WORD = "aircon";
+ private static final int LOWER_BOUND = 15;
+ private static final int UPPER_BOUND = 31;
+ private String temperature;
+
+ /**
+ * Constructor for Air Conditioner type.
+ *
+ * @param name name of appliance.
+ * @param location location of appliance.
+ * @param wattage wattage of appliance.
+ * @param locationList locations available in SmartHomeBot, appliance will only be created:
+ * Appliance will only be created when:
+ * 1. location inputted is present in the locationList.
+ * 2. User inputted name does not exist in locationList.
+ * @throws InvalidApplianceNameException When name already exists in LocationList.
+ * @throws LocationNotFoundException When Location does not exist in LocationList.
+ */
+ public AirConditioner(String name, String location, String wattage, LocationList locationList)
+ throws InvalidApplianceNameException, LocationNotFoundException {
+ super(name, location, wattage, locationList);
+ this.temperature = "25";
+ }
+
+ /**
+ * Method to return the set temperature of the Air conditioner.
+ *
+ * @return the set set temperature of the appliance in String.
+ */
+ @Override
+ public String getParameter(boolean isList) {
+ if (isList) {
+ return String.format("%s Degrees", getParameter(false));
+ } else {
+ return temperature;
+ }
+ }
+
+
+ /**
+ * Method to set the temperature of appliance from user text file.
+ *
+ * @param loadedTemperature temperature to set.
+ */
+ public void getTemperatureFromLoadFile(String loadedTemperature) {
+ setTemperature(loadedTemperature);
+ }
+
+ /**
+ * Method to set the temperature of appliance from user input.
+ *
+ * @param temperature temperature to set.
+ * @return the corresponding printout message after setting temperature in String.
+ */
+ public boolean setTemperature(String temperature) {
+ boolean isSuccess = true;
+ if (temperature.isEmpty()) {
+ // default temperature will be set.
+ } else if (isParameterValid(temperature, LOWER_BOUND, UPPER_BOUND)) {
+ // user input speed will be set.
+ this.temperature = temperature;
+ } else {
+ // user inputs an invalid temperature.
+ isSuccess = false;
+ }
+ return isSuccess;
+ }
+
+ /**
+ * Method to return the type of appliance.
+ *
+ * @return the type of appliance in String.
+ */
+ public String getType() {
+ return TYPE_WORD;
+ }
+
+ /**
+ * Method to return the full details of the appliance.
+ *
+ * @return the full details of the appliance in String.
+ */
+ public String toString() {
+ String temperatureStatement;
+ if (appliancePower.getStatus()) {
+ temperatureStatement = "@ " + getParameter(true);
+ } else {
+ temperatureStatement = "";
+ }
+
+ return super.toString() + temperatureStatement;
+ }
+
+}
diff --git a/src/main/java/seedu/smarthomebot/data/appliance/type/Fan.java b/src/main/java/seedu/smarthomebot/data/appliance/type/Fan.java
new file mode 100644
index 0000000000..d3e1ff3c90
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/data/appliance/type/Fan.java
@@ -0,0 +1,107 @@
+package seedu.smarthomebot.data.appliance.type;
+
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+//@@author leonlowzd
+
+/**
+ * Represents Fan type extended from Appliance.
+ */
+public class Fan extends Appliance {
+
+ public static final String TYPE_WORD = "fan";
+ private static final int LOWER_BOUND = 0;
+ private static final int UPPER_BOUND = 4;
+ private String speed;
+
+ /**
+ * Constructor for Fan type.
+ *
+ * @param name name of appliance.
+ * @param location location of appliance.
+ * @param wattage wattage of appliance.
+ * @param locationList locations available in SmartHomeBot, appliance will only be created:
+ * Appliance will only be created when:
+ * 1. location inputted is present in the locationList.
+ * 2. User inputted name does not exist in locationList.
+ * @throws InvalidApplianceNameException When name already exists in LocationList.
+ * @throws LocationNotFoundException When Location does not exist in LocationList.
+ */
+ public Fan(String name, String location, String wattage, LocationList locationList)
+ throws InvalidApplianceNameException, LocationNotFoundException {
+ super(name, location, wattage, locationList);
+ this.speed = "1";
+ }
+
+ /**
+ * Method to return the set speed of the Fan.
+ *
+ * @return the set set speed of the appliance in String.
+ */
+ @Override
+ public String getParameter(boolean isList) {
+ if (isList) {
+ return "Speed " + getParameter(false);
+ } else {
+ return speed;
+ }
+ }
+
+ /**
+ * Method to set the speed of appliance from user text file.
+ *
+ * @param loadedSpeed speed to set.
+ */
+ public void getSpeedFromLoadFile(String loadedSpeed) {
+ setSpeed(loadedSpeed);
+ }
+
+ /**
+ * Method to set the temperature of appliance from user input.
+ *
+ * @param speed speed to set.
+ * @return the corresponding printout message after setting speed in String.
+ */
+ public boolean setSpeed(String speed) {
+ boolean isSuccess = true;
+ if (speed.isEmpty()) {
+ // default speed will be set.
+ } else if (isParameterValid(speed, LOWER_BOUND, UPPER_BOUND)) {
+ // user input speed will be set.
+ this.speed = speed;
+ } else {
+ // user inputs an invalid speed.
+ isSuccess = false;
+ }
+ return isSuccess;
+ }
+
+ /**
+ * Method to return the type of appliance.
+ *
+ * @return the type of appliance in String.
+ */
+ public String getType() {
+ return TYPE_WORD;
+ }
+
+ /**
+ * Method to return the full details of the appliance.
+ *
+ * @return the full details of the appliance in String.
+ */
+ @Override
+ public String toString() {
+ String speedStatement;
+ if (appliancePower.getStatus()) {
+ speedStatement = "@ " + getParameter(true);
+ } else {
+ speedStatement = "";
+ }
+ return super.toString() + speedStatement;
+ }
+
+}
diff --git a/src/main/java/seedu/smarthomebot/data/appliance/type/Lights.java b/src/main/java/seedu/smarthomebot/data/appliance/type/Lights.java
new file mode 100644
index 0000000000..7a6a3057df
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/data/appliance/type/Lights.java
@@ -0,0 +1,54 @@
+package seedu.smarthomebot.data.appliance.type;
+
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+//@@author leonlowzd
+
+/**
+ * Represents Lights type extended from Appliance.
+ */
+public class Lights extends Appliance {
+
+ public static final String TYPE_WORD = "light";
+
+ /**
+ * Constructor for light type.
+ *
+ * @param name name of appliance.
+ * @param location location of appliance.
+ * @param wattage wattage of appliance.
+ * @param locationList locations available in SmartHomeBot, appliance will only be created:
+ * Appliance will only be created when:
+ * 1. location inputted is present in the locationList.
+ * 2. User inputted name does not exist in locationList.
+ * @throws InvalidApplianceNameException When name already exists in LocationList.
+ * @throws LocationNotFoundException When Location does not exist in LocationList.
+ */
+ public Lights(String name, String location, String wattage, LocationList locationList)
+ throws InvalidApplianceNameException, LocationNotFoundException {
+ super(name, location, wattage, locationList);
+ }
+
+ /**
+ * Method to return the type of appliance.
+ *
+ * @return the type of appliance in String.
+ */
+ public String getType() {
+ return TYPE_WORD;
+ }
+
+ /**
+ * Method to return the set temperature of the Air conditioner.
+ *
+ * @return the set set temperature of the appliance in String.
+ */
+ public String getParameter(boolean isList) {
+ return "None";
+ }
+
+
+}
diff --git a/src/main/java/seedu/smarthomebot/data/appliance/type/SmartPlug.java b/src/main/java/seedu/smarthomebot/data/appliance/type/SmartPlug.java
new file mode 100644
index 0000000000..2a24dcb636
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/data/appliance/type/SmartPlug.java
@@ -0,0 +1,55 @@
+package seedu.smarthomebot.data.appliance.type;
+
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+//@@author leonlowzd
+
+/**
+ * Represents SmartPlug type extended from Appliance.
+ */
+public class SmartPlug extends Appliance {
+
+ public static final String TYPE_WORD = "smartplug";
+
+ /**
+ * Constructor for SmartPlug type.
+ *
+ * @param name name of appliance.
+ * @param location location of appliance.
+ * @param wattage wattage of appliance.
+ * @param locationList locations available in SmartHomeBot, appliance will only be created:
+ * Appliance will only be created when:
+ * 1. location inputted is present in the locationList.
+ * 2. User inputted name does not exist in locationList.
+ * @throws InvalidApplianceNameException When name already exists in LocationList.
+ * @throws LocationNotFoundException When Location does not exist in LocationList.
+ */
+ public SmartPlug(String name, String location, String wattage, LocationList locationList)
+ throws InvalidApplianceNameException, LocationNotFoundException {
+ super(name, location, wattage, locationList);
+ }
+
+ /**
+ * Returns the type of appliance.
+ *
+ * @return the type of appliance in String.
+ */
+ public String getType() {
+ return TYPE_WORD;
+ }
+
+ /**
+ * Returns the set temperature of the Air conditioner.
+ *
+ * @return the set set temperature of the appliance in String.
+ */
+ @Override
+ public String getParameter(boolean isList) {
+ return "None";
+ }
+
+
+}
diff --git a/src/main/java/seedu/smarthomebot/data/location/LocationList.java b/src/main/java/seedu/smarthomebot/data/location/LocationList.java
new file mode 100644
index 0000000000..6b683d4400
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/data/location/LocationList.java
@@ -0,0 +1,110 @@
+package seedu.smarthomebot.data.location;
+
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.commons.exceptions.InvalidLocationException;
+
+import java.util.ArrayList;
+
+//@@author TanLeeWei
+
+/**
+ * Represents the locations in SmartHomeBot.
+ */
+public class LocationList {
+
+ private static ArrayList locationList;
+
+ public LocationList() {
+ locationList = new ArrayList<>();
+ }
+
+ /**
+ * Creating new location if is not existed.
+ *
+ * @param location used to be added into the location list.
+ */
+ public void addLocation(String location) throws DuplicateDataException {
+ // create location from Appliance
+ if (!isLocationCreated(location)) {
+ locationList.add(location);
+ } else {
+ throw new DuplicateDataException();
+ }
+ }
+
+ /**
+ * Removing selected location with user input.
+ *
+ * @param location used to be removed from the location list.
+ */
+ public void removeLocation(String location) throws InvalidLocationException {
+ if (!(isLocationCreated(location))) {
+ throw new InvalidLocationException();
+ } else {
+ int removeIndex = getRemoveLocationIndex(location);
+ locationList.remove(removeIndex);
+ }
+ }
+
+ /**
+ * Returns true if location string is not found.
+ *
+ * @param toCheckLocation used to identify the display index.
+ * @return isValid true if location is not found in list.
+ */
+ public boolean isLocationCreated(String toCheckLocation) {
+ boolean isValid = false;
+ for (String location : locationList) {
+ if (location.equals(toCheckLocation)) {
+ isValid = true;
+ break;
+ }
+ }
+ return isValid;
+ }
+
+ /**
+ * Returns list of Location stored SmartHomeBot.
+ *
+ * @return list of Location in SmartHomeBot in ArrayList String.
+ */
+ public ArrayList getAllLocations() {
+ return locationList;
+ }
+
+ /**
+ * Returns true if location string is not found.
+ *
+ * @return list of Location in SmartHomeBot.
+ */
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (String location : locationList) {
+ sb.append(location);
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns the index of selected Location to remove.
+ *
+ * @param toRemoveLocation name of Location to remove.
+ * @return the index of selected location in integer, if integer is not found, method will return -1.
+ */
+ private int getRemoveLocationIndex(String toRemoveLocation) {
+ int removeIndex = -1;
+ int locationIndex = 0;
+ for (String location : locationList) {
+ if (location.equals(toRemoveLocation)) {
+ removeIndex = locationIndex;
+ break;
+ } else {
+ locationIndex++;
+ }
+ }
+ return removeIndex;
+ }
+
+
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/AddCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/AddCommand.java
new file mode 100644
index 0000000000..e1d597d3c3
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/AddCommand.java
@@ -0,0 +1,95 @@
+package seedu.smarthomebot.logic.commands;
+
+import seedu.smarthomebot.data.appliance.type.AirConditioner;
+import seedu.smarthomebot.data.appliance.type.Fan;
+import seedu.smarthomebot.data.appliance.type.Lights;
+import seedu.smarthomebot.data.appliance.type.SmartPlug;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+import java.util.logging.Level;
+
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_EXIST;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_TYPE_NOT_EXIST;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LOCATION_NOT_EXIST;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_LOCATION_CONFLICT;
+
+//@@author zongxian-ctrl
+
+/**
+ * Represent the command for adding an appliance to the ApplianceList.
+ */
+public class AddCommand extends Command {
+
+ public static final String COMMAND_WORD = "add";
+ public static final String MESSAGE_USAGE = "Add Appliance: " + COMMAND_WORD
+ + " [APPLIANCE_NAME] l/[LOCATION_NAME] w/[WATTAGE] t/[TYPE_OF_APPLIANCE]";
+
+ private final String name;
+ private final String location;
+ private final String wattage;
+ private final String type;
+
+ /**
+ * Constructor for AddCommand.
+ *
+ * @param name name of Appliance to create.
+ * @param location location the Appliance will be placed.
+ * @param wattage wattage power rating of Appliance.
+ * @param type type of Appliance.
+ */
+ public AddCommand(String name, String location, String wattage, String type) {
+ assert !name.isEmpty() : "AddCommand must not accept empty name";
+ assert !location.isEmpty() : "AddCommand must not accept empty location";
+ assert !wattage.isEmpty() : "AddCommand must not accept empty wattage";
+ assert !type.isEmpty() : "AddCommand must not accept empty type";
+ this.name = name;
+ this.location = location;
+ this.wattage = wattage;
+ this.type = type.toLowerCase();
+ }
+
+ /**
+ * Executing the AddCommand.
+ */
+ @Override
+ public CommandResult execute() {
+ try {
+ switch (this.type) {
+ case Fan.TYPE_WORD:
+ Fan fan = new Fan(name, location, wattage, locationList);
+ applianceList.addAppliance(fan);
+ commandLogger.log(Level.INFO, "ADDING" + fan.toString());
+ return new CommandResult("ADDING " + fan.toString() + "......ADDED!");
+ case AirConditioner.TYPE_WORD:
+ AirConditioner ac = new AirConditioner(name, location, wattage, locationList);
+ applianceList.addAppliance(ac);
+ commandLogger.log(Level.INFO, "ADDING" + ac.toString());
+ return new CommandResult("ADDING " + ac.toString() + "......ADDED!");
+ case Lights.TYPE_WORD:
+ Lights light = new Lights(name, location, wattage, locationList);
+ applianceList.addAppliance(light);
+ commandLogger.log(Level.INFO, "ADDING" + light.toString());
+ return new CommandResult("ADDING " + light.toString() + "......ADDED!");
+ case SmartPlug.TYPE_WORD:
+ SmartPlug smartPlug = new SmartPlug(name, location, wattage, locationList);
+ applianceList.addAppliance(smartPlug);
+ commandLogger.log(Level.INFO, "ADDING" + smartPlug.toString());
+ return new CommandResult("ADDING " + smartPlug.toString() + "......ADDED!");
+ default:
+ commandLogger.log(Level.WARNING, MESSAGE_APPLIANCE_TYPE_NOT_EXIST);
+ return new CommandResult(MESSAGE_APPLIANCE_TYPE_NOT_EXIST);
+ }
+ } catch (DuplicateDataException e) {
+ commandLogger.log(Level.WARNING, MESSAGE_APPLIANCE_EXIST);
+ return new CommandResult(MESSAGE_APPLIANCE_EXIST);
+ } catch (LocationNotFoundException e) {
+ commandLogger.log(Level.WARNING, MESSAGE_LOCATION_NOT_EXIST);
+ return new CommandResult(MESSAGE_LOCATION_NOT_EXIST);
+ } catch (InvalidApplianceNameException e) {
+ commandLogger.log(Level.WARNING, MESSAGE_APPLIANCE_LOCATION_CONFLICT);
+ return new CommandResult(MESSAGE_APPLIANCE_LOCATION_CONFLICT);
+ }
+ }
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/Command.java b/src/main/java/seedu/smarthomebot/logic/commands/Command.java
new file mode 100644
index 0000000000..93b153c8a3
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/Command.java
@@ -0,0 +1,57 @@
+package seedu.smarthomebot.logic.commands;
+
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.location.LocationList;
+
+import java.util.logging.Logger;
+
+//@@author zongxian-ctrl
+
+/**
+ * Represent the parent of all command types.
+ */
+public abstract class Command {
+
+ protected ApplianceList applianceList;
+ protected LocationList locationList;
+ protected int maxNameLength = 0;
+ protected int maxLocationLength = 0;
+ public static Logger commandLogger = Logger.getLogger("SmartHomeBotLogger");
+
+ protected Command() {
+ }
+
+ /**
+ * Passes the ApplianceList and LocationList to allow Command classes to use.
+ *
+ * @param applianceList stores the appliances in SmartHomeBot
+ * @param locationList stores the locations in SmartHomeBot
+ */
+ public void setData(ApplianceList applianceList, LocationList locationList) {
+ this.applianceList = applianceList;
+ this.locationList = locationList;
+ }
+
+ //@@author fanceso
+
+ /**
+ * Computing the longest length of name and location in the appliance class.
+ */
+ protected void autoFormattingStringIndex() {
+ for (Appliance a : applianceList.getAllAppliance()) {
+ if (a.getName().length() > maxNameLength) {
+ maxNameLength = a.getName().length();
+ }
+ if (a.getLocation().length() > maxLocationLength) {
+ maxLocationLength = a.getLocation().length();
+ }
+ }
+ }
+
+ /**
+ * Abstract Method for executing Command.
+ */
+ public abstract CommandResult execute();
+
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/CommandResult.java b/src/main/java/seedu/smarthomebot/logic/commands/CommandResult.java
new file mode 100644
index 0000000000..cfb2e1baee
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/CommandResult.java
@@ -0,0 +1,22 @@
+package seedu.smarthomebot.logic.commands;
+
+//@@author Ang_Cheng_Jun
+
+/**
+ * Represents the result of a command execution.
+ */
+public class CommandResult {
+
+ public final String feedbackToUser;
+
+ /**
+ * Constructor for Command Result.
+ *
+ * @param feedbackToUser Message to print to user.
+ */
+ public CommandResult(String feedbackToUser) {
+ assert !feedbackToUser.isEmpty() : "CommandResult must not accept empty feedbackToUser";
+ this.feedbackToUser = feedbackToUser;
+ }
+
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/CreateCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/CreateCommand.java
new file mode 100644
index 0000000000..18dc1d1204
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/CreateCommand.java
@@ -0,0 +1,54 @@
+package seedu.smarthomebot.logic.commands;
+
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.commons.exceptions.InvalidLocationException;
+
+import java.util.logging.Level;
+
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LOCATION_EXIST;
+
+//@@author zongxian-ctrl
+
+/**
+ * Represent the command for creating a location in the LocationList.
+ */
+public class CreateCommand extends Command {
+
+ public static final String COMMAND_WORD = "create";
+ public static final String MESSAGE_USAGE = "Create location: " + COMMAND_WORD
+ + " [LOCATION_NAME]";
+ private final String userEnteredLocation;
+
+ /**
+ * Constructor for CreateCommand.
+ *
+ * @param location Name of Location to be created.
+ */
+ public CreateCommand(String location) {
+ assert !location.isEmpty() : "CreateCommand must not accept empty location";
+ this.userEnteredLocation = location;
+ }
+
+ /**
+ * Executing the CreateCommand.
+ */
+ @Override
+ public CommandResult execute() {
+ try {
+ if (!applianceList.isApplianceExist(userEnteredLocation)) {
+ locationList.addLocation(userEnteredLocation);
+ } else {
+ throw new InvalidLocationException();
+ }
+ commandLogger.log(Level.INFO, "Created new Location " + userEnteredLocation);
+ return new CommandResult("Creating Location \"" + userEnteredLocation + "\".....CREATED!");
+ } catch (DuplicateDataException e) {
+ commandLogger.log(Level.WARNING, MESSAGE_LOCATION_EXIST);
+ return new CommandResult(MESSAGE_LOCATION_EXIST);
+ } catch (InvalidLocationException e) {
+ commandLogger.log(Level.WARNING, "Duplicate name found in ApplianceList");
+ return new CommandResult(MESSAGE_LOCATION_EXIST
+ + " as an Appliance, please choose another name.");
+ }
+ }
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/DeleteCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/DeleteCommand.java
new file mode 100644
index 0000000000..910a509a84
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/DeleteCommand.java
@@ -0,0 +1,47 @@
+package seedu.smarthomebot.logic.commands;
+
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.commons.exceptions.ApplianceNotFoundException;
+
+import java.util.logging.Level;
+
+import static seedu.smarthomebot.commons.Messages.LINE;
+
+//@@author zongxian-ctrl
+
+/**
+ * Represent the command for deleting an appliance in the ApplianceList.
+ */
+public class DeleteCommand extends Command {
+ public static final String COMMAND_WORD = "delete";
+ public static final String MESSAGE_USAGE = "Delete Appliance: " + COMMAND_WORD
+ + " [APPLIANCE_NAME]";
+ private final String userEnteredName;
+
+ /**
+ * Constructor for DeleteCommand.
+ *
+ * @param name Appliance name to be deleted.
+ */
+ public DeleteCommand(String name) {
+ assert !name.isEmpty() : "DeleteCommand must not accept empty name";
+ this.userEnteredName = name;
+ }
+
+ /**
+ * Executing the DeleteCommand.
+ */
+ @Override
+ public CommandResult execute() {
+ try {
+ Appliance toDeleteAppliance = applianceList.deleteAppliance(userEnteredName);
+ autoFormattingStringIndex();
+ commandLogger.log(Level.INFO, "Deleted Appliance " + toDeleteAppliance);
+ return new CommandResult("Deleting " + toDeleteAppliance + ".......DELETED.");
+ } catch (ApplianceNotFoundException e) {
+ commandLogger.log(Level.WARNING, userEnteredName + " does not exist.");
+ return new CommandResult(userEnteredName + " does not exist.");
+ }
+ }
+
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/ExitCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/ExitCommand.java
new file mode 100644
index 0000000000..7ebb49eed0
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/ExitCommand.java
@@ -0,0 +1,40 @@
+package seedu.smarthomebot.logic.commands;
+
+import seedu.smarthomebot.data.appliance.Appliance;
+
+import java.util.logging.Level;
+
+import static seedu.smarthomebot.commons.Messages.MESSAGE_EXIT_ACKNOWLEDGEMENT;
+
+
+//@@author Ang-Cheng-Jun
+
+/**
+ * Represent the command to terminate the program.
+ */
+public class ExitCommand extends Command {
+
+ public static final String COMMAND_WORD = "exit";
+ public static final String MESSAGE_USAGE = "Exiting the application: " + COMMAND_WORD;
+
+ /**
+ * Method to check if ExitCommand class is created.
+ *
+ * @param command check for ExitCommand class.
+ * @return true if ExitCommand class is created
+ */
+ public static boolean isExit(Command command) {
+ return command instanceof ExitCommand;
+ }
+
+ /**
+ * Executing the ExitCommand.
+ */
+ public CommandResult execute() {
+ for (Appliance a : applianceList.getAllAppliance()) {
+ a.switchOff();
+ }
+ commandLogger.log(Level.INFO, MESSAGE_EXIT_ACKNOWLEDGEMENT);
+ return new CommandResult(MESSAGE_EXIT_ACKNOWLEDGEMENT);
+ }
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/HelpCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/HelpCommand.java
new file mode 100644
index 0000000000..f480aee47b
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/HelpCommand.java
@@ -0,0 +1,35 @@
+package seedu.smarthomebot.logic.commands;
+
+import static seedu.smarthomebot.commons.Messages.LINE;
+
+//@@author zongxian-ctrl
+
+/**
+ * Represent the command for showing help instructions.
+ */
+public class HelpCommand extends Command {
+
+ public static final String COMMAND_WORD = "help";
+ public static final String MESSAGE_USAGE = "Help: " + COMMAND_WORD;
+ public static final String MESSAGE_HELP = "Here is the list of commands available:\n" + LINE
+ + "\t1. " + HelpCommand.MESSAGE_USAGE + "\n"
+ + "\t2. " + CreateCommand.MESSAGE_USAGE + "\n"
+ + "\t3. " + RemoveCommand.MESSAGE_USAGE + "\n"
+ + "\t4. " + AddCommand.MESSAGE_USAGE + "\n"
+ + "\t5. " + DeleteCommand.MESSAGE_USAGE + "\n"
+ + "\t6. " + OnCommand.MESSAGE_USAGE + "\n"
+ + "\t7. " + OffCommand.MESSAGE_USAGE + "\n"
+ + "\t8. " + ListCommand.MESSAGE_USAGE + "\n"
+ + "\t9. " + UsageCommand.MESSAGE_USAGE + "\n"
+ + "\t10. " + ResetCommand.MESSAGE_USAGE + "\n"
+ + "\t11. " + ExitCommand.MESSAGE_USAGE + "\n";
+
+ /**
+ * Executing the HelpCommand.
+ */
+ @Override
+ public CommandResult execute() {
+ return new CommandResult(MESSAGE_HELP);
+ }
+
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/InvalidCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/InvalidCommand.java
new file mode 100644
index 0000000000..ff471322d1
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/InvalidCommand.java
@@ -0,0 +1,33 @@
+package seedu.smarthomebot.logic.commands;
+
+import java.util.logging.Level;
+
+//@@author Ang-Cheng-Jun
+
+/**
+ * Represent the command to print error notifications to user.
+ */
+public class InvalidCommand extends Command {
+
+ public final String feedbackToUser;
+
+ /**
+ * Constructor for InvalidCommand.
+ *
+ * @param feedbackToUser Error message to be printed to user.
+ */
+ public InvalidCommand(String feedbackToUser) {
+ assert feedbackToUser.isEmpty() != true : "InvalidCommand must not accept empty feedbackToUser";
+ this.feedbackToUser = feedbackToUser;
+ }
+
+ /**
+ * Executing the InvalidCommand.
+ */
+ @Override
+ public CommandResult execute() {
+ commandLogger.log(Level.WARNING, feedbackToUser);
+ return new CommandResult(feedbackToUser);
+ }
+
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/ListCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/ListCommand.java
new file mode 100644
index 0000000000..1d830c9391
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/ListCommand.java
@@ -0,0 +1,176 @@
+package seedu.smarthomebot.logic.commands;
+
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.logic.commands.exceptions.EmptyApplianceListException;
+import seedu.smarthomebot.logic.commands.exceptions.EmptyLocationListException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+import seedu.smarthomebot.commons.exceptions.NoApplianceInLocationException;
+
+import java.util.ArrayList;
+import java.util.logging.Level;
+
+import static java.util.stream.Collectors.toList;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LIST_APPLIANCES;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LIST_LOCATIONS;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LIST_NO_APPLIANCES;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LIST_NO_LOCATIONS;
+
+//@@author Ang-Cheng-Jun
+
+/**
+ * Represent the command to list LocationList or ApplianceList to the user.
+ */
+public class ListCommand extends Command {
+
+ public static final String COMMAND_WORD = "list";
+ public static final String MESSAGE_USAGE = "List: \n\t\t a. " + COMMAND_WORD
+ + " appliance \n\t\t b. " + COMMAND_WORD + " location \n\t\t c. "
+ + COMMAND_WORD + " appliance l/[LOCATION_NAME]";
+
+ private static final String APPLIANCE_TYPE = "appliance";
+ private static final String LOCATION_TYPE = "location";
+ private static final String DISPLAY_LOCATION = " | Location: ";
+ private static final String DISPLAY_STATUS = " | Status: ";
+ private static final String DISPLAY_WATT = " | Watt: ";
+ private static final String DISPLAY_TYPE = " | Type: ";
+ private static final String DISPLAY_PARAMETER = " | Parameter: ";
+
+ private final String argument;
+ private final String filteredLocation;
+
+ /**
+ * Constructor for List Command.
+ *
+ * @param argument to determine ListLocation or ListAppliance.
+ * @param filteredLocation input location filter for ListAppliance.
+ */
+ public ListCommand(String argument, String filteredLocation) {
+ assert argument.isEmpty() != true : "ListCommand must not accept empty argument";
+ this.argument = argument;
+ this.filteredLocation = filteredLocation;
+ }
+
+ /**
+ * Executing the ListCommand.
+ */
+ @Override
+ public CommandResult execute() {
+ try {
+ switch (argument) {
+ case LOCATION_TYPE:
+ return listLocation();
+ case APPLIANCE_TYPE:
+ return listAppliance();
+ default:
+ commandLogger.log(Level.WARNING, "Invalid Format");
+ return new CommandResult("Invalid Format");
+ }
+ } catch (EmptyApplianceListException e) {
+ commandLogger.log(Level.WARNING, "Unable to list: Empty Appliance List");
+ return new CommandResult(MESSAGE_LIST_NO_APPLIANCES);
+ } catch (LocationNotFoundException e) {
+ commandLogger.log(Level.WARNING, "Location: \"" + filteredLocation + "\" does not exist.");
+ return new CommandResult("Location: \"" + filteredLocation + "\" does not exist.");
+ } catch (NoApplianceInLocationException e) {
+ commandLogger.log(Level.WARNING, "There is no Appliance in \"" + filteredLocation + "\".");
+ return new CommandResult("There is no Appliance in \"" + filteredLocation + "\".");
+ } catch (EmptyLocationListException e) {
+ commandLogger.log(Level.WARNING, MESSAGE_LIST_NO_LOCATIONS);
+ return new CommandResult(MESSAGE_LIST_NO_LOCATIONS);
+ }
+ }
+
+ /**
+ * Method to list all the appliances or appliances in filteredLocation.
+ *
+ * @return the Appliance List in String.
+ */
+ private CommandResult listAppliance() throws LocationNotFoundException, EmptyApplianceListException,
+ NoApplianceInLocationException {
+ String outputResult;
+ ArrayList outputApplianceList = applianceList.getAllAppliance();
+ if (filteredLocation.equals("")) {
+ outputResult = listAllAppliances(outputApplianceList);
+ } else {
+ outputResult = listApplianceByLocation(outputApplianceList);
+ }
+ commandLogger.log(Level.INFO, outputResult);
+ return new CommandResult(outputResult);
+ }
+
+
+ private String listAllAppliances(ArrayList outputApplianceList) throws EmptyApplianceListException {
+ if (outputApplianceList.size() == 0) {
+ throw new EmptyApplianceListException();
+ }
+ String outputResult = displayOutput(MESSAGE_LIST_APPLIANCES, outputApplianceList);
+ commandLogger.log(Level.INFO, outputResult);
+ return outputResult;
+ }
+
+ private String listApplianceByLocation(ArrayList outputApplianceList)
+ throws LocationNotFoundException, NoApplianceInLocationException {
+ ArrayList filterApplianceList =
+ (ArrayList) outputApplianceList.stream()
+ .filter((s) -> s.getLocation().equals(filteredLocation))
+ .collect(toList());
+
+ if (filterApplianceList.isEmpty()) {
+ if (locationList.isLocationCreated(filteredLocation)) {
+ throw new NoApplianceInLocationException();
+ }
+ throw new LocationNotFoundException();
+ }
+ String header = ("Here are the Appliances in \"" + filteredLocation + "\"");
+ String outputResult = displayOutput(header, filterApplianceList);
+ commandLogger.log(Level.INFO, outputResult);
+ return outputResult;
+ }
+
+ /**
+ * Method to list all the locations.
+ *
+ * @return the Location List in String.
+ */
+ private CommandResult listLocation() throws EmptyLocationListException {
+ int index = 1;
+ ArrayList outputLocationList = locationList.getAllLocations();
+
+ if (outputLocationList.size() == 0) {
+ throw new EmptyLocationListException();
+ }
+ String outputResult = MESSAGE_LIST_LOCATIONS;
+ for (String location : outputLocationList) {
+ outputResult = outputResult.concat(System.lineSeparator() + index + ": " + location);
+ index++;
+ }
+ commandLogger.log(Level.INFO, outputResult);
+ return new CommandResult(outputResult);
+ }
+
+ /**
+ * Method to format the displayList.
+ *
+ * @param displayList Appliance List to display.
+ * @return the formatted Appliance List in String.
+ */
+ private String displayOutput(String header, ArrayList displayList) {
+ autoFormattingStringIndex();
+ int index = 1;
+ String outputResult = header;
+ String format = "%-2d. %-" + maxNameLength + "s"
+ + DISPLAY_LOCATION + "%-" + maxLocationLength + "s"
+ + DISPLAY_STATUS + "%-3s"
+ + DISPLAY_WATT + "%-4sW"
+ + DISPLAY_TYPE + "%-9s"
+ + DISPLAY_PARAMETER + "%s";
+
+ for (Appliance a : displayList) {
+ outputResult = outputResult.concat(System.lineSeparator() + String.format(format, index,
+ a.getName(), a.getLocation(), a.getStatus(), a.getWattage(), a.getType(), a.getParameter(true)));
+ index++;
+ }
+ commandLogger.log(Level.INFO, outputResult);
+ return outputResult;
+ }
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/OffCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/OffCommand.java
new file mode 100644
index 0000000000..093d6465b0
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/OffCommand.java
@@ -0,0 +1,126 @@
+package seedu.smarthomebot.logic.commands;
+
+import seedu.smarthomebot.commons.exceptions.ApplianceNotFoundException;
+import seedu.smarthomebot.data.appliance.Appliance;
+
+import java.util.ArrayList;
+import java.util.logging.Level;
+
+import static java.util.stream.Collectors.toList;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_PREVIOUSLY_OFF;
+
+//@@author Ang-Cheng-Jun
+
+/**
+ * Represent the Command to turn off Appliance(s).
+ */
+public class OffCommand extends Command {
+
+ public static final String COMMAND_WORD = "off";
+ public static final String MESSAGE_USAGE = "Switch OFF Appliance: \n\t\t a. " + COMMAND_WORD
+ + " [APPLIANCE_NAME] \n\t\t b. " + COMMAND_WORD + " [LOCATION_NAME]";
+ private static final String APPLIANCE_TYPE = "appliance";
+ private static final String LOCATION_TYPE = "location";
+ private final String argument;
+
+ /**
+ * Constructor for OffCommand.
+ *
+ * @param argument Appliance or Location 's name to be off.
+ */
+ public OffCommand(String argument) {
+ assert argument.isEmpty() != true : "OffCommand must not accept empty argument";
+ this.argument = argument;
+ }
+
+ /**
+ * Executing the OffCommand.
+ */
+ @Override
+ public CommandResult execute() {
+ try {
+ String type = APPLIANCE_TYPE;
+ ArrayList filterApplianceList =
+ (ArrayList) applianceList.getAllAppliance().stream()
+ .filter((s) -> s.getLocation().equals(argument))
+ .collect(toList());
+ if (!filterApplianceList.isEmpty()) {
+ type = LOCATION_TYPE;
+ }
+
+ switch (type) {
+ case (APPLIANCE_TYPE):
+ return offByApplianceName();
+ case (LOCATION_TYPE):
+ return offByLocation(filterApplianceList);
+ default:
+ return new CommandResult("Invalid Format");
+ }
+ } catch (ApplianceNotFoundException e) {
+ if (locationList.isLocationCreated(argument)) {
+ commandLogger.log(Level.WARNING, "There are no Appliances in \"" + argument + "\".");
+ return new CommandResult("There are no Appliances in \"" + argument + "\".");
+ } else {
+ commandLogger.log(Level.WARNING, MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST);
+ return new CommandResult(MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST);
+ }
+ }
+ }
+
+ /**
+ * Method to off Appliance by the name.
+ *
+ * @throws ApplianceNotFoundException when keyed Appliance is not found in ApplianceList.
+ */
+ private CommandResult offByApplianceName() throws ApplianceNotFoundException {
+ int toOffApplianceIndex = applianceList.getApplianceIndex(argument);
+ Appliance toOffAppliance = applianceList.getAppliance(toOffApplianceIndex);
+ String outputResult = offAppliance(toOffAppliance, true);
+ assert !outputResult.isEmpty() : "outputResult must contains String";
+ commandLogger.log(Level.INFO, outputResult);
+
+ return new CommandResult(outputResult);
+ }
+
+ /**
+ * Method to off Appliance by the Location.
+ */
+ private CommandResult offByLocation(ArrayList toOffAppliance) {
+ offApplianceByLoop(toOffAppliance);
+ String outputResult = "All Appliances in \"" + argument + "\" are turned off ";
+ commandLogger.log(Level.INFO, outputResult);
+ return new CommandResult(outputResult);
+ }
+
+ /**
+ * Method to iterate through the list and filter out the location to turn off.
+ */
+ private void offApplianceByLoop(ArrayList toOffAppliance) {
+ for (Appliance appliance : toOffAppliance) {
+ offAppliance(appliance, false);
+ }
+ }
+
+ /**
+ * Method to switch off Appliance.
+ *
+ * @param toOffAppliance Appliance to switch off in Appliance.
+ * @param isList flag to return its corresponding output message.
+ * @return the corresponding output Message in String if isList is true.
+ */
+ private String offAppliance(Appliance toOffAppliance, boolean isList) {
+ boolean offResult = toOffAppliance.switchOff();
+ String outputResult = "";
+ assert toOffAppliance.getStatus().equals("OFF") : "Appliance should be already OFF";
+
+ if (isList) {
+ if (offResult) {
+ outputResult = "Switching: " + toOffAppliance + "......OFF";
+ } else {
+ outputResult = toOffAppliance.getName() + MESSAGE_APPLIANCE_PREVIOUSLY_OFF;
+ }
+ }
+ return outputResult;
+ }
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/OnCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/OnCommand.java
new file mode 100644
index 0000000000..d9c2a42aa4
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/OnCommand.java
@@ -0,0 +1,176 @@
+package seedu.smarthomebot.logic.commands;
+
+import seedu.smarthomebot.commons.exceptions.ApplianceNotFoundException;
+import seedu.smarthomebot.data.appliance.type.AirConditioner;
+import seedu.smarthomebot.data.appliance.type.Fan;
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.logic.commands.exceptions.ParameterFoundException;
+
+import java.util.ArrayList;
+import java.util.logging.Level;
+
+import static java.util.stream.Collectors.toList;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_PREVIOUSLY_ON;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_NO_PARAMETER_IN_ON_BY_LOCATION;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_INVALID_TEMPERATURE_AC;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_INVALID_FAN_SPEED;
+
+//@@author leonlowzd
+
+/**
+ * Represent the Command to turn on Appliance(s).
+ */
+public class OnCommand extends Command {
+
+ public static final String COMMAND_WORD = "on";
+ public static final String MESSAGE_USAGE = "Switch ON Appliance: \n\t\t a. " + COMMAND_WORD
+ + " [APPLIANCE_NAME] \n\t\t b. " + COMMAND_WORD + " [APPLIANCE_NAME] p/[PARAMETER] \n\t\t c. "
+ + COMMAND_WORD + " [LOCATION_NAME]";
+
+ private static final String APPLIANCE_TYPE = "appliance";
+ private static final String LOCATION_TYPE = "location";
+ private final String argument;
+ private final String parameter;
+
+ /**
+ * Constructor for OnCommand.
+ *
+ * @param argument Appliance or Location 's name to be on.
+ * @param parameter To set Appliance's parameter: only valid for fan and aircon.
+ */
+ public OnCommand(String argument, String parameter) {
+ assert !argument.isEmpty() : "OnCommand must not accept empty argument";
+ this.argument = argument;
+ this.parameter = parameter;
+ }
+
+ /**
+ * Executing the OnCommand.
+ */
+ @Override
+ public CommandResult execute() {
+ try {
+ String onByType = APPLIANCE_TYPE;
+ // To filter out Appliances with location corresponding to the argument.
+ ArrayList filterApplianceList =
+ (ArrayList) applianceList.getAllAppliance().stream()
+ .filter((s) -> s.getLocation().equals(argument))
+ .collect(toList());
+
+ // If the list is not empty; it means that user wants to onByLocation.
+ if (!filterApplianceList.isEmpty()) {
+ onByType = LOCATION_TYPE;
+ }
+
+ switch (onByType) {
+ case (APPLIANCE_TYPE):
+ return onByApplianceName();
+ case (LOCATION_TYPE):
+ return onByLocation(filterApplianceList);
+ default:
+ return new CommandResult("Invalid Format");
+ }
+ } catch (ApplianceNotFoundException e) {
+ if (locationList.isLocationCreated(argument)) {
+ commandLogger.log(Level.WARNING, "There are no Appliances in \"" + argument + "\".");
+ return new CommandResult("There are no Appliances in \"" + argument + "\".");
+ } else {
+ commandLogger.log(Level.WARNING, MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST);
+ return new CommandResult(MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST);
+ }
+ } catch (ParameterFoundException e) {
+ commandLogger.log(Level.WARNING, MESSAGE_NO_PARAMETER_IN_ON_BY_LOCATION);
+ return new CommandResult(MESSAGE_NO_PARAMETER_IN_ON_BY_LOCATION);
+ }
+ }
+
+ /**
+ * Method to on Appliance by the name.
+ *
+ * @throws ApplianceNotFoundException when keyed Appliance is not found in ApplianceList.
+ */
+ private CommandResult onByApplianceName() throws ApplianceNotFoundException {
+ int toOnApplianceIndex = applianceList.getApplianceIndex(argument);
+ Appliance toOnAppliance = applianceList.getAppliance(toOnApplianceIndex);
+ String outputResult = onAppliance(toOnAppliance, true);
+ commandLogger.log(Level.INFO, outputResult);
+ return new CommandResult(outputResult);
+ }
+
+ /**
+ * Method to set Appliance's parameter.
+ *
+ * @return error message if there is an error setting the parameter.
+ */
+ private String setParameter(String parameter, Appliance appliance) {
+ String setParameterStatement = "";
+ switch (appliance.getType().toLowerCase()) {
+ case AirConditioner.TYPE_WORD:
+ AirConditioner ac = (AirConditioner) appliance;
+ if (!ac.setTemperature(parameter)) {
+ setParameterStatement = MESSAGE_INVALID_TEMPERATURE_AC;
+ }
+ break;
+ case Fan.TYPE_WORD:
+ Fan fan = (Fan) appliance;
+ if (!fan.setSpeed(parameter)) {
+ setParameterStatement = MESSAGE_INVALID_FAN_SPEED;
+ }
+ break;
+ default:
+ return "";
+ }
+ return setParameterStatement;
+ }
+
+ /**
+ * Method to On Appliance by the Location.
+ *
+ * @throws ParameterFoundException When entered Parameter is Invalid.
+ */
+ private CommandResult onByLocation(ArrayList toOnAppliance) throws ParameterFoundException {
+ if (!parameter.isEmpty()) {
+ throw new ParameterFoundException();
+ } else {
+ onApplianceByLoop(toOnAppliance);
+ String outputResult = "All Appliances in \"" + argument + "\" are turned on ";
+ commandLogger.log(Level.INFO, outputResult);
+ return new CommandResult(outputResult);
+ }
+ }
+
+ /**
+ * Method to iterate through the toOnAppliance List and turn on the Appliance.
+ */
+ private void onApplianceByLoop(ArrayList toOnAppliance) {
+ for (Appliance appliance : toOnAppliance) {
+ onAppliance(appliance, false);
+ }
+ }
+
+ /**
+ * Method to switch on Appliance.
+ *
+ * @param toOnAppliance Appliance to switch on in Appliance.
+ * @param isList flag to return its corresponding output message.
+ * @return the corresponding output Message in String if isList is true.
+ */
+ private String onAppliance(Appliance toOnAppliance, boolean isList) {
+ String outputResult = "";
+ boolean onResult = toOnAppliance.switchOn();
+ assert toOnAppliance.getStatus().equals("ON") : "Appliance should be already ON";
+ String setParameterStatement = setParameter(parameter, toOnAppliance);
+ if (isList) {
+ if (onResult) {
+ outputResult = setParameterStatement + "Switching " + toOnAppliance.toString() + ".....ON";
+
+ } else {
+ outputResult = setParameterStatement
+ + toOnAppliance.getName() + MESSAGE_APPLIANCE_PREVIOUSLY_ON + toOnAppliance.toString();
+ }
+ }
+ return outputResult;
+ }
+
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/RemoveCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/RemoveCommand.java
new file mode 100644
index 0000000000..3a56d003a8
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/RemoveCommand.java
@@ -0,0 +1,52 @@
+package seedu.smarthomebot.logic.commands;
+
+import seedu.smarthomebot.commons.exceptions.ApplianceNotFoundException;
+import seedu.smarthomebot.commons.exceptions.InvalidLocationException;
+
+import java.util.logging.Level;
+
+import static seedu.smarthomebot.commons.Messages.LINE;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LOCATION_NOT_EXIST;
+
+//@@author zongxian-ctrl
+
+/**
+ * Represent the command for removing a location in the LocationList.
+ */
+public class RemoveCommand extends Command {
+
+ public static final String COMMAND_WORD = "remove";
+ public static final String MESSAGE_USAGE = "Remove location: " + COMMAND_WORD
+ + " [LOCATION_NAME]";
+ private final String userEnteredLocation;
+
+ /**
+ * Constructor for OnCommand.
+ *
+ * @param location name of Location to be removed from LocationList.
+ */
+ public RemoveCommand(String location) {
+ assert !location.isEmpty() : "RemoveCommand must not accept empty location";
+ this.userEnteredLocation = location;
+ }
+
+ /**
+ * Executing the RemoveCommand.
+ */
+ @Override
+ public CommandResult execute() {
+ try {
+ locationList.removeLocation(userEnteredLocation);
+ applianceList.deleteByLocation(userEnteredLocation);
+ commandLogger.log(Level.INFO, "Removed location " + userEnteredLocation);
+ return new CommandResult("Removing LOCATION \"" + userEnteredLocation + "\"......REMOVED!");
+ } catch (InvalidLocationException e) {
+ commandLogger.log(Level.WARNING, MESSAGE_LOCATION_NOT_EXIST);
+ return new CommandResult(MESSAGE_LOCATION_NOT_EXIST + " Nothing will be deleted.");
+ } catch (ApplianceNotFoundException e) {
+ commandLogger.log(Level.WARNING, MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST);
+ return new CommandResult(MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST + " Nothing will be deleted.");
+ }
+ }
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/ResetCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/ResetCommand.java
new file mode 100644
index 0000000000..1e52689a07
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/ResetCommand.java
@@ -0,0 +1,46 @@
+package seedu.smarthomebot.logic.commands;
+
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.logic.commands.exceptions.EmptyApplianceListException;
+
+import java.util.ArrayList;
+import java.util.logging.Level;
+
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LIST_NO_APPLIANCES;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_USAGE_RESET;
+
+//@@author fanceso
+
+/**
+ * Represent the command to reset the power monitored.
+ */
+public class ResetCommand extends Command {
+
+ public static final String COMMAND_WORD = "p_reset";
+ public static final String MESSAGE_USAGE = "Resetting previous recorded usage: " + COMMAND_WORD;
+
+ /**
+ * Executing the ResetCommand.
+ */
+ @Override
+ public CommandResult execute() {
+ try {
+ ArrayList resetApplianceList = applianceList.getAllAppliance();
+ if (resetApplianceList.size() == 0) {
+ commandLogger.log(Level.WARNING, MESSAGE_LIST_NO_APPLIANCES);
+ throw new EmptyApplianceListException();
+ } else {
+ assert !resetApplianceList.isEmpty() : "resetApplianceList must not be empty";
+ for (Appliance a : resetApplianceList) {
+ a.resetPowerUsage();
+ assert a.getPowerInString().equals("0.00") : "Power usage needs to be reset to 0.00";
+ }
+ commandLogger.log(Level.INFO, MESSAGE_USAGE_RESET);
+ return new CommandResult(MESSAGE_USAGE_RESET);
+ }
+ } catch (EmptyApplianceListException e) {
+ return new CommandResult(MESSAGE_LIST_NO_APPLIANCES);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/UsageCommand.java b/src/main/java/seedu/smarthomebot/logic/commands/UsageCommand.java
new file mode 100644
index 0000000000..bdfb5e5322
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/UsageCommand.java
@@ -0,0 +1,76 @@
+package seedu.smarthomebot.logic.commands;
+
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.logic.commands.exceptions.EmptyApplianceListException;
+
+import java.util.ArrayList;
+import java.util.logging.Level;
+
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LIST_NO_APPLIANCES;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_POWER_USAGE;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_TOTAL_POWER_USAGE;
+
+//@@author fanceso
+
+/**
+ * Represent the command to display power usage of the application to the user.
+ */
+public class UsageCommand extends Command {
+
+ public static final String COMMAND_WORD = "usage";
+ public static final String MESSAGE_USAGE = "Usage of Appliance: " + COMMAND_WORD;
+
+ private static final String DISPLAY_LOCATION = " | Location: ";
+ private static final String DISPLAY_STATUS = " | Status: ";
+ private static final String DISPLAY_USAGE = " | Usage: ";
+
+ /**
+ * Executing the UsageCommand.
+ */
+ @Override
+ public CommandResult execute() {
+ String outputResult;
+ try {
+ ArrayList outputApplianceList = applianceList.getAllAppliance();
+ assert !outputApplianceList.equals(null) : "outputApplianceList must not be null";
+ if (outputApplianceList.size() == 0) {
+ commandLogger.log(Level.WARNING, MESSAGE_LIST_NO_APPLIANCES);
+ throw new EmptyApplianceListException();
+ } else {
+ outputResult = displayOutput(outputApplianceList);
+ assert !outputApplianceList.isEmpty() : "outputApplianceList must not be empty";
+ return new CommandResult(outputResult);
+ }
+ } catch (EmptyApplianceListException e) {
+ return new CommandResult(MESSAGE_LIST_NO_APPLIANCES);
+ }
+ }
+
+ /**
+ * Method to display output result of usage command.
+ *
+ * @param outputApplianceList is the list that to switch off in Appliance.
+ * @return the Appliance List in String with auto formatted result.
+ */
+ private String displayOutput(ArrayList outputApplianceList) {
+ int index = 1;
+ double totalUsage = 0;
+ String outputResult = MESSAGE_POWER_USAGE;
+ autoFormattingStringIndex();
+ String formatInString = "%-2d. %-" + maxNameLength + "s"
+ + DISPLAY_LOCATION + "%-" + maxLocationLength + "s"
+ + DISPLAY_STATUS + "%-3s"
+ + DISPLAY_USAGE + "%.2f kWh";
+ for (Appliance a : outputApplianceList) {
+ outputResult = outputResult.concat(System.lineSeparator() + String.format(formatInString,
+ index, a.getName(), a.getLocation(), a.getStatus(), a.getPowerInDouble()));
+ totalUsage += a.getPowerInDouble();
+ index++;
+ }
+ outputResult = outputResult.concat(MESSAGE_TOTAL_POWER_USAGE + String.format("%.2f kWh", totalUsage));
+ assert !outputResult.isEmpty() : "outputResult must contains String";
+ commandLogger.log(Level.INFO, "Power usage computed with output message.\n" + outputResult);
+ return outputResult;
+ }
+
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/exceptions/EmptyApplianceListException.java b/src/main/java/seedu/smarthomebot/logic/commands/exceptions/EmptyApplianceListException.java
new file mode 100644
index 0000000000..41b59dc0e2
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/exceptions/EmptyApplianceListException.java
@@ -0,0 +1,4 @@
+package seedu.smarthomebot.logic.commands.exceptions;
+
+public class EmptyApplianceListException extends Exception {
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/exceptions/EmptyLocationListException.java b/src/main/java/seedu/smarthomebot/logic/commands/exceptions/EmptyLocationListException.java
new file mode 100644
index 0000000000..eab629d7cb
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/exceptions/EmptyLocationListException.java
@@ -0,0 +1,4 @@
+package seedu.smarthomebot.logic.commands.exceptions;
+
+public class EmptyLocationListException extends Exception {
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/exceptions/InvalidApplianceNameException.java b/src/main/java/seedu/smarthomebot/logic/commands/exceptions/InvalidApplianceNameException.java
new file mode 100644
index 0000000000..d2da4a4b37
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/exceptions/InvalidApplianceNameException.java
@@ -0,0 +1,4 @@
+package seedu.smarthomebot.logic.commands.exceptions;
+
+public class InvalidApplianceNameException extends Exception {
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/exceptions/LocationNotFoundException.java b/src/main/java/seedu/smarthomebot/logic/commands/exceptions/LocationNotFoundException.java
new file mode 100644
index 0000000000..311eab8d44
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/exceptions/LocationNotFoundException.java
@@ -0,0 +1,4 @@
+package seedu.smarthomebot.logic.commands.exceptions;
+
+public class LocationNotFoundException extends Exception{
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/commands/exceptions/ParameterFoundException.java b/src/main/java/seedu/smarthomebot/logic/commands/exceptions/ParameterFoundException.java
new file mode 100644
index 0000000000..600c22b953
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/commands/exceptions/ParameterFoundException.java
@@ -0,0 +1,5 @@
+package seedu.smarthomebot.logic.commands.exceptions;
+
+public class ParameterFoundException extends Exception {
+
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/parser/Parser.java b/src/main/java/seedu/smarthomebot/logic/parser/Parser.java
new file mode 100644
index 0000000000..d0f758bf3d
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/parser/Parser.java
@@ -0,0 +1,338 @@
+package seedu.smarthomebot.logic.parser;
+
+import org.apache.commons.lang3.StringUtils;
+import seedu.smarthomebot.logic.commands.AddCommand;
+import seedu.smarthomebot.logic.commands.Command;
+import seedu.smarthomebot.logic.commands.CreateCommand;
+import seedu.smarthomebot.logic.commands.DeleteCommand;
+import seedu.smarthomebot.logic.commands.ExitCommand;
+import seedu.smarthomebot.logic.commands.HelpCommand;
+import seedu.smarthomebot.logic.commands.InvalidCommand;
+import seedu.smarthomebot.logic.commands.ListCommand;
+import seedu.smarthomebot.logic.commands.OffCommand;
+import seedu.smarthomebot.logic.commands.OnCommand;
+import seedu.smarthomebot.logic.commands.RemoveCommand;
+import seedu.smarthomebot.logic.commands.ResetCommand;
+import seedu.smarthomebot.logic.commands.UsageCommand;
+import seedu.smarthomebot.logic.commands.exceptions.ParameterFoundException;
+import seedu.smarthomebot.logic.parser.exceptions.EmptyParameterException;
+import seedu.smarthomebot.logic.parser.exceptions.IllegalCharacterException;
+import seedu.smarthomebot.logic.parser.exceptions.InvalidCommandException;
+import seedu.smarthomebot.commons.exceptions.InvalidNumericalValueException;
+import seedu.smarthomebot.logic.parser.exceptions.WattageExceedException;
+
+import static seedu.smarthomebot.commons.Messages.MESSAGE_EMPTY_PARAMETER;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_ILLEGAL_CHARACTER;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_INVALID_ADD_COMMAND;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_INVALID_LIST_COMMAND;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_POWER_EXCEEDED;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_VALUE_NOT_NUMBER;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_PARAMETER_INVALID;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_NO_PARAMETER_IN_ON_BY_LOCATION;
+
+/**
+ * Parses user input.
+ */
+public class Parser {
+
+ private static final String APPLIANCE_TYPE = "appliance";
+ private static final String LOCATION_TYPE = "location";
+
+ //@@author zongxian-ctrl
+
+ /**
+ * Parses user input into command for execution.
+ *
+ * @param userInput full user input string.
+ * @return command based on the user input.
+ */
+ public Command parseCommand(String userInput) {
+ String[] words = userInput.trim().split(" ", 2);
+ final String commandWord = words[0];
+ final String argument = StringUtils.replaceOnce(userInput, commandWord, "").trim();
+
+ switch (commandWord) {
+ case HelpCommand.COMMAND_WORD:
+ return new HelpCommand();
+ case CreateCommand.COMMAND_WORD:
+ return prepareCreateCommand(argument);
+ case RemoveCommand.COMMAND_WORD:
+ return prepareRemoveCommand(argument);
+ case AddCommand.COMMAND_WORD:
+ return prepareAddCommand(argument);
+ case DeleteCommand.COMMAND_WORD:
+ return prepareDeleteCommand(argument);
+ case OnCommand.COMMAND_WORD:
+ return prepareOnCommand(argument);
+ case OffCommand.COMMAND_WORD:
+ return prepareOffCommand(argument);
+ case ListCommand.COMMAND_WORD:
+ return prepareListCommand(argument);
+ case UsageCommand.COMMAND_WORD:
+ return new UsageCommand();
+ case ResetCommand.COMMAND_WORD:
+ return new ResetCommand();
+ case ExitCommand.COMMAND_WORD:
+ return new ExitCommand();
+ default:
+ return new InvalidCommand(MESSAGE_INVALID_COMMAND_FORMAT);
+ }
+
+ }
+
+ /**
+ * Parses arguments for CreateCommand by checking if arguments is valid.
+ *
+ * @param argument parameter of CreateCommand.
+ * @return the prepared CreateCommand.
+ */
+ private Command prepareCreateCommand(String argument) {
+ try {
+ if (isEmptyInput(argument)) {
+ throw new EmptyParameterException();
+ }
+ if (hasIllegalCharacter(argument)) {
+ throw new IllegalCharacterException();
+ }
+ return new CreateCommand(argument);
+ } catch (EmptyParameterException e) {
+ return new InvalidCommand(MESSAGE_EMPTY_PARAMETER);
+ } catch (IllegalCharacterException e) {
+ return new InvalidCommand(MESSAGE_ILLEGAL_CHARACTER + " [LOCATION_NAME].");
+ }
+
+ }
+
+ /**
+ * Parses arguments for RemoveCommand by checking if arguments is valid.
+ *
+ * @param argument parameter of RemoveCommand.
+ * @return the prepared RemoveCommand.
+ */
+ private Command prepareRemoveCommand(String argument) {
+ try {
+ if (isEmptyInput(argument)) {
+ throw new EmptyParameterException();
+ }
+ return new RemoveCommand(argument);
+ } catch (EmptyParameterException e) {
+ return new InvalidCommand(MESSAGE_EMPTY_PARAMETER);
+ }
+
+ }
+
+ /**
+ * Parses arguments into AddCommand format.
+ *
+ * @param argument parameters of AddComand.
+ * @return the prepared AddCommand.
+ */
+ private static Command prepareAddCommand(String argument) {
+ int indexLocation = argument.indexOf("l/");
+ int indexPower = argument.indexOf("w/");
+ int indexType = argument.indexOf("t/");
+ String name;
+ String location;
+ String wattage;
+ String type;
+
+ try {
+ if (indexLocation < indexPower && indexPower < indexType) {
+ name = argument.substring(0, indexLocation).trim();
+ location = argument.substring(indexLocation + 2, indexPower).trim();
+ wattage = argument.substring(indexPower + 2, indexType).trim();
+ type = argument.substring(indexType + 2).toLowerCase().trim();
+
+ if (isEmptyInput(name) | isEmptyInput(location)
+ | isEmptyInput(wattage) | isEmptyInput(type)) {
+ throw new EmptyParameterException();
+ }
+ if (hasIllegalCharacter(name)) {
+ throw new IllegalCharacterException();
+ }
+ testWattageValidity(wattage);
+ } else {
+ throw new InvalidCommandException();
+ }
+ return new AddCommand(name, location, wattage, type);
+
+ } catch (InvalidCommandException | StringIndexOutOfBoundsException e) {
+ return new InvalidCommand(MESSAGE_INVALID_ADD_COMMAND);
+ } catch (InvalidNumericalValueException e) {
+ return new InvalidCommand(MESSAGE_VALUE_NOT_NUMBER);
+ } catch (WattageExceedException e) {
+ return new InvalidCommand(MESSAGE_POWER_EXCEEDED);
+ } catch (EmptyParameterException e) {
+ return new InvalidCommand(MESSAGE_EMPTY_PARAMETER);
+ } catch (IllegalCharacterException e) {
+ return new InvalidCommand(MESSAGE_ILLEGAL_CHARACTER + " [APPLIANCE_NAME].");
+ }
+
+ }
+
+ /**
+ * Parses arguments for DeleteCommand by checking if arguments is valid.
+ *
+ * @param argument parameter of DeleteCommand.
+ * @return the prepared DeleteCommand.
+ */
+ private Command prepareDeleteCommand(String argument) {
+ try {
+ if (isEmptyInput(argument)) {
+ throw new EmptyParameterException();
+ }
+ return new DeleteCommand(argument);
+ } catch (EmptyParameterException e) {
+ return new InvalidCommand(MESSAGE_EMPTY_PARAMETER);
+ }
+
+ }
+
+ //@@author leonlowzd
+
+ /**
+ * Parses arguments into OnCommand format.
+ *
+ * @param argument parameters of OnCommand
+ * @return the prepared OnCommand
+ */
+ private static Command prepareOnCommand(String argument) {
+ int indexParameter = argument.indexOf("p/");
+ String name;
+ String parameter;
+ try {
+ if (indexParameter < 1) {
+ name = argument;
+ if (isEmptyInput(name)) {
+ throw new EmptyParameterException();
+ }
+ parameter = "";
+ } else {
+ name = argument.substring(0, indexParameter).trim();
+ parameter = argument.substring(indexParameter + 2).toLowerCase().trim();
+ if (isEmptyInput(name) || isEmptyInput(parameter)) {
+ throw new EmptyParameterException();
+ }
+ checkIfParameterIsInt(parameter);
+ }
+ return new OnCommand(name, parameter);
+ } catch (EmptyParameterException e) {
+ return new InvalidCommand(MESSAGE_EMPTY_PARAMETER);
+ } catch (InvalidNumericalValueException e) {
+ return new InvalidCommand(MESSAGE_PARAMETER_INVALID);
+ }
+ }
+
+ //@@author Ang-Cheng-Jun
+
+ /**
+ * Parses arguments into OffCommand format.
+ *
+ * @param argument parameters of OffCommand
+ * @return the prepared OffCommand
+ */
+ private static Command prepareOffCommand(String argument) {
+ try {
+ int indexParameter = argument.indexOf("p/");
+ if (!(indexParameter < 0)) {
+ throw new ParameterFoundException();
+ }
+ if (isEmptyInput(argument)) {
+ throw new EmptyParameterException();
+ }
+ return new OffCommand(argument);
+ } catch (EmptyParameterException e) {
+ return new InvalidCommand(MESSAGE_EMPTY_PARAMETER);
+ } catch (ParameterFoundException e) {
+ return new InvalidCommand(MESSAGE_NO_PARAMETER_IN_ON_BY_LOCATION);
+ }
+ }
+
+ //@@author Ang-Cheng-Jun
+
+ /**
+ * Parses arguments into ListCommand format.
+ *
+ * @param argument parameters of ListCommand
+ * @return the prepared ListCommand
+ */
+ private static Command prepareListCommand(String argument) {
+ String[] str = argument.split(" ");
+ if (str[0].equals(LOCATION_TYPE)) {
+ return new ListCommand(LOCATION_TYPE, "");
+ } else if (str[0].equals(APPLIANCE_TYPE)) {
+ if (argument.equals(APPLIANCE_TYPE)) {
+ return new ListCommand(APPLIANCE_TYPE, "");
+ } else if (str[1].trim().startsWith("l/")) {
+ return new ListCommand(APPLIANCE_TYPE, str[1].trim().substring(2));
+ } else {
+ return new InvalidCommand(MESSAGE_INVALID_LIST_COMMAND);
+ }
+ } else {
+ return new InvalidCommand(MESSAGE_INVALID_LIST_COMMAND);
+ }
+ }
+
+ //@@author fanceso
+
+ /**
+ * Checks if the parameter is numerical value.
+ *
+ * @param parameter parameter entered by user
+ * @throws InvalidNumericalValueException if the parameter is not numerical value
+ */
+ private static void checkIfParameterIsInt(String parameter) throws InvalidNumericalValueException {
+ try {
+ Integer.parseInt(parameter);
+ } catch (NumberFormatException e) {
+ throw new InvalidNumericalValueException();
+ }
+
+ }
+
+ /**
+ * Checks if the wattage entered by the user is valid.
+ *
+ * @param wattage parameter entered by user.
+ * @throws WattageExceedException if the wattage is less 1 or more than 9999.
+ * @throws InvalidNumericalValueException if the wattage is not an numerical value.
+ */
+ private static void testWattageValidity(String wattage) throws WattageExceedException,
+ InvalidNumericalValueException {
+ try {
+ int wattageValue = Integer.parseInt(wattage);
+ // Common appliance is between 1 to 9999 watts
+ if ((wattageValue < 1) || (wattageValue > 9999)) {
+ throw new WattageExceedException();
+ }
+ } catch (NumberFormatException e) {
+ throw new InvalidNumericalValueException();
+ }
+ }
+
+ //@@author zongxian-ctrl
+
+ /**
+ * Checks if the input is empty.
+ *
+ * @param input parameter entered by the user.
+ * @return true if input is empty.
+ */
+ private static boolean isEmptyInput(String input) {
+ return (input.isEmpty());
+ }
+
+
+ /**
+ * Check if the input contains illegal character.
+ *
+ * @param input parameter entered by the user.
+ * @return true if any illegal character is found.
+ */
+ private static boolean hasIllegalCharacter(String input) {
+ return (input.contains(" ") || input.contains("/") || input.contains("|"));
+ }
+
+}
+
diff --git a/src/main/java/seedu/smarthomebot/logic/parser/exceptions/EmptyParameterException.java b/src/main/java/seedu/smarthomebot/logic/parser/exceptions/EmptyParameterException.java
new file mode 100644
index 0000000000..c4a5723b6e
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/parser/exceptions/EmptyParameterException.java
@@ -0,0 +1,7 @@
+package seedu.smarthomebot.logic.parser.exceptions;
+
+/**
+ * Signals an empty parameter is found.
+ */
+public class EmptyParameterException extends Exception {
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/parser/exceptions/IllegalCharacterException.java b/src/main/java/seedu/smarthomebot/logic/parser/exceptions/IllegalCharacterException.java
new file mode 100644
index 0000000000..1de606ff38
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/parser/exceptions/IllegalCharacterException.java
@@ -0,0 +1,7 @@
+package seedu.smarthomebot.logic.parser.exceptions;
+
+/**
+ * Signals that illegal character is found.
+ */
+public class IllegalCharacterException extends Exception {
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/parser/exceptions/InvalidCommandException.java b/src/main/java/seedu/smarthomebot/logic/parser/exceptions/InvalidCommandException.java
new file mode 100644
index 0000000000..b71697a6b6
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/parser/exceptions/InvalidCommandException.java
@@ -0,0 +1,7 @@
+package seedu.smarthomebot.logic.parser.exceptions;
+
+/**
+ * Signal that an invalid command is entered.
+ */
+public class InvalidCommandException extends Exception{
+}
diff --git a/src/main/java/seedu/smarthomebot/logic/parser/exceptions/WattageExceedException.java b/src/main/java/seedu/smarthomebot/logic/parser/exceptions/WattageExceedException.java
new file mode 100644
index 0000000000..32f1cb5015
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/logic/parser/exceptions/WattageExceedException.java
@@ -0,0 +1,7 @@
+package seedu.smarthomebot.logic.parser.exceptions;
+
+/**
+ * Signal an error when the user enter power wattage which is not within the range.
+ */
+public class WattageExceedException extends Exception{
+}
diff --git a/src/main/java/seedu/smarthomebot/storage/ReadStorageFile.java b/src/main/java/seedu/smarthomebot/storage/ReadStorageFile.java
new file mode 100644
index 0000000000..61d2fd1362
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/storage/ReadStorageFile.java
@@ -0,0 +1,149 @@
+package seedu.smarthomebot.storage;
+
+import seedu.smarthomebot.commons.Messages;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.appliance.type.AirConditioner;
+import seedu.smarthomebot.data.appliance.type.Fan;
+import seedu.smarthomebot.data.appliance.type.Lights;
+import seedu.smarthomebot.data.appliance.type.SmartPlug;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.storage.exceptions.FileCorruptedException;
+import seedu.smarthomebot.ui.TextUi;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.NoSuchElementException;
+import java.util.Scanner;
+import java.util.logging.Level;
+
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_TYPE_NOT_EXIST;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_EMPTY_FILE;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_FILE_CORRUPTED;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_FILE_DOES_NOT_EXIST;
+
+//@@author TanLeeWei
+
+/**
+ * Represent reading of storage file back into the program.
+ */
+public class ReadStorageFile extends StorageFile {
+
+ private static String FILE_PATH;
+ private final TextUi ui = new TextUi();
+
+ public ReadStorageFile(String filePath, ApplianceList applianceList, LocationList locationList) {
+ super(applianceList, locationList);
+ FILE_PATH = filePath;
+ }
+
+ /**
+ * Executing the reading of storage file.
+ */
+ @Override
+ public void execute() {
+ try {
+ int i = 0;
+ assert FILE_PATH.equals("data/SmartHomeBot.txt") : "FILE_PATH should be data/SmartHome.txt";
+ File myFile = new File(FILE_PATH);
+ Scanner myReader = new Scanner(myFile);
+ String locationList = myReader.nextLine();
+ try {
+ readToLocationList(locationList);
+ readToApplianceList(i, myReader);
+ if (locationList.equals("[]")) {
+ ui.printToUser(MESSAGE_EMPTY_FILE);
+ } else {
+ ui.printToUser(Messages.MESSAGE_IMPORT);
+ }
+ } catch (FileCorruptedException e) {
+ storageLogger.log(Level.WARNING, MESSAGE_FILE_CORRUPTED);
+ ui.printToUser(Messages.MESSAGE_FILE_CORRUPTED);
+ }
+ storageLogger.log(Level.INFO, "Successfully loaded Save File");
+ myReader.close();
+ } catch (FileNotFoundException e) {
+ storageLogger.log(Level.WARNING, MESSAGE_FILE_DOES_NOT_EXIST);
+ ui.printToUser(MESSAGE_FILE_DOES_NOT_EXIST);
+ } catch (NoSuchElementException e) {
+ storageLogger.log(Level.WARNING, MESSAGE_FILE_CORRUPTED);
+ ui.printToUser(Messages.MESSAGE_FILE_CORRUPTED);
+ }
+ }
+
+ /**
+ * Method to read appliance from the storage file into ApplianceList.
+ *
+ * @param numberOfAppliance Keep track of the number of appliance.
+ * @param myReader Read each line in the .txt storage file into the program.
+ */
+ private void readToApplianceList(int numberOfAppliance, Scanner myReader) throws FileCorruptedException {
+ while (myReader.hasNextLine()) {
+ try {
+ String appliance = myReader.nextLine();
+ String[] splitString = appliance.split("\\|", 9);
+ if (splitString[1].isEmpty() || splitString[0].isEmpty()
+ || splitString[2].isEmpty() || splitString[3].isEmpty()) {
+ throw new FileCorruptedException();
+ }
+ String name = splitString[1];
+ String location = splitString[0];
+ String power = splitString[2];
+ String type = splitString[3];
+ String powerConsumption = splitString[4];
+ String parameter = splitString[5];
+
+ switch (type.toLowerCase()) {
+ case Fan.TYPE_WORD:
+ Fan fan = new Fan(name, location, power, locationList);
+ applianceList.addAppliance(fan);
+ fan.getSpeedFromLoadFile(parameter);
+ break;
+ case AirConditioner.TYPE_WORD:
+ AirConditioner ac = new AirConditioner(name, location, power, locationList);
+ applianceList.addAppliance(ac);
+ ac.getTemperatureFromLoadFile(parameter);
+ break;
+ case Lights.TYPE_WORD:
+ Lights light = new Lights(name, location, power, locationList);
+ applianceList.addAppliance(light);
+ break;
+ case SmartPlug.TYPE_WORD:
+ SmartPlug smartPlug = new SmartPlug(name, location, power, locationList);
+ applianceList.addAppliance(smartPlug);
+ break;
+ default:
+ ui.printToUser(MESSAGE_APPLIANCE_TYPE_NOT_EXIST);
+ }
+ applianceList.getAppliance(numberOfAppliance).loadDataFromFile(powerConsumption);
+ numberOfAppliance++;
+ storageLogger.log(Level.INFO, "Successfully read appliance into appliancelist");
+ } catch (Exception e) {
+ throw new FileCorruptedException();
+ }
+ }
+ }
+
+ /**
+ * Method to read location from the storage file into LocationList.
+ *
+ * @param location appliance location read from the .txt storage file.
+ */
+ private void readToLocationList(String location) throws FileCorruptedException {
+ try {
+ int openBracesIndex = location.indexOf("[") + 1;
+ int closeBracesIndex = location.lastIndexOf("]");
+ String locations = location.substring(openBracesIndex, closeBracesIndex);
+ String[] stringSplit = locations.split(",");
+ for (String locationName : stringSplit) {
+ if (!locationName.isEmpty() && !applianceList.isApplianceExist(locationName.trim())) {
+ locationList.addLocation(locationName.trim());
+ }
+ }
+ storageLogger.log(Level.INFO, "Successfully read location into locationList");
+ } catch (IndexOutOfBoundsException | DuplicateDataException e) {
+ throw new FileCorruptedException();
+ }
+
+ }
+}
diff --git a/src/main/java/seedu/smarthomebot/storage/StorageFile.java b/src/main/java/seedu/smarthomebot/storage/StorageFile.java
new file mode 100644
index 0000000000..08a5c762f2
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/storage/StorageFile.java
@@ -0,0 +1,32 @@
+package seedu.smarthomebot.storage;
+
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.location.LocationList;
+
+import java.util.logging.Logger;
+
+//@@author TanLeeWei
+
+/**
+ * Represent the parent class of ReadStorageFile and WriteStorageFile.
+ */
+public abstract class StorageFile {
+
+ protected static ApplianceList applianceList;
+ protected static LocationList locationList;
+ public static Logger storageLogger = Logger.getLogger("SmartHomeBotLogger");
+
+ /**
+ * Passes the ApplianceList and LocationList to allow ReadStorageFile and WriteStorageFile to use.
+ *
+ * @param applianceList stores the appliances in SmartHomeBot
+ * @param locationList stores the locations in SmartHomeBot
+ */
+ public StorageFile(ApplianceList applianceList, LocationList locationList) {
+ StorageFile.locationList = locationList;
+ StorageFile.applianceList = applianceList;
+ }
+
+ public abstract void execute();
+
+}
diff --git a/src/main/java/seedu/smarthomebot/storage/WriteStorageFile.java b/src/main/java/seedu/smarthomebot/storage/WriteStorageFile.java
new file mode 100644
index 0000000000..1f1feadb59
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/storage/WriteStorageFile.java
@@ -0,0 +1,90 @@
+package seedu.smarthomebot.storage;
+
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.ui.TextUi;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.logging.Level;
+
+import static seedu.smarthomebot.commons.Messages.MESSAGE_CLEAR_FILE_ERROR;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_FILE_CREATION_ERROR;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_WRITE_FILE_ERROR;
+
+//@@author TanLeeWei
+
+/**
+ * Represent the writing of data into the storage file.
+ */
+public class WriteStorageFile extends StorageFile {
+
+ private static String FILE_PATH;
+ private final TextUi ui = new TextUi();
+
+ public WriteStorageFile(String filePath, ApplianceList applianceList, LocationList locationList) {
+ super(applianceList, locationList);
+ this.FILE_PATH = filePath;
+ }
+
+ /**
+ * Execute the writing of data into storage file.
+ */
+ @Override
+ public void execute() {
+ try {
+ assert FILE_PATH.equals("data/SmartHomeBot.txt") : "FILE_PATH should be data/SmartHome.txt";
+ createFile();
+ clearFile();
+ FileWriter myWriter = new FileWriter(FILE_PATH);
+ myWriter.write(locationList.getAllLocations().toString() + "\n");
+ for (int i = 0; i < applianceList.getAllAppliance().size(); i++) {
+ myWriter.write(applianceList.getAppliance(i).writeFileFormat() + System.lineSeparator());
+ }
+ storageLogger.log(Level.INFO, "Successfully written data into Storage File");
+ myWriter.close();
+ } catch (IOException e) {
+ storageLogger.log(Level.WARNING, MESSAGE_WRITE_FILE_ERROR);
+ ui.printToUser(MESSAGE_WRITE_FILE_ERROR);
+ }
+ }
+
+ /**
+ * Method to create the .txt storage file and the storage file directory.
+ */
+ private void createFile() {
+ try {
+ assert FILE_PATH.equals("data/SmartHomeBot.txt") : "FILE_PATH should be data/SmartHome.txt";
+ File myObj = new File(FILE_PATH);
+ if (!myObj.getParentFile().exists()) {
+ myObj.getParentFile().mkdirs();
+ }
+ if (!myObj.exists()) {
+ myObj.createNewFile();
+ }
+ storageLogger.log(Level.INFO, "Successfully created Storage File");
+ } catch (IOException e) {
+ storageLogger.log(Level.WARNING, MESSAGE_FILE_CREATION_ERROR);
+ ui.printToUser(MESSAGE_FILE_CREATION_ERROR);
+ }
+ }
+
+ /**
+ * Method to clear the contents of the .txt storage file.
+ */
+ private void clearFile() {
+ try {
+ assert FILE_PATH.equals("data/SmartHomeBot.txt") : "FILE_PATH should be data/SmartHome.txt";
+ PrintWriter writer = new PrintWriter(FILE_PATH);
+ writer.print("");
+ writer.close();
+ storageLogger.log(Level.INFO, "Successfully cleared Storage File");
+ } catch (FileNotFoundException e) {
+ storageLogger.log(Level.WARNING, MESSAGE_CLEAR_FILE_ERROR);
+ ui.printToUser(MESSAGE_CLEAR_FILE_ERROR);
+ }
+ }
+}
diff --git a/src/main/java/seedu/smarthomebot/storage/exceptions/FileCorruptedException.java b/src/main/java/seedu/smarthomebot/storage/exceptions/FileCorruptedException.java
new file mode 100644
index 0000000000..9d1c60e155
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/storage/exceptions/FileCorruptedException.java
@@ -0,0 +1,4 @@
+package seedu.smarthomebot.storage.exceptions;
+
+public class FileCorruptedException extends Exception {
+}
diff --git a/src/main/java/seedu/smarthomebot/ui/TextUi.java b/src/main/java/seedu/smarthomebot/ui/TextUi.java
new file mode 100644
index 0000000000..4288f58fd9
--- /dev/null
+++ b/src/main/java/seedu/smarthomebot/ui/TextUi.java
@@ -0,0 +1,86 @@
+package seedu.smarthomebot.ui;
+
+import seedu.smarthomebot.logic.commands.CommandResult;
+
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Scanner;
+
+import static seedu.smarthomebot.commons.Messages.DIVIDER;
+import static seedu.smarthomebot.commons.Messages.LINE;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_EXPORT;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_GOODBYE;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_WELCOME;
+
+//@@author Ang-Cheng-Jun
+
+//Solution below adapted from https://github.com/nus-cs2113-AY2021S1/personbook
+/**
+ * Text UI of the application.
+ */
+public class TextUi {
+
+ private static final String ENTER_COMMAND = "Enter command: ";
+ private final Scanner in;
+ private final PrintStream out;
+
+ public TextUi() {
+ this(System.in, System.out);
+ }
+
+ public TextUi(InputStream in, PrintStream out) {
+ this.in = new Scanner(System.in);
+ this.out = out;
+ }
+
+ /**
+ * Prints message(s) to the user.
+ */
+ public void printToUser(String message) {
+ assert !message.isEmpty() : "Message must not be empty";
+ out.println(message);
+ }
+
+ /**
+ * Prints result(s) of the command to the user.
+ */
+ public void printResultToUser(CommandResult result) {
+ assert !result.feedbackToUser.isEmpty() : "The feedback for result cannot be empty";
+ printToUser(LINE + result.feedbackToUser);
+ }
+
+ /**
+ * Prints a divider.
+ */
+ private void printDivider() {
+ printToUser(DIVIDER);
+ }
+
+
+ /**
+ * Prompts for the command and reads the text entered by the user.
+ * @return command (full line) entered by the user.
+ */
+ public String getUserCommand() {
+ printDivider();
+ out.print(ENTER_COMMAND);
+ String fullInputLine = in.nextLine();
+ return fullInputLine.trim();
+ }
+
+ /**
+ * Generates and prints the Welcome message upon the end of the application.
+ */
+ public void showWelcomeMessage() {
+ printDivider();
+ printToUser(MESSAGE_WELCOME);
+ }
+
+ /**
+ * Generates and prints the Goodbye message upon the end of the application.
+ */
+ public void showGoodByeMessage() {
+ printToUser(MESSAGE_EXPORT);
+ printToUser(MESSAGE_GOODBYE);
+ }
+}
diff --git a/src/test/java/seedu/duke/DukeTest.java b/src/test/java/seedu/duke/DukeTest.java
deleted file mode 100644
index 2dda5fd651..0000000000
--- a/src/test/java/seedu/duke/DukeTest.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package seedu.duke;
-
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import org.junit.jupiter.api.Test;
-
-class DukeTest {
- @Test
- public void sampleTest() {
- assertTrue(true);
- }
-}
diff --git a/src/test/java/seedu/smarthomebot/data/appliance/ApplianceListTest.java b/src/test/java/seedu/smarthomebot/data/appliance/ApplianceListTest.java
new file mode 100644
index 0000000000..6f07ee6259
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/data/appliance/ApplianceListTest.java
@@ -0,0 +1,99 @@
+package seedu.smarthomebot.data.appliance;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.commons.exceptions.ApplianceNotFoundException;
+
+import seedu.smarthomebot.data.appliance.type.Fan;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+public class ApplianceListTest {
+
+ private LocationList myHome;
+ private ArrayList expectedOutput;
+ private ApplianceList applianceList;
+ private ArrayList emptyList;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ applianceList = new ApplianceList();
+ emptyList = new ArrayList<>();
+ expectedOutput = new ArrayList<>();
+ myHome = new LocationList();
+
+ myHome.addLocation("MasterRoom");
+ Fan newFan = new Fan("Fan", "MasterRoom", "150", myHome);
+ applianceList.addAppliance(newFan);
+ expectedOutput.add(newFan.toString());
+
+ }
+
+ @Test
+ void addAppliance_ApplianceNotInList_ApplianceAddedNormally() {
+ for (int i = 0; i < applianceList.getAllAppliance().size(); i++) {
+ assertEquals(applianceList.getAppliance(i).toString(), expectedOutput.get(i));
+ }
+ }
+
+ @Test
+ void addAppliance_ApplianceNotInList_LocationNotInLocationList() {
+ assertThrows(LocationNotFoundException.class, () ->
+ new Fan("Fan", "Bedroom1", "150", myHome));
+ }
+
+ @Test
+ void deleteAppliance_ApplianceInList_ApplianceDeleteNormally() {
+ assertDoesNotThrow(() -> applianceList.deleteAppliance("Fan"));
+
+ }
+
+ @Test
+ void deleteAppliance_ApplianceInList_ExceptionThrown() {
+ assertThrows(ApplianceNotFoundException.class, () ->
+ applianceList.deleteAppliance("Fan3"));
+
+ }
+
+ @Test
+ void isApplianceExist_ApplianceInList_IsTrue() {
+ assertTrue(() -> applianceList.isApplianceExist("Fan"));
+ }
+
+ @Test
+ void isApplianceExist_ApplianceInList_IsFalse() {
+ assertFalse(() -> applianceList.isApplianceExist("Fan3"));
+ }
+
+ @Test
+ void getApplianceIndex_ApplianceInList_GetNormally() {
+ assertDoesNotThrow(() -> applianceList.getApplianceIndex("Fan"));
+ }
+
+ @Test
+ void getApplianceIndex_ApplianceNotInList_exceptionThrown() {
+ assertThrows(ApplianceNotFoundException.class, () ->
+ applianceList.getApplianceIndex("Fan3"));
+ }
+
+ @Test
+ void deleteByLocation_LocationInList_DeleteNormally() {
+ assertDoesNotThrow(() ->
+ applianceList.deleteByLocation("MasterRoom"));
+ }
+
+ @Test
+ void getAppliance_ApplianceInList_GetNormally() {
+ assertDoesNotThrow(() -> applianceList.getAppliance(0));
+ }
+
+
+}
diff --git a/src/test/java/seedu/smarthomebot/data/appliance/PowerTest.java b/src/test/java/seedu/smarthomebot/data/appliance/PowerTest.java
new file mode 100644
index 0000000000..ca95b8b5f1
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/data/appliance/PowerTest.java
@@ -0,0 +1,80 @@
+package seedu.smarthomebot.data.appliance;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.appliance.type.Fan;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+//@@author fanceso
+
+class PowerTest {
+
+ private Appliance coolingFan;
+ private LocationList locationList;
+
+ @BeforeEach
+ public void setUp() throws InvalidApplianceNameException, LocationNotFoundException, DuplicateDataException {
+ String bedroom = "bedroom";
+ locationList = new LocationList();
+ locationList.addLocation(bedroom);
+ coolingFan = new Fan("PowerfulSpeedy", bedroom, "9000", locationList);
+ }
+
+ @Test
+ void onAppliance_applianceOffPreviously_onNormally() {
+ coolingFan.switchOff();
+ assertTrue(coolingFan.switchOn());
+ }
+
+ @Test
+ void onAppliance_applianceAlreadyOn_returnFalse() {
+ coolingFan.switchOn();
+ assertFalse(coolingFan.switchOn());
+ }
+
+ @Test
+ void offAppliance_applianceOnPreviously_onNormally() {
+ coolingFan.switchOn();
+ assertTrue(coolingFan.switchOff());
+ }
+
+ @Test
+ void offAppliance_applianceAlreadyOff_returnFalse() {
+ coolingFan.switchOff();
+ assertFalse(coolingFan.switchOff());
+ }
+
+ @Test
+ void resetPower_fanOnForThreeSeconds_powerResetToZero() throws InterruptedException {
+ useFanForThreeSeconds();
+ coolingFan.resetPowerUsage();
+ assertEquals("0.00", coolingFan.getPowerInString());
+ }
+
+ @Test
+ void getPower_fanOnForThreeSeconds_returnPowerValue() throws InterruptedException {
+ useFanForThreeSeconds();
+ assertEquals(0.01, coolingFan.getPowerInDouble());
+ }
+
+ @Test
+ void testToString() throws InterruptedException {
+ useFanForThreeSeconds();
+ assertEquals("0.01", coolingFan.getPowerInString());
+ }
+
+ private void useFanForThreeSeconds() throws InterruptedException {
+ coolingFan.switchOn();
+ // Appliance will be on for 3000ms which equals to 30 minutes in SmartHomeBot
+ Thread.sleep(3000);
+ coolingFan.switchOff();
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/smarthomebot/data/appliance/type/AirConditionerTest.java b/src/test/java/seedu/smarthomebot/data/appliance/type/AirConditionerTest.java
new file mode 100644
index 0000000000..386cae8fff
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/data/appliance/type/AirConditionerTest.java
@@ -0,0 +1,43 @@
+package seedu.smarthomebot.data.appliance.type;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class AirConditionerTest {
+
+ private AirConditioner ac;
+
+ @BeforeEach
+ void setUp() throws InvalidApplianceNameException, LocationNotFoundException, DuplicateDataException {
+ String bedroom = "bedroom";
+ LocationList locationList = new LocationList();
+ locationList.addLocation(bedroom);
+ ac = new AirConditioner("ac1", bedroom, "2000", locationList);
+ }
+
+ @Test
+ void getParameterTest_returnsTemperature() {
+ assertEquals("25 Degrees", ac.getParameter(true));
+ }
+
+ @Test
+ void setSpeedTest_returnTrue() {
+ assertEquals(true, ac.setTemperature("25"));
+ }
+
+ @Test
+ void getTypeTest_returnsAircon() {
+ assertEquals("aircon", ac.getType());
+ }
+
+ @Test
+ void testToString_returnsNameLocationPower() {
+ assertEquals("ac1(2000W), located at bedroom ", ac.toString());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/smarthomebot/data/appliance/type/FanTest.java b/src/test/java/seedu/smarthomebot/data/appliance/type/FanTest.java
new file mode 100644
index 0000000000..88c1eff98b
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/data/appliance/type/FanTest.java
@@ -0,0 +1,44 @@
+package seedu.smarthomebot.data.appliance.type;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class FanTest {
+
+ private Fan fan;
+
+ @BeforeEach
+ void setUp() throws InvalidApplianceNameException, LocationNotFoundException, DuplicateDataException {
+ String bedroom = "bedroom";
+ LocationList locationList = new LocationList();
+ locationList.addLocation(bedroom);
+ fan = new Fan("fanny", bedroom, "150", locationList);
+ }
+
+ @Test
+ void getParameterTest_returnsSpeed() {
+ assertEquals("Speed 1", fan.getParameter(true));
+ }
+
+ @Test
+ void setSpeedTest_returnTrue() {
+ assertEquals(true, fan.setSpeed("2"));
+ }
+
+ @Test
+ void getTypeTest_returnsfan() {
+ assertEquals("fan", fan.getType());
+ }
+
+ @Test
+ void testToString_returnsNameLocationPower() {
+ assertEquals("fanny(150W), located at bedroom ", fan.toString());
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/smarthomebot/data/appliance/type/LightsTest.java b/src/test/java/seedu/smarthomebot/data/appliance/type/LightsTest.java
new file mode 100644
index 0000000000..0a9797a3e7
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/data/appliance/type/LightsTest.java
@@ -0,0 +1,34 @@
+package seedu.smarthomebot.data.appliance.type;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class LightsTest {
+
+ private Appliance light;
+
+ @BeforeEach
+ void setUp() throws InvalidApplianceNameException, LocationNotFoundException, DuplicateDataException {
+ String bedroom = "bedroom";
+ LocationList locationList = new LocationList();
+ locationList.addLocation(bedroom);
+ light = new Lights("pluggy", bedroom, "150", locationList);
+ }
+
+ @Test
+ void getTypeTest_returnsLight() {
+ assertEquals("light", light.getType());
+ }
+
+ @Test
+ void getParameterTest_returnsNone() {
+ assertEquals("None", light.getParameter(true));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/smarthomebot/data/appliance/type/SmartPlugTest.java b/src/test/java/seedu/smarthomebot/data/appliance/type/SmartPlugTest.java
new file mode 100644
index 0000000000..6a85dfbb05
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/data/appliance/type/SmartPlugTest.java
@@ -0,0 +1,34 @@
+package seedu.smarthomebot.data.appliance.type;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.appliance.Appliance;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class SmartPlugTest {
+
+ private Appliance smartPlug;
+
+ @BeforeEach
+ void setUp() throws InvalidApplianceNameException, LocationNotFoundException, DuplicateDataException {
+ String bedroom = "bedroom";
+ LocationList locationList = new LocationList();
+ locationList.addLocation(bedroom);
+ smartPlug = new SmartPlug("pluggy", bedroom, "150", locationList);
+ }
+
+ @Test
+ void getTypeTest_returnsSmartPlug() {
+ assertEquals("smartplug", smartPlug.getType());
+ }
+
+ @Test
+ void getParameterTest_returnsNone() {
+ assertEquals("None", smartPlug.getParameter(true));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/smarthomebot/data/location/LocationListTest.java b/src/test/java/seedu/smarthomebot/data/location/LocationListTest.java
new file mode 100644
index 0000000000..6d041d1b36
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/data/location/LocationListTest.java
@@ -0,0 +1,67 @@
+package seedu.smarthomebot.data.location;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.commons.exceptions.InvalidLocationException;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class LocationListTest {
+
+ private LocationList myHome;
+ private ArrayList expectedOutput;
+ private ArrayList emptyList;
+
+ @BeforeEach
+ void setUp() throws Exception {
+ myHome = new LocationList();
+ myHome.addLocation("LivingRoom");
+ expectedOutput = new ArrayList<>();
+ expectedOutput.add("LivingRoom");
+ emptyList = new ArrayList<>();
+ }
+
+ @Test
+ void addLocation_locationNotInList_locationAddedNormally() throws DuplicateDataException {
+ myHome.addLocation("MasterRoom");
+ expectedOutput.add("MasterRoom");
+ assertEquals(expectedOutput, myHome.getAllLocations());
+ }
+
+ @Test
+ void addLocation_locationAlreadyInList_throwsDuplicateDataException() {
+ assertThrows(DuplicateDataException.class, () -> myHome.addLocation("LivingRoom"));
+ }
+
+ @Test
+ void removeLocation_locationInList_locationRemovedNormally() throws InvalidLocationException {
+ myHome.removeLocation("LivingRoom");
+ assertEquals(emptyList, myHome.getAllLocations());
+ }
+
+ @Test
+ void removeLocation_locationNotExist_throws_InvalidRemovalLocationException() {
+ assertThrows(InvalidLocationException.class, () -> myHome.removeLocation("Other Places"));
+ }
+
+ @Test
+ void getLocations() {
+ assertEquals(expectedOutput, myHome.getAllLocations());
+ }
+
+ @Test
+ void testToString() {
+ assertEquals("LivingRoom\n", myHome.toString());
+ }
+
+ @Test
+ void isLocationCreated_locationInList_returnTrue() {
+ assertTrue(myHome.isLocationCreated("LivingRoom"));
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/smarthomebot/logic/ParserTest.java b/src/test/java/seedu/smarthomebot/logic/ParserTest.java
new file mode 100644
index 0000000000..d98c767598
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/ParserTest.java
@@ -0,0 +1,165 @@
+package seedu.smarthomebot.logic;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.logic.commands.AddCommand;
+import seedu.smarthomebot.logic.commands.Command;
+import seedu.smarthomebot.logic.commands.CreateCommand;
+import seedu.smarthomebot.logic.commands.DeleteCommand;
+import seedu.smarthomebot.logic.commands.ExitCommand;
+import seedu.smarthomebot.logic.commands.HelpCommand;
+import seedu.smarthomebot.logic.commands.InvalidCommand;
+import seedu.smarthomebot.logic.commands.ListCommand;
+import seedu.smarthomebot.logic.commands.OffCommand;
+import seedu.smarthomebot.logic.commands.OnCommand;
+import seedu.smarthomebot.logic.commands.RemoveCommand;
+import seedu.smarthomebot.logic.commands.UsageCommand;
+import seedu.smarthomebot.logic.parser.Parser;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_EMPTY_PARAMETER;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_INVALID_ADD_COMMAND;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_INVALID_LIST_COMMAND;
+
+class ParserTest {
+
+ private Parser parser;
+
+ @BeforeEach
+ public void setUp() {
+ parser = new Parser();
+ }
+
+
+ @Test
+ public void parse_emptyInput_returnsInvalid() {
+ final String[] emptyInputs = {"", " ", "\n \n"};
+ final String resultMessage = (MESSAGE_INVALID_COMMAND_FORMAT);
+ parseAndAssertIncorrectWithMessage(resultMessage, emptyInputs);
+ }
+
+ @Test
+ public void parse_helpCommand_parsedCorrectly() {
+ final String input = "help";
+ parseAndAssertCommand(input, HelpCommand.class);
+ }
+
+ @Test
+ public void parse_createCommand_parserCorrectly() {
+ final String input = "create Bedroom1";
+ parseAndAssertCommand(input, CreateCommand.class);
+ }
+
+ @Test
+ public void parse_addCommand_parserCorrectly() {
+ final String input = "add Lightbulb l/Kitchen w/ 100 t/Light";
+ parseAndAssertCommand(input, AddCommand.class);
+ }
+
+ @Test
+ public void parse_exitCommand_parserCorrectly() {
+ final String input = "exit";
+ parseAndAssertCommand(input, ExitCommand.class);
+ }
+
+ @Test
+ public void parse_invalidCommand_parserCorrectly() {
+ final String input = "SmartHomeBot";
+ parseAndAssertCommand(input, InvalidCommand.class);
+ }
+
+ @Test
+ public void parse_deleteCommand_parserCorrectly() {
+ final String input = "delete Lightbulb";
+ parseAndAssertCommand(input, DeleteCommand.class);
+ }
+
+ @Test
+ public void parse_removeCommand_parserCorrectly() {
+ final String input = "remove Bedroom1";
+ parseAndAssertCommand(input, RemoveCommand.class);
+ }
+
+ @Test
+ public void parse_usageCommand_parserCorrectly() {
+ final String input = "usage";
+ parseAndAssertCommand(input, UsageCommand.class);
+ }
+
+ @Test
+ public void parse_onCommand_parserCorrectly() {
+ final String input = "on Lightbulb";
+ parseAndAssertCommand(input, OnCommand.class);
+ }
+
+ @Test
+ public void parse_offCommand_parserCorrectly() {
+ final String input = "off Lightbulb";
+ parseAndAssertCommand(input, OffCommand.class);
+ }
+
+ @Test
+ public void parse_listCommand_parserCorrectly() {
+ final String input = "list appliance";
+ parseAndAssertCommand(input, ListCommand.class);
+ }
+
+ @Test
+ public void parse_CommandsWithNoParameter_errorMessage() {
+ final String[] inputs = {
+ "create", "create ", "delete", "delete ",
+ "on", "on ", "off", "off ", "remove", "remove "
+ };
+ final String resultMessage = MESSAGE_EMPTY_PARAMETER;
+ parseAndAssertIncorrectWithMessage(resultMessage, inputs);
+ }
+
+ @Test
+ public void parse_listCommandNoParameter_errorMessage() {
+ final String[] inputs = {"list", "list ", "list appliance b/"};
+ final String resultMessage = MESSAGE_INVALID_LIST_COMMAND;
+ parseAndAssertIncorrectWithMessage(resultMessage, inputs);
+ }
+
+ @Test
+ public void parse_addCommandInvalidParameter_errorMessage() {
+ final String[] inputs = {
+ "add Light t/100 l/BR1 w/fan", "add ", "add appliance b/",
+ "add Light l/BR1 w/fan", "add Light", "add Light 1234"
+ };
+ final String resultMessage = MESSAGE_INVALID_ADD_COMMAND;
+ parseAndAssertIncorrectWithMessage(resultMessage, inputs);
+ }
+
+ @Test
+ public void parse_addCommandEmptyParameter_errorMessage() {
+ final String[] inputs = {
+ "add Light l/ w/100 t/fan", "add Light l/BR1 w/ t/fan",
+ "add Light l/BR1 w/100 t/"
+ };
+ final String resultMessage = MESSAGE_EMPTY_PARAMETER;
+ parseAndAssertIncorrectWithMessage(resultMessage, inputs);
+ }
+
+
+ /**
+ * Asserts that parsing the given inputs will return InvalidCommand with the given feedback.
+ */
+ private void parseAndAssertIncorrectWithMessage(String feedback, String... inputs) {
+ for (String input : inputs) {
+ final InvalidCommand result = parseAndAssertCommand(input, InvalidCommand.class);
+ assertEquals(result.feedbackToUser, feedback);
+ }
+ }
+
+ /**
+ * Parses input and assert it is the correct class command object.
+ */
+ private T parseAndAssertCommand(String input, Class expectedCommandClass) {
+ final Command result = parser.parseCommand(input);
+ assertTrue(result.getClass().isAssignableFrom(expectedCommandClass));
+ return (T) result;
+ }
+}
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/AddCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/AddCommandTest.java
new file mode 100644
index 0000000000..3757fcc731
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/AddCommandTest.java
@@ -0,0 +1,93 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.appliance.type.Lights;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_EXIST;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_LOCATION_CONFLICT;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_TYPE_NOT_EXIST;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LOCATION_NOT_EXIST;
+
+public class AddCommandTest {
+
+ private LocationList locationList = new LocationList();
+ private ApplianceList applianceList = new ApplianceList();
+
+ @BeforeEach
+ public void setup() throws DuplicateDataException, InvalidApplianceNameException, LocationNotFoundException {
+ locationList.addLocation("BedRoom1");
+ Lights l1 = new Lights("l1", "BedRoom1", "50", locationList);
+ applianceList.addAppliance(l1);
+ }
+
+ @Test
+ void addApplianceTest_Fan_addFanSuccess() {
+ Command addAppliance = new AddCommand("Fan1", "BedRoom1", "50", "Fan");
+ addAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = addAppliance.execute();
+ assertEquals("ADDING Fan1(50W), located at BedRoom1 ......ADDED!", actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void addApplianceTest_Light_addLightSuccess() {
+ Command addAppliance = new AddCommand("l2", "BedRoom1", "50", "light");
+ addAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = addAppliance.execute();
+ assertEquals("ADDING l2(50W), located at BedRoom1 ......ADDED!", actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void addApplianceTest_AirConditioner_addAirConditionerSuccess() {
+ Command addAppliance = new AddCommand("AC1", "BedRoom1", "500", "aircon");
+ addAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = addAppliance.execute();
+ assertEquals("ADDING AC1(500W), located at BedRoom1 ......ADDED!", actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void addApplianceTest_SmartPlug_addSmartPlugSuccess() {
+ Command addAppliance = new AddCommand("Plug1", "BedRoom1", "500", "smartplug");
+ addAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = addAppliance.execute();
+ assertEquals("ADDING Plug1(500W), located at BedRoom1 ......ADDED!", actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void addApplianceTest_TypeNotFound_addApplianceFailed() {
+ Command addAppliance = new AddCommand("Plug1", "BedRoom1", "500", "plug");
+ addAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = addAppliance.execute();
+ assertEquals(MESSAGE_APPLIANCE_TYPE_NOT_EXIST, actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void addApplianceTest_DuplicateAppliance_DuplicateDataException() {
+ Command addAppliance = new AddCommand("l1", "BedRoom1", "500", "light");
+ addAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = addAppliance.execute();
+ assertEquals(MESSAGE_APPLIANCE_EXIST, actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void addApplianceTest_LocationNotCreated_LocationNotFoundException() {
+ Command addAppliance = new AddCommand("l1", "BedRoom2", "500", "light");
+ addAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = addAppliance.execute();
+ assertEquals(MESSAGE_LOCATION_NOT_EXIST, actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void addApplianceTest_DuplicateNameAsLocation_InvalidApplianceNameException() {
+ Command addAppliance = new AddCommand("BedRoom1", "BedRoom1", "500", "light");
+ addAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = addAppliance.execute();
+ assertEquals(MESSAGE_APPLIANCE_LOCATION_CONFLICT, actualCommandResult.feedbackToUser);
+ }
+}
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/CommandResultTest.java b/src/test/java/seedu/smarthomebot/logic/commands/CommandResultTest.java
new file mode 100644
index 0000000000..922c77e7ba
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/CommandResultTest.java
@@ -0,0 +1,21 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class CommandResultTest {
+
+ @Test
+ public void equals() {
+ CommandResult commandResult = new CommandResult("feedback");
+
+ // test if same value -> returns true
+ assertTrue(commandResult.feedbackToUser.equals("feedback"));
+
+ // test if not same value -> return false
+ assertFalse(commandResult.feedbackToUser.equals("False"));
+
+ }
+}
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/CreateCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/CreateCommandTest.java
new file mode 100644
index 0000000000..3e5b21370f
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/CreateCommandTest.java
@@ -0,0 +1,52 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.appliance.type.Lights;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LOCATION_EXIST;
+
+public class CreateCommandTest {
+
+ private LocationList locationList = new LocationList();
+ private ApplianceList applianceList = new ApplianceList();
+
+ @BeforeEach
+ public void setup() throws DuplicateDataException, InvalidApplianceNameException, LocationNotFoundException {
+ locationList.addLocation("BedRoom1");
+ Lights l1 = new Lights("l1", "BedRoom1", "50", locationList);
+ applianceList.addAppliance(l1);
+ }
+
+ @Test
+ void createLocationTest_createLocationSuccess() {
+ Command createLocation = new CreateCommand("BedRoom3");
+ createLocation.setData(applianceList, locationList);
+ CommandResult actualCommandResult = createLocation.execute();
+ assertEquals("Creating Location \"BedRoom3\".....CREATED!", actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void createLocationTest_DuplicateLocation_DuplicateDataException() {
+ Command createLocation = new CreateCommand("BedRoom1");
+ createLocation.setData(applianceList, locationList);
+ CommandResult actualCommandResult = createLocation.execute();
+ assertEquals(MESSAGE_LOCATION_EXIST, actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void createLocationTest_DuplicateNameAsAppliance_InvalidLocationException() {
+ Command createLocation = new CreateCommand("l1");
+ createLocation.setData(applianceList, locationList);
+ CommandResult actualCommandResult = createLocation.execute();
+ assertEquals(MESSAGE_LOCATION_EXIST + " as an Appliance, please choose another name.",
+ actualCommandResult.feedbackToUser);
+ }
+}
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/DeleteCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/DeleteCommandTest.java
new file mode 100644
index 0000000000..4b92578bc7
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/DeleteCommandTest.java
@@ -0,0 +1,45 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.appliance.type.Lights;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class DeleteCommandTest {
+
+ private LocationList locationList = new LocationList();
+ private ApplianceList applianceList = new ApplianceList();
+
+ @BeforeEach
+ public void setup() throws DuplicateDataException,InvalidApplianceNameException, LocationNotFoundException {
+ locationList.addLocation("BedRoom1");
+ Lights l1 = new Lights("l1", "BedRoom1", "50", locationList);
+ Lights l2 = new Lights("l2", "BedRoom1", "50", locationList);
+ applianceList.addAppliance(l1);
+ applianceList.addAppliance(l2);
+ }
+
+ @Test
+ void deleteApplianceTest_deleteApplianceSuccess() {
+ Command deleteAppliance = new DeleteCommand("l2");
+ deleteAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = deleteAppliance.execute();
+ assertEquals("Deleting l2(50W), located at BedRoom1 .......DELETED.", actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void deleteApplianceTest_ApplianceNotIsList_ApplianceNotFoundException() {
+ Command deleteAppliance = new DeleteCommand("l3");
+ deleteAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = deleteAppliance.execute();
+ assertEquals("l3 does not exist.", actualCommandResult.feedbackToUser);
+ }
+
+}
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/ExitCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/ExitCommandTest.java
new file mode 100644
index 0000000000..858fc989bd
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/ExitCommandTest.java
@@ -0,0 +1,22 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.smarthomebot.logic.commands.ExitCommand.isExit;
+
+class ExitCommandTest {
+
+ @Test
+ void isExit_returnTrue() {
+ Command c = new ExitCommand();
+ assertEquals(true, isExit(c));
+ }
+
+ @Test
+ void isExit_returnFalse() {
+ Command c = new ListCommand("appliance", "");
+ assertEquals(false, isExit(c));
+ }
+
+}
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/HelpCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/HelpCommandTest.java
new file mode 100644
index 0000000000..cbe58d9dae
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/HelpCommandTest.java
@@ -0,0 +1,15 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class HelpCommandTest {
+
+ @Test
+ public void execute_help_success() {
+ HelpCommand helpCommand = new HelpCommand();
+ CommandResult expectedCommandResult = helpCommand.execute();
+ assertEquals(expectedCommandResult.feedbackToUser, HelpCommand.MESSAGE_HELP);
+ }
+}
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/InvalidCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/InvalidCommandTest.java
new file mode 100644
index 0000000000..0531d3bfd1
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/InvalidCommandTest.java
@@ -0,0 +1,16 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_EMPTY_PARAMETER;
+
+class InvalidCommandTest {
+
+ @Test
+ public void execute_invalid_success() {
+ InvalidCommand invalidCommand = new InvalidCommand(MESSAGE_EMPTY_PARAMETER);
+ CommandResult expectedCommandResult = invalidCommand.execute();
+ assertEquals(expectedCommandResult.feedbackToUser, MESSAGE_EMPTY_PARAMETER);
+ }
+}
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/ListCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/ListCommandTest.java
new file mode 100644
index 0000000000..0c27705b16
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/ListCommandTest.java
@@ -0,0 +1,58 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.location.LocationList;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LIST_NO_APPLIANCES;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LIST_NO_LOCATIONS;
+
+public class ListCommandTest {
+
+ @Test
+ void listLocation_EmptyLocationList_EmptyLocationListException() {
+ LocationList locationList = new LocationList();
+ ApplianceList applianceList = new ApplianceList();
+ Command listLocation = new ListCommand("location", "");
+ listLocation.setData(applianceList, locationList);
+ CommandResult actualCommandResult = listLocation.execute();
+ assertEquals(MESSAGE_LIST_NO_LOCATIONS, actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void listAppliance_EmptyApplianceList_EmptyApplianceListException() {
+ LocationList locationList = new LocationList();
+ ApplianceList applianceList = new ApplianceList();
+ Command listAppliance = new ListCommand("appliance", "");
+ listAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = listAppliance.execute();
+ assertEquals(MESSAGE_LIST_NO_APPLIANCES, actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void listApplianceByFilteredLocation_NoApplianceInFilteredLocation_NoApplianceInLocationException() throws
+ DuplicateDataException {
+ LocationList locationList = new LocationList();
+ ApplianceList applianceList = new ApplianceList();
+ locationList.addLocation("BedRoom1");
+ Command listFilteredAppliance = new ListCommand("appliance", "BedRoom1");
+ listFilteredAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = listFilteredAppliance.execute();
+ assertEquals("There is no Appliance in \"BedRoom1\".",actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void listApplianceByFilteredLocation_FilteredLocationNotFound_LocationNotFoundException() throws
+ DuplicateDataException {
+ LocationList locationList = new LocationList();
+ ApplianceList applianceList = new ApplianceList();
+ locationList.addLocation("BedRoom1");
+ Command listFilteredAppliance = new ListCommand("appliance", "BedRoom2");
+ listFilteredAppliance.setData(applianceList, locationList);
+ CommandResult actualCommandResult = listFilteredAppliance.execute();
+ assertEquals("Location: \"BedRoom2\" does not exist.", actualCommandResult.feedbackToUser);
+ }
+}
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/OffCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/OffCommandTest.java
new file mode 100644
index 0000000000..77c9f7bc0a
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/OffCommandTest.java
@@ -0,0 +1,51 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.appliance.type.Fan;
+import seedu.smarthomebot.data.location.LocationList;
+
+import java.util.ArrayList;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST;
+
+public class OffCommandTest {
+
+ private LocationList myHome;
+ private ArrayList expectedOutput;
+ private ApplianceList applianceList;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ applianceList = new ApplianceList();
+ expectedOutput = new ArrayList<>();
+ myHome = new LocationList();
+ myHome.addLocation("MasterRoom");
+ Fan newFan = new Fan("Fan", "MasterRoom", "150", myHome);
+ applianceList.addAppliance(newFan);
+ expectedOutput.add(newFan.toString());
+
+ }
+
+ @Test
+ void offCommandTest_OffNormally() {
+ applianceList.getAppliance(0).switchOn();
+ Command offCommand = new OffCommand("Fan");
+ offCommand.setData(applianceList, myHome);
+ assertDoesNotThrow(() -> offCommand.execute());
+ }
+
+ @Test
+ void offCommandTest_ApplianceNotFoundException() {
+ Command offCommand = new OffCommand("Fan1");
+ offCommand.setData(applianceList, myHome);
+ CommandResult actualCommandResult = offCommand.execute();
+ assertEquals(MESSAGE_APPLIANCE_OR_LOCATION_NOT_EXIST, actualCommandResult.feedbackToUser);
+ }
+
+}
+
+
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/OnCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/OnCommandTest.java
new file mode 100644
index 0000000000..d6a9ef7f5f
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/OnCommandTest.java
@@ -0,0 +1,48 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.appliance.type.Fan;
+import seedu.smarthomebot.data.location.LocationList;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class OnCommandTest {
+
+ private LocationList myHome;
+ private ApplianceList applianceList;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+ applianceList = new ApplianceList();
+ myHome = new LocationList();
+ myHome.addLocation("MasterRoom");
+ Fan newFan = new Fan("Fan", "MasterRoom", "150", myHome);
+ applianceList.addAppliance(newFan);
+
+
+ }
+
+ @Test
+ void onCommandTest_OnNormally() {
+ Command onCommand = new OnCommand("Fan", "");
+ onCommand.setData(applianceList, myHome);
+ assertDoesNotThrow(() -> onCommand.execute());
+ }
+
+ @Test
+ void onCommandTest_ParameterFoundException() {
+ Command onCommand = new OnCommand("Fan", "-2");
+ onCommand.setData(applianceList, myHome);
+ String expectedOutput = "Invalid speed is detected, "
+ + "ensure that it is within 1-3 speed.\n"
+ + "Previous set speed will be set.Switching Fan(150W), located at MasterRoom @ Speed 1.....ON";
+ CommandResult actualCommandResult = onCommand.execute();
+ assertEquals(expectedOutput, actualCommandResult.feedbackToUser);
+ }
+
+}
+
+
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/RemoveCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/RemoveCommandTest.java
new file mode 100644
index 0000000000..84c9732bec
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/RemoveCommandTest.java
@@ -0,0 +1,42 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LOCATION_NOT_EXIST;
+
+
+public class RemoveCommandTest {
+
+ private LocationList locationList = new LocationList();
+ private ApplianceList applianceList = new ApplianceList();
+
+ @BeforeEach
+ public void setup() throws DuplicateDataException {
+ locationList.addLocation("BedRoom1");
+ locationList.addLocation("BedRoom2");
+ }
+
+ @Test
+ void removeLocationTest_removeLocationSuccess() {
+ Command removeLocation = new RemoveCommand("BedRoom1");
+ removeLocation.setData(applianceList, locationList);
+ CommandResult actualCommandResult = removeLocation.execute();
+ assertEquals("Removing LOCATION \"BedRoom1\"......REMOVED!", actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void removeLocationTest_LocationNotInList_catch_InvalidLocationException() {
+ Command removeLocation = new RemoveCommand("BedRoom3");
+ removeLocation.setData(applianceList, locationList);
+ CommandResult actualCommandResult = removeLocation.execute();
+ assertEquals(MESSAGE_LOCATION_NOT_EXIST + " Nothing will be deleted.", actualCommandResult.feedbackToUser);
+ }
+
+}
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/ResetCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/ResetCommandTest.java
new file mode 100644
index 0000000000..e5c471bc10
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/ResetCommandTest.java
@@ -0,0 +1,46 @@
+package seedu.smarthomebot.logic.commands;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.appliance.type.Fan;
+import seedu.smarthomebot.data.appliance.type.Lights;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LIST_NO_APPLIANCES;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_USAGE_RESET;
+
+class ResetCommandTest {
+
+ private final ApplianceList emptyApplianceList = new ApplianceList();
+ private LocationList locationList = new LocationList();
+ private ApplianceList applianceList = new ApplianceList();
+
+
+ @Test
+ void resetTest_EmptyApplianceList_EmptyApplianceListException() {
+ Command resetPower = new ResetCommand();
+ resetPower.setData(emptyApplianceList, locationList);
+ CommandResult actualCommandResult = resetPower.execute();
+ assertEquals(MESSAGE_LIST_NO_APPLIANCES, actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void resetTest_resetPowerUsageSuccess() throws DuplicateDataException,
+ InvalidApplianceNameException, LocationNotFoundException {
+ locationList.addLocation("BedRoom");
+ Lights light = new Lights("BrightLight", "BedRoom", "100", locationList);
+ Fan fan = new Fan("SpeedyFan", "BedRoom", "50", locationList);
+ applianceList.addAppliance(light);
+ applianceList.addAppliance(fan);
+ Command resetPower = new ResetCommand();
+ resetPower.setData(emptyApplianceList, locationList);
+ CommandResult actualCommandResult = resetPower.execute();
+ assertEquals(MESSAGE_USAGE_RESET, actualCommandResult.feedbackToUser);
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/smarthomebot/logic/commands/UsageCommandTest.java b/src/test/java/seedu/smarthomebot/logic/commands/UsageCommandTest.java
new file mode 100644
index 0000000000..541f82509f
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/logic/commands/UsageCommandTest.java
@@ -0,0 +1,44 @@
+package seedu.smarthomebot.logic.commands;
+
+
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.commons.exceptions.DuplicateDataException;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.appliance.type.Lights;
+import seedu.smarthomebot.data.location.LocationList;
+import seedu.smarthomebot.logic.commands.exceptions.InvalidApplianceNameException;
+import seedu.smarthomebot.logic.commands.exceptions.LocationNotFoundException;
+
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static seedu.smarthomebot.commons.Messages.MESSAGE_LIST_NO_APPLIANCES;
+
+class UsageCommandTest {
+
+ private final ApplianceList emptyApplianceList = new ApplianceList();
+ private LocationList locationList = new LocationList();
+ private ApplianceList applianceList = new ApplianceList();
+
+
+
+ @Test
+ void usageTest_EmptyApplianceList_EmptyApplianceListException() {
+ Command computeUsage = new UsageCommand();
+ computeUsage.setData(emptyApplianceList, locationList);
+ CommandResult actualCommandResult = computeUsage.execute();
+ assertEquals(MESSAGE_LIST_NO_APPLIANCES, actualCommandResult.feedbackToUser);
+ }
+
+ @Test
+ void usageTest_computePowerUsageSuccess() throws DuplicateDataException,
+ InvalidApplianceNameException, LocationNotFoundException {
+ locationList.addLocation("BedRoom");
+ Lights light = new Lights("BrightLight", "BedRoom", "100", locationList);
+ applianceList.addAppliance(light);
+ Command computeUsage = new UsageCommand();
+ computeUsage.setData(applianceList, locationList);
+ computeUsage.execute();
+ assertEquals(applianceList.getAppliance(0).getPowerInString(), "0.00");
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/smarthomebot/storage/ReadStorageFileTest.java b/src/test/java/seedu/smarthomebot/storage/ReadStorageFileTest.java
new file mode 100644
index 0000000000..d747935d09
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/storage/ReadStorageFileTest.java
@@ -0,0 +1,25 @@
+package seedu.smarthomebot.storage;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.location.LocationList;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+class ReadStorageFileTest {
+ private LocationList locationList;
+ private ApplianceList applianceList;
+
+ @BeforeEach
+ void setUp() {
+ locationList = new LocationList();
+ applianceList = new ApplianceList();
+ }
+
+ @Test
+ void readStorageFileTest_doesNotThrowException() {
+ ReadStorageFile test = new ReadStorageFile("data/SmartHomeBot.txt", applianceList, locationList);
+ assertDoesNotThrow(() -> test.execute());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/seedu/smarthomebot/storage/WriteStorageFileTest.java b/src/test/java/seedu/smarthomebot/storage/WriteStorageFileTest.java
new file mode 100644
index 0000000000..a2b345dbfc
--- /dev/null
+++ b/src/test/java/seedu/smarthomebot/storage/WriteStorageFileTest.java
@@ -0,0 +1,26 @@
+package seedu.smarthomebot.storage;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import seedu.smarthomebot.data.appliance.ApplianceList;
+import seedu.smarthomebot.data.location.LocationList;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+
+class WriteStorageFileTest {
+
+ private LocationList locationList;
+ private ApplianceList applianceList;
+
+ @BeforeEach
+ void setUp() {
+ locationList = new LocationList();
+ applianceList = new ApplianceList();
+ }
+
+ @Test
+ void writeStorageFileTest_doesNotThrowException() {
+ WriteStorageFile test = new WriteStorageFile("data/SmartHomeBot.txt", applianceList, locationList);
+ assertDoesNotThrow(() -> test.execute());
+ }
+}
\ No newline at end of file
diff --git a/text-ui-test/EXPECTED-UNIX.TXT b/text-ui-test/EXPECTED-UNIX.TXT
new file mode 100644
index 0000000000..3afb09ed22
--- /dev/null
+++ b/text-ui-test/EXPECTED-UNIX.TXT
@@ -0,0 +1,20 @@
+====================================================
+Welcome to your SmartHomeBot V2.1!
+Load File does not exist. No contents will be loaded.
+====================================================
+Enter command: ----------------------------------------------------
+Invalid Command Format
+====================================================
+Enter command: ----------------------------------------------------
+Invalid Command Format
+====================================================
+Enter command: ----------------------------------------------------
+Invalid Command Format
+====================================================
+Enter command: ----------------------------------------------------
+Invalid Command Format
+====================================================
+Enter command: ----------------------------------------------------
+Exiting SmartHomeBot as requested, all Appliances are switched off.
+Exporting data........Completed!
+Good bye!
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 892cb6cae7..3afb09ed22 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,9 +1,20 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
-What is your name?
-Hello James Gosling
+====================================================
+Welcome to your SmartHomeBot V2.1!
+Load File does not exist. No contents will be loaded.
+====================================================
+Enter command: ----------------------------------------------------
+Invalid Command Format
+====================================================
+Enter command: ----------------------------------------------------
+Invalid Command Format
+====================================================
+Enter command: ----------------------------------------------------
+Invalid Command Format
+====================================================
+Enter command: ----------------------------------------------------
+Invalid Command Format
+====================================================
+Enter command: ----------------------------------------------------
+Exiting SmartHomeBot as requested, all Appliances are switched off.
+Exporting data........Completed!
+Good bye!
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index f6ec2e9f95..7363eb1e51 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -1 +1,5 @@
-James Gosling
\ No newline at end of file
+##########################################################
+# test exit command
+##########################################################
+ # exits properly
+ exit
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
index 1dcbd12021..276ec340be 100755
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -10,8 +10,6 @@ cd text-ui-test
java -jar $(find ../build/libs/ -mindepth 1 -print -quit) < input.txt > ACTUAL.TXT
-cp EXPECTED.TXT EXPECTED-UNIX.TXT
-dos2unix EXPECTED-UNIX.TXT ACTUAL.TXT
diff EXPECTED-UNIX.TXT ACTUAL.TXT
if [ $? -eq 0 ]
then