chore: added smappee api

This commit is contained in:
Willem Serruys
2026-08-21 07:38:21 +02:00
parent df21ce581b
commit 1d0a5beb8c
12 changed files with 309 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
using enums;
using interfaces;
using Microsoft.Extensions.Options;
using options;
namespace services;
internal class SmappeeChargerService : IChargerService
{
private readonly ChargerOptions options;
private readonly IBearerTokenService tokenService;
private readonly IHttpClientFactory httpClientFactory;
public SmappeeChargerService(
IOptions<ChargerOptions> options,
IBearerTokenService tokenService,
IHttpClientFactory httpClientFactory
)
{
ArgumentNullException.ThrowIfNull(tokenService);
this.options = options?.Value ?? throw new ArgumentNullException(nameof(options));
this.tokenService = tokenService;
this.httpClientFactory =
httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
}
public async Task ExecuteRequest(ChargerRequests request)
{
var token = await tokenService.GetToken(false);
var httpClient = httpClientFactory.CreateClient("smappee");
httpClient.BaseAddress = options.Url;
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
var response = request switch
{
ChargerRequests.Enable => await httpClient.PutAsJsonAsync<SmappeeRequestBody>(
$"/dev/v3/chargingstations/${options.ChargingStation}/connectors/{options.Connector}/mode",
new SmappeeRequestBody("NORMAL", new Limit("AMPERE", 6))
),
ChargerRequests.Disable => await httpClient.PutAsJsonAsync(
"/dev/v3/chargingstations",
new SmappeeRequestBody("PAUSED", null)
),
_ => throw new NotImplementedException(),
};
response.EnsureSuccessStatusCode();
}
record SmappeeRequestBody(string mode, Limit? limit);
record Limit(string unit, int value);
}

View File

@@ -0,0 +1,73 @@
using interfaces;
using Microsoft.Extensions.Options;
using options;
namespace services;
internal class SmappeeTokenService : IBearerTokenService
{
private readonly ChargerOptions options;
private readonly IHttpClientFactory httpClientFactory;
private TokenData? tokenData = null;
public SmappeeTokenService(
IOptions<ChargerOptions> options,
IHttpClientFactory httpClientFactory
)
{
this.options = options?.Value ?? throw new ArgumentNullException(nameof(options));
this.httpClientFactory =
httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
}
public async ValueTask<string> GetToken(bool forceNewToken)
{
if (
tokenData == null
|| tokenData.Expiration < DateTime.UtcNow.AddSeconds(-10)
|| forceNewToken
)
{
tokenData = await RequestNewToken();
}
return tokenData.Token;
}
private async Task<TokenData> RequestNewToken()
{
var httpClient = httpClientFactory.CreateClient("smappeeTokenService");
httpClient.BaseAddress = options.Url;
var result = await httpClient.PostAsJsonAsync<TokenRequestBody>(
"/dev/v3/oauth2/token",
new TokenRequestBody(
"password",
options.ClientId,
options.ClientSecret,
options.UserName,
options.Password
)
);
result.EnsureSuccessStatusCode();
var tokenResponse =
await result.Content.ReadFromJsonAsync<TokenResponse>()
?? throw new InvalidOperationException("Token could not be fetched");
return new TokenData(
tokenResponse.access_token,
DateTime.UtcNow.AddSeconds(tokenResponse.expires_in)
);
}
record TokenRequestBody(
string grant_type,
string client_id,
string client_secret,
string username,
string password
);
record TokenResponse(string access_token, int expires_in);
record TokenData(string Token, DateTime Expiration);
}