- Installation
- Standalone Usage (no DI)
- Dependency Injection
- Common Tasks
- Cancellation
- Error Handling
- Environment Variables
Install the NuGet package:
dotnet add package SharpToyotaClientOr via NuGet Package Manager:
Install-Package SharpToyotaClient
If you are building a console app or any project that does not use a DI container, you can create the client directly using the fluent builder API:
using SharpToyotaClient.Services;
using SharpToyotaClient.Interfaces;
IMyToyotaClient client = new MyToyotaClient()
.UseCredentials("your@email.com", "your-password")
.UseTimeout(30)
.UseTokenCaching(true)
.UseLogger(msg => Console.WriteLine(msg)); // optional
var loginSuccess = await client.LoginAsync();
if (!loginSuccess)
throw new InvalidOperationException("Login failed");var vehicles = await client.GetVehiclesAsync();
if (vehicles?.Data != null)
{
foreach (var vehicle in vehicles.Data)
{
Console.WriteLine($"VIN: {vehicle.Vin}, Name: {vehicle.Nickname}");
}
}var vin = "JTHJP5C27D5012345";
var location = await client.GetLocationAsync(vin);
Console.WriteLine($"Location: {location?.Data?.Latitude}, {location?.Data?.Longitude}");
var electric = await client.GetElectricAsync(vin);
Console.WriteLine($"Battery Level: {electric?.Data?.BatteryLevel}%");SharpToyotaClient ships with first-class support for the
.NET Options pattern
and Microsoft.Extensions.DependencyInjection.
The library exposes IMyToyotaClient as the public abstraction and provides
AddToyotaClient() extension methods on IServiceCollection.
Add the using directive once in Program.cs:
using SharpToyotaClient.Extensions;Use the lambda overload when you want to configure the client directly in code, e.g. reading from environment variables or a secrets manager:
// Program.cs
builder.Services.AddToyotaClient(options =>
{
options.Username = builder.Configuration["Toyota:Username"]!;
options.Password = builder.Configuration["Toyota:Password"]!;
options.TimeoutSeconds = 30;
options.UseTokenCaching = true;
options.Logger = msg => Console.WriteLine(msg); // optional
});Add a dedicated section to your appsettings.json:
{
"ToyotaClient": {
"Username": "your@email.com",
"Password": "your-password",
"TimeoutSeconds": 30,
"UseTokenCaching": true,
"TokenCacheFilename": "toyota_token_cache.json"
}
}Then pass the section to AddToyotaClient:
// Program.cs
using SharpToyotaClient;
using SharpToyotaClient.Extensions;
builder.Services.AddToyotaClient(
builder.Configuration.GetSection(ToyotaClientOptions.SectionName));
ToyotaClientOptions.SectionNameis the string constant"ToyotaClient".
Once registered, inject IMyToyotaClient into any service, controller, or minimal-API handler:
using SharpToyotaClient.Interfaces;
public class VehicleService(IMyToyotaClient client)
{
public async Task<string?> GetFirstVinAsync(CancellationToken ct = default)
{
await client.LoginAsync(ct);
var vehicles = await client.GetVehiclesAsync(ct);
return vehicles?.Data?.FirstOrDefault()?.Vin;
}
}Register the service and wire it up:
builder.Services.AddScoped<VehicleService>();app.MapGet("/vehicles", async (IMyToyotaClient client, CancellationToken ct) =>
{
await client.LoginAsync(ct);
return await client.GetVehiclesAsync(ct);
});If you need to read the configured options elsewhere:
using Microsoft.Extensions.Options;
using SharpToyotaClient;
public class MyDiagnosticsService(IOptions<ToyotaClientOptions> options)
{
public string GetConfiguredUsername() => options.Value.Username;
}| Environment | Recommended approach |
|---|---|
| Local development | .NET Secret Manager |
| CI / staging | Environment variables |
| Production | Azure Key Vault / secrets provider |
Never commit credentials to source control.
The token cache file (toyota_credentials_cache_contains_secrets.json by default)
should also be added to .gitignore.
var result = await client.StartClimateControlAsync(vin);
if (result?.IsSuccess == true)
Console.WriteLine("Climate control started");var result = await client.SendRemoteCommandAsync(vin, RemoteCommandType.Lock);
if (result?.IsSuccess == true)
Console.WriteLine("Vehicle locked");var trips = await client.GetTripsAsync(
vin,
from: DateOnly.FromDateTime(DateTime.Now.AddDays(-7)),
to: DateOnly.FromDateTime(DateTime.Now),
options: new TripQueryOptions { Route = true, Summary = true, Limit = 50 }
);
foreach (var trip in trips?.Data ?? [])
Console.WriteLine($"Trip: {trip.StartTime} - Distance: {trip.Distance}km");var status = await client.RefreshClimateStatusAsync(vin);
Console.WriteLine($"Climate Status: {status?.Data?.Status}");| Property | Type | Default | Description |
|---|---|---|---|
Username |
string |
— | MyToyota account e-mail |
Password |
string |
— | MyToyota account password |
TimeoutSeconds |
int |
60 |
HTTP request timeout |
UseTokenCaching |
bool |
true |
Cache the bearer token to disk |
TokenCacheFilename |
string |
toyota_credentials_cache_contains_secrets.json |
Token cache file path |
Logger |
Action<string>? |
null |
Optional diagnostic logger |
options.TimeoutSeconds = 60;// Console
options.Logger = message => Console.WriteLine(message);
// Bridge to Microsoft.Extensions.Logging
options.Logger = message => logger.LogDebug("{Message}", message);options.UseTokenCaching = true;
options.TokenCacheFilename = "my_tokens.json";All async methods accept a CancellationToken:
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
try
{
var vehicles = await client.GetVehiclesAsync(cts.Token);
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation was cancelled");
}try
{
var result = await client.GetElectricAsync(vin);
}
catch (AuthenticationException ex)
{
Console.WriteLine($"Authentication failed: {ex.Message}");
}
catch (ApiException ex)
{
Console.WriteLine($"API error: {ex.Message}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Operation was cancelled");
}
catch (TimeoutException)
{
Console.WriteLine("Request timeout");
}You can read credentials from environment variables to avoid hardcoding them:
// Standalone
var client = new MyToyotaClient()
.UseCredentials(
Environment.GetEnvironmentVariable("TOYOTA_USERNAME")
?? throw new InvalidOperationException("TOYOTA_USERNAME not set"),
Environment.GetEnvironmentVariable("TOYOTA_PASSWORD")
?? throw new InvalidOperationException("TOYOTA_PASSWORD not set"));
// DI / lambda
builder.Services.AddToyotaClient(options =>
{
options.Username = Environment.GetEnvironmentVariable("TOYOTA_USERNAME")
?? throw new InvalidOperationException("TOYOTA_USERNAME not set");
options.Password = Environment.GetEnvironmentVariable("TOYOTA_PASSWORD")
?? throw new InvalidOperationException("TOYOTA_PASSWORD not set");
});