Electric Vehicle
A unidirectional EV can be in one of four possible states:
- Disconnected
- Connected but not charging
- Connected and charging below maximum power
- Connected and charging at maximum power
Once the EV is connected, a charging schedule is generated and reported as the baseline.
As soon as flexibility has been activated, you should calculate a new charging schedule and send in new bids.
Stop charging​
Let's first look at cases one and four. The car is connected as soon as we can see the green baseline.

When the car is disconnected no bids are made. Once connected, a charging schedule is created, and the car starts charging at maximum power. This allows for flexibility. We can offer to stop charging the car, setting a new set point at 0kW.
Since customer comfort comes first, there's a few cases where you cannot offer flexibility:
- If the user explicitly requests fast charging at maximum power
- If the remaining schedule time is needed to reach a minimum State of Charge (SoC)
Bid Curve​
The bid curve in this case is quite simple, and consists of a single point at 0kW.
In the image below, the red line shows the baseline, and the single green dot shows the point that indicates the EV can stop charging.
The API call to make this bid is as follows:
- Python
- JavaScript
- Java
- Go
- C#
- cURL
import requests
import json
url = "https://api.powernaut.io/v1/connect/resources/<uuid>/bid"
payload = json.dumps({
"timing": {
"start": "2024-07-01T14:00:00Z",
"end": "2024-07-01T14:15:00Z"
},
"curve": [
{
"value": "0"
}
]
})
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer <token>'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Accept", "application/json");
myHeaders.append("Authorization", "Bearer <token>");
const raw = JSON.stringify({
"timing": {
"start": "2024-07-01T14:00:00Z",
"end": "2024-07-01T14:15:00Z"
},
"curve": [
{
"value": "0"
}
]
});
const requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow"
};
fetch("https://api.powernaut.io/v1/connect/resources/<uuid>/bid", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\"timing\":{\"start\":\"2024-07-01T14:00:00Z\",\"end\":\"2024-07-01T14:15:00Z\"},\"curve\":[{\"value\":\"0\"}]}");
Request request = new Request.Builder()
.url("https://api.powernaut.io/v1/connect/resources/<uuid>/bid")
.method("POST", body)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer <token>")
.build();
Response response = client.newCall(request).execute();
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://api.powernaut.io/v1/connect/resources/<uuid>/bid"
method := "POST"
payload := strings.NewReader(`{"timing":{"start":"2024-07-01T14:00:00Z","end":"2024-07-01T14:15:00Z"},"curve":[{"value":"0"}]}`)
client := &http.Client {
}
req, err := http.NewRequest(method, url, payload)
if err != nil {
fmt.Println(err)
return
}
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Accept", "application/json")
req.Header.Add("Authorization", "Bearer <token>")
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.powernaut.io/v1/connect/resources/<uuid>/bid");
request.Headers.Add("Accept", "application/json");
request.Headers.Add("Authorization", "Bearer <token>");
var content = new StringContent("{\"timing\":{\"start\":\"2024-07-01T14:00:00Z\",\"end\":\"2024-07-01T14:15:00Z\"},\"curve\":[{\"value\":\"0\"}]}", null, "application/json");
request.Content = content;
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());
curl --location 'https://api.powernaut.io/v1/connect/resources/<uuid>/bid' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <token>' \
--data '{"timing":{"start":"2024-07-01T14:00:00Z","end":"2024-07-01T14:15:00Z"},"curve":[{"value":"0"}]}'
Start or stop charging​
Now, lets explore cases two and three.

When the car is connected, but not charging, we can offer flexiblity with max power to start charging.
If the car is already at 100% SoC, then we are not able to offer flexibility to start charging.
As soon as the car is charging below max power we can offer flexiblity in both directions.
We can offer to stop charging with current power
and go to zero or we start charging at max power
and offer flexibility of max power - current power
.
Bid Curve​
The bid curve in this case is a bit more complex:
- The car can stop charging, and offers the first bid curve point at 0kW, at no cost.
- The car can start charging at max power, and offers the second bid curve point at max power, but at a cost of €0.10/kWh because the owner will have to pay extra grid fees.
In the image below, the red line shows the baseline, and the green dots show the points that indicate the EV can stop charging and start charging at max power.
The API call to make this bid is as follows:
- Python
- JavaScript
- Java
- Go
- C#
- cURL
import requests
import json
url = "https://api.powernaut.io/v1/connect/resources/<uuid>/bid"
payload = json.dumps({
"timing": {
"start": "2024-07-01T14:00:00Z",
"end": "2024-07-01T14:15:00Z"
},
"curve": [
{
"value": "0"
},
{
"value": "5",
"price": "0.10"
}
]
})
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer <token>'
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)
const myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");
myHeaders.append("Accept", "application/json");
myHeaders.append("Authorization", "Bearer <token>");
const raw = JSON.stringify({
"timing": {
"start": "2024-07-01T14:00:00Z",
"end": "2024-07-01T14:15:00Z"
},
"curve": [
{
"value": "0"
},
{
"value": "5",
"price": "0.10"
}
]
});
const requestOptions = {
method: "POST",
headers: myHeaders,
body: raw,
redirect: "follow"
};
fetch("https://api.powernaut.io/v1/connect/resources/<uuid>/bid", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\"timing\":{\"start\":\"2024-07-01T14:00:00Z\",\"end\":\"2024-07-01T14:15:00Z\"},\"curve\":[{\"value\":\"0\"},{\"value\":\"5\",\"price\":\"0.10\"}]}");
Request request = new Request.Builder()
.url("https://api.powernaut.io/v1/connect/resources/<uuid>/bid")
.method("POST", body)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.addHeader("Authorization", "Bearer <token>")
.build();
Response response = client.newCall(request).execute();
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://api.powernaut.io/v1/connect/resources/<uuid>/bid"
method := "POST"
payload := strings.NewReader(`{"timing":{"start":"2024-07-01T14:00:00Z","end":"2024-07-01T14:15:00Z"},"curve":[{"value":"0"},{"value":"5","price":"0.10"}]}`)
client := &http.Client {
}
req, err := http.NewRequest(method, url, payload)
if err != nil {
fmt.Println(err)
return
}
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Accept", "application/json")
req.Header.Add("Authorization", "Bearer <token>")
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.powernaut.io/v1/connect/resources/<uuid>/bid");
request.Headers.Add("Accept", "application/json");
request.Headers.Add("Authorization", "Bearer <token>");
var content = new StringContent("{\"timing\":{\"start\":\"2024-07-01T14:00:00Z\",\"end\":\"2024-07-01T14:15:00Z\"},\"curve\":[{\"value\":\"0\"},{\"value\":\"5\",\"price\":\"0.10\"}]}", null, "application/json");
request.Content = content;
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
Console.WriteLine(await response.Content.ReadAsStringAsync());
curl --location 'https://api.powernaut.io/v1/connect/resources/<uuid>/bid' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer <token>' \
--data '{"timing":{"start":"2024-07-01T14:00:00Z","end":"2024-07-01T14:15:00Z"},"curve":[{"value":"0"},{"value":"5","price":"0.10"}]}'