PowerDale is a small town with around 100 residents. Most houses have a smart meter installed that can save and send information about how much energy a house has consumed.
There are three major power suppliers in town that charge different amounts for the power they supply.
- Dr Evil's Dark Energy
- The Green Eco
- Power for Everyone
Each customer with a smart meter needs to sign up for one of the price plans offered by these suppliers.
JOI Energy is a new start-up in the energy industry. Rather than selling energy they want to differentiate themselves from the market by recording their customers' energy usage from their smart meters and recommending the best supplier to meet their needs.
This codebase is for an API which their customers and smart meters will interact with.
Unfortunately, as the codebase has evolved, it has gathered a number of code smells and some questionable design decisions. Our goal with this exercise would be to deliver value by implementing a new feature, while at the same time improving the codebase by refactoring away any code smells we identify.
To trial the new JOI software 5 people from the JOI accounts team have agreed to test the service and share their energy data.
User | Smart Meter ID | Power Supplier |
---|---|---|
Sarah | smart-meter-0 |
Dr Evil's Dark Energy |
Paolo | smart-meter-1 |
The Green Eco |
Chitra | smart-meter-2 |
Dr Evil's Dark Energy |
Andrei | smart-meter-3 |
Power for Everyone |
Jingyi | smart-meter-4 |
The Green Eco |
These values are used in the code and in the following examples too.
The project requires Java 21 or higher.
Compile the project, run the tests and creates an executable JAR file
$ ./gradlew build
There are two types of tests, the unit tests and the functional tests. These can be executed as follows.
-
Run unit tests only
$ ./gradlew test
-
Run functional tests only
$ ./gradlew functionalTest
-
Run unit, functional and code style tests
$ ./gradlew check
Run the application which will be listening on port 8080
.
$ ./gradlew bootRun
Below is a list of API endpoints with their respective input and output. Please note that the application needs to be running for the following endpoints to work. For more information about how to run the application, please refer to run the application section above.
POST /readings
Example of body
{
"smartMeterId": <smartMeterId>,
"electricityReadings": [
{
"time": <time>,
"reading": <reading>
}
]
}
Parameters
Parameter | Description |
---|---|
smartMeterId |
One of the smart meters' id listed above |
time |
The date/time (as epoch) when the reading was taken |
reading |
The consumption in kW at the time of the reading |
Example readings
Date (GMT ) |
Epoch timestamp | Reading (kWh ) |
---|---|---|
2020-11-29 8:00 |
1606636800 | 0.0503 |
2020-11-29 9:00 |
1606636860 | 0.0621 |
2020-11-30 7:30 |
1606636920 | 0.0922 |
2020-11-31 8:30 |
1606636980 | 0.1223 |
2020-11-31 8:00 |
1606637040 | 0.1391 |
In the above example, the smart meter periodically sampled readings, in kWh
, over multiple days. Note that since the smart meter is reporting the total consumption at that point in time, the reading value will either be higher or the same as the previous reading. These readings are then sent by the smart meter to the application using the provided REST API.
The following POST request, is an example request using CURL, sends the readings shown in the table above.
$ curl \
-X POST \
-H "Content-Type: application/json" \
"http://localhost:8080/readings" \
-d '{"smartMeterId":"smart-meter-0","electricityReadings":[{"time":1606636800,"reading":0.0503},{"time":1606636860,"reading":0.0621},{"time":1606636920,"reading":0.0222},{"time":1606636980,"reading":0.0423},{"time":1606637040,"reading":0.0191}]}'
The above command does not return anything.
GET /readings/<smartMeterId>
Parameters
Parameter | Description |
---|---|
smartMeterId |
One of the smart meters' id listed above |
Retrieving readings using CURL
$ curl "http://localhost:8080/readings/read/smart-meter-0"
Example output
[
{
"time": "2020-11-29T08:00:00Z",
"reading": 0.0503
},
{
"time": "2020-11-29T08:01:00Z",
"reading": 0.0621
},
{
"time": "2020-11-29T08:02:00Z",
"reading": 0.0222
},
{
"time": "2020-11-29T08:03:00Z",
"reading": 0.0423
},
{
"time": "2020-11-29T08:04:00Z",
"reading": 0.0191
}
]
GET /price-plans/compare-all/<smartMeterId>
Parameters
Parameter | Description |
---|---|
smartMeterId |
One of the smart meters' id listed above |
Sample call with CURL
$ curl "http://localhost:8080/price-plans/compare-all/smart-meter-0"
Example output
{
"pricePlanComparisons": {
"price-plan-2": 0.0002,
"price-plan-1": 0.0004,
"price-plan-0": 0.002
},
"pricePlanId": "price-plan-0"
}
GET /price-plans/recommend/<smartMeterId>[?limit=<limit>]
Parameters
Parameter | Description |
---|---|
smartMeterId |
One of the smart meters' id listed above |
limit |
(Optional) limit the number of plans to be displayed |
Sample call with CURL
$ curl "http://localhost:8080/price-plans/recommend/smart-meter-0?limit=2"
Example output
[
{
"price-plan-2": 0.0002
},
{
"price-plan-1": 0.0004
}
]