Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version updates december 2024 #11

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Gradle
uses: gradle/[email protected]
with:
arguments: build
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4
with:
gradle-version: "8.11.1"
- name: Run Build
run: ./gradlew build

113 changes: 46 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Welcome to PowerDale

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 power a house is drawing/using.
information about how much power a house is drawing/using at a given point in time.

There are three major providers of energy in town that charge different amounts for the power they supply.

Expand All @@ -15,31 +15,13 @@ JOI Energy is a new start-up in the energy industry. Rather than selling energy
from the market by recording their customers' energy usage from their smart meters and recommending the best supplier to
meet their needs.

You have been placed into their development team, whose current goal is to produce an API which their customers and
You have been placed into their development team, whose current goal it is to produce an API which their customers and
smart meters will interact with.

Unfortunately, two members of the team are on annual leave, and another one has called in sick! You are left with
another ThoughtWorker to progress with the current user stories on the story wall. This is your chance to make an impact
on the business, improve the code base and deliver value.

## Story Wall

At JOI energy the development team use a story wall or Kanban board to keep track of features or "stories" as they are
worked on.

The wall you will be working from today has 7 columns:

- Backlog
- Ready for Dev
- In Dev
- Ready for Testing
- In Testing
- Ready for sign off
- Done

Examples can be found
here [https://leankit.com/learn/kanban/kanban-board/](https://leankit.com/learn/kanban/kanban-board/)

## Users

To trial the new JOI software 5 people from the JOI accounts team have agreed to test the service and share their energy
Expand All @@ -57,29 +39,25 @@ These values are used in the code and in the following examples too.

## Requirements

The project requires [Java 17](https://adoptium.net/en-GB/) or
higher.
The project requires [Java 21](https://adoptium.net/en-GB/) or higher. If you have multiple JVMs, you
might consider a tool such as [sdkman](https://sdkman.io/) to help manage them.

The project makes use of Gradle and uses
the [Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html), which means you don't need Gradle
The project makes use of Gradle and uses the [Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html), which means you don't need Gradle
installed.

## Useful Gradle commands

The project makes use of Gradle and uses the Gradle wrapper to help you out carrying some common tasks such as building
the project or running it.

### List all Gradle tasks

List all the tasks that Gradle can do, such as `build` and `test`.
List all the tasks that Gradle can run, such as `build` and `test`.

```console
$ ./gradlew tasks
```

### Build the project

Compiles the project, runs the test and then creates an executable JAR file
Compiles the project, runs the tests and then creates an executable JAR file.

```console
$ ./gradlew build
Expand Down Expand Up @@ -138,30 +116,31 @@ Example of body

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 |
| Parameter | Description |
|----------------|---------------------------------------------------------------|
| `smartMeterId` | One of the smart meters ids listed above |
| `time` | The date/time (as epoch seconds) when the _reading_ was taken |
| `reading` | The power consumption in `kW` at the _time_ of the reading |

Example readings

| Date (`GMT`) | Epoch timestamp | Reading (`kW`) |
|-------------------|----------------:|---------------:|
| `2020-11-29 8:00` | 1606636800 | 0.0503 |
| `2020-11-29 8:01` | 1606636860 | 0.0621 |
| `2020-11-29 8:02` | 1606636920 | 0.0222 |
| `2020-11-29 8:03` | 1606636980 | 0.0423 |
| `2020-11-29 8:04` | 1606637040 | 0.0191 |
| Date (`GMT/UTC`) | Epoch timestamp (seconds) | Power Reading (`kW`) |
|-------------------|--------------------------:|---------------------:|
| `2020-11-29 8:00` | 1606636800 | 0.0503 |
| `2020-11-29 8:01` | 1606636860 | 0.0621 |
| `2020-11-29 8:02` | 1606636920 | 0.0222 |
| `2020-11-29 8:03` | 1606636980 | 0.0423 |
| `2020-11-29 8:04` | 1606637040 | 0.0191 |

In the above example, the smart meter sampled readings, in `kW`, every minute. Note that the reading is in `kW` and
not `kWH`, which means that each reading represents the consumption at the reading time. If no power is being consumed
not `kWH`, which means that each reading represents the _power_ consumption at the reading time. If no power is being consumed
at the time of reading, then the reading value will be `0`. Given that `0` may introduce new challenges, we can assume
that there is always some consumption, and we will never have a `0` reading value. These readings are then sent by the
smart meter to the application using REST. There is a service in the application that calculates the `kWH` from these
readings.
smart meter to the application using the HTTP endpoint.

The following POST request, is an example request using CURL, sends the readings shown in the table above.
There is a service in the application that calculates the `kWH` from these readings.

The following POST request, is an example request using `curl`, sends the readings shown in the table above.

```console
$ curl \
Expand All @@ -171,7 +150,7 @@ $ curl \
-d '{"smartMeterId":"smart-meter-0","readings":[{"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 should return.
The above command should return:

```json
{
Expand All @@ -184,19 +163,19 @@ The above command should return.

### Get Stored Readings

Endpoint
Endpoint:

```text
GET /readings/read/<smartMeterId>
```

Parameters
Parameters:

| Parameter | Description |
|----------------|------------------------------------------|
| `smartMeterId` | One of the smart meters' id listed above |
| Parameter | Description |
|----------------|-------------------------------------------|
| `smartMeterId` | One of the smart meters ids listed above. |

Retrieving readings using CURL
Retrieving readings using `curl`:

```console
$ curl "http://localhost:8080/readings/read/smart-meter-0"
Expand Down Expand Up @@ -237,25 +216,25 @@ Example output

### View Current Price Plan and Compare Usage Cost Against all Price Plans

Endpoint
Endpoint:

```text
GET /price-plans/compare-all/<smartMeterId>
```

Parameters
Parameters:

| Parameter | Description |
|----------------|------------------------------------------|
| `smartMeterId` | One of the smart meters' id listed above |
| Parameter | Description |
|----------------|-------------------------------------------|
| `smartMeterId` | One of the smart meters ids listed above. |

Retrieving readings using CURL
Retrieving readings using `curl`:

```console
$ curl "http://localhost:8080/price-plans/compare-all/smart-meter-0"
```

Example output
Example output:

```json
{
Expand All @@ -275,26 +254,26 @@ Example output

### View Recommended Price Plans for Usage

Endpoint
Endpoint:

```text
GET /price-plans/recommend/<smartMeterId>[?limit=<limit>]
```

Parameters
Parameters:

| Parameter | Description |
|----------------|------------------------------------------------------|
| `smartMeterId` | One of the smart meters' id listed above |
| `limit` | (Optional) limit the number of plans to be displayed |
| Parameter | Description |
|----------------|-------------------------------------------------------|
| `smartMeterId` | One of the smart meters ids listed above. |
| `limit` | (Optional) limit the number of plans to be displayed. |

Retrieving readings using CURL
Retrieving readings using `curl`:

```console
$ curl "http://localhost:8080/price-plans/recommend/smart-meter-0?limit=2"
```

Example output
Example output:

```json
{
Expand Down
38 changes: 19 additions & 19 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ plugins {
id("com.github.ben-manes.versions")
}

val kotlin_version: String by project
val ktor_version: String by project
val logback_version: String by project
val jackson_version: String by project
val strikt_version: String by project
val detekt_version: String by project
val kotlinVersion: String by project
val ktorVersion: String by project
val logbackVersion: String by project
val jacksonVersion: String by project
val striktVersion: String by project
val detektVersion: String by project

application {
mainClass.set("io.ktor.server.netty.EngineMain")
Expand All @@ -23,25 +23,25 @@ repositories {
}

dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
implementation("io.ktor:ktor-server-netty:$ktor_version")
implementation("ch.qos.logback:logback-classic:$logback_version")
implementation("io.ktor:ktor-server-core:$ktor_version")
implementation("io.ktor:ktor-server-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-serialization-jackson:$ktor_version")
implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
implementation("io.ktor:ktor-server-netty:$ktorVersion")
implementation("ch.qos.logback:logback-classic:$logbackVersion")
implementation("io.ktor:ktor-server-core:$ktorVersion")
implementation("io.ktor:ktor-server-content-negotiation:$ktorVersion")
implementation("io.ktor:ktor-serialization-jackson:$ktorVersion")

implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jackson_version")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jacksonVersion")

testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
testImplementation("io.ktor:ktor-server-tests:$ktor_version")
testImplementation("io.strikt:strikt-core:$strikt_version")
testImplementation("io.ktor:ktor-client-content-negotiation:$ktor_version")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion")
testImplementation("io.ktor:ktor-server-test-host:$ktorVersion")
testImplementation("io.strikt:strikt-core:$striktVersion")
testImplementation("io.ktor:ktor-client-content-negotiation:$ktorVersion")

detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detekt_version")
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:$detektVersion")
}

kotlin {
jvmToolchain(17)
jvmToolchain(21)
}

tasks {
Expand Down
14 changes: 7 additions & 7 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
detekt_version=1.23.1
jackson_version=2.15.2
kotlin_version=1.9.10
ktor_version=2.3.4
logback_version=1.4.11
strikt_version=0.34.1
versions_version=0.48.0
detektVersion=1.23.7
jacksonVersion=2.18.2
kotlinVersion=2.1.0
ktorVersion=3.0.2
logbackVersion=1.5.12
striktVersion=0.35.1
versionsVersion=0.51.0
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
16 changes: 8 additions & 8 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
pluginManagement {
val kotlin_version: String by settings
val ktor_version: String by settings
val detekt_version: String by settings
val versions_version: String by settings
val kotlinVersion: String by settings
val ktorVersion: String by settings
val detektVersion: String by settings
val versionsVersion: String by settings
plugins {
kotlin("jvm") version kotlin_version
id("io.ktor.plugin") version ktor_version
id("io.gitlab.arturbosch.detekt") version detekt_version
id("com.github.ben-manes.versions") version versions_version
kotlin("jvm") version kotlinVersion
id("io.ktor.plugin") version ktorVersion
id("io.gitlab.arturbosch.detekt") version detektVersion
id("com.github.ben-manes.versions") version versionsVersion
}
}

Expand Down
7 changes: 3 additions & 4 deletions src/main/kotlin/de/tw/energy/Application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import de.tw.energy.services.PricePlanService
import io.ktor.http.HttpStatusCode
import io.ktor.serialization.jackson.jackson
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.application.install
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.request.receive
Expand Down Expand Up @@ -43,7 +42,7 @@ fun Application.module() {
val controller = MeterReadingController(meterReadingsService)

get("/read/{smartMeterId}") {
val smartMeterId = call.parameters["smartMeterId"] ?: ""
val smartMeterId = call.parameters["smartMeterId"].orEmpty()
call.respondNullable(controller.readings(smartMeterId))
}

Expand All @@ -65,12 +64,12 @@ fun Application.module() {
)

get("/compare-all/{smartMeterId}") {
val smartMeterId = call.parameters["smartMeterId"] ?: ""
val smartMeterId = call.parameters["smartMeterId"].orEmpty()
call.respondNullable(controller.calculatedCostForEachPricePlan(smartMeterId))
}

get("/recommend/{smartMeterId}") {
val smartMeterId = call.parameters["smartMeterId"] ?: ""
val smartMeterId = call.parameters["smartMeterId"].orEmpty()
val limit = call.request.queryParameters["limit"]
call.respondNullable(controller.recommendCheapestPricePlans(smartMeterId, limit?.toInt()))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ class MeterReadingService(private val meterReadings: MutableMap<String, List<Ele
meterReadings[smartMeterId] = existingOrEmpty(smartMeterId) + readings
}

private fun existingOrEmpty(smartMeterId: String) = this[smartMeterId] ?: listOf()
private fun existingOrEmpty(smartMeterId: String) = this[smartMeterId].orEmpty()
}
Loading
Loading