mirror of
https://github.com/q39JzrRa/GM-Vehicle-API.git
synced 2025-12-23 23:38:45 -05:00
Completed renaming of JSON model properties and added some helpful code docs. Fixed a bug in the UI
This commit is contained in:
@@ -191,7 +191,7 @@ namespace GM.Api
|
||||
/// </summary>
|
||||
/// <param name="vin"></param>
|
||||
/// <returns></returns>
|
||||
async Task<Commandresponse> VehicleConnect()
|
||||
async Task<CommandResponse> VehicleConnect()
|
||||
{
|
||||
if (ActiveVehicle == null) throw new InvalidOperationException("ActiveVehicle must be populated");
|
||||
using (var response = await PostAsync(ActiveVehicle.GetCommand("connect").Url, new StringContent("{}", Encoding.UTF8, "application/json")))
|
||||
@@ -199,9 +199,9 @@ namespace GM.Api
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var respString = await response.Content.ReadAsStringAsync();
|
||||
var respObj = JsonConvert.DeserializeObject<CommandResponseRoot>(respString);
|
||||
if (respObj == null || respObj.commandResponse == null) return null;
|
||||
return respObj.commandResponse;
|
||||
var respObj = JsonConvert.DeserializeObject<CommandRequestResponse>(respString);
|
||||
if (respObj == null || respObj.CommandResponse == null) return null;
|
||||
return respObj.CommandResponse;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -384,7 +384,7 @@ namespace GM.Api
|
||||
/// <param name="pin">OnStar PIN</param>
|
||||
/// <param name="command">command name</param>
|
||||
/// <returns></returns>
|
||||
async Task<Commandresponse> InitiateCommand(string command, JObject requestParameters)
|
||||
async Task<CommandResponse> InitiateCommand(string command, JObject requestParameters)
|
||||
{
|
||||
if (ActiveVehicle == null) throw new InvalidOperationException("ActiveVehicle must be populated");
|
||||
|
||||
@@ -427,9 +427,9 @@ namespace GM.Api
|
||||
return null;
|
||||
}
|
||||
|
||||
var commandResult = await response.Content.ReadAsAsync<CommandResponseRoot>();
|
||||
var commandResult = await response.Content.ReadAsAsync<CommandRequestResponse>();
|
||||
|
||||
return commandResult.commandResponse;
|
||||
return commandResult.CommandResponse;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,7 +439,7 @@ namespace GM.Api
|
||||
/// </summary>
|
||||
/// <param name="statusUrl">statusUrl returned when the command was initiated</param>
|
||||
/// <returns>Response from final poll</returns>
|
||||
async Task<Commandresponse> WaitForCommandCompletion(string statusUrl)
|
||||
async Task<CommandResponse> WaitForCommandCompletion(string statusUrl)
|
||||
{
|
||||
int nullResponseCount = 0;
|
||||
|
||||
@@ -452,16 +452,16 @@ namespace GM.Api
|
||||
nullResponseCount++;
|
||||
if (nullResponseCount > 5) return null;
|
||||
}
|
||||
if ("inProgress".Equals(result.status, StringComparison.OrdinalIgnoreCase)) continue;
|
||||
if ("inProgress".Equals(result.Status, StringComparison.OrdinalIgnoreCase)) continue;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected async Task<Commandresponse> InitiateCommandAndWait(string command, JObject requestParameters)
|
||||
protected async Task<CommandResponse> InitiateCommandAndWait(string command, JObject requestParameters)
|
||||
{
|
||||
var result = await InitiateCommand(command, requestParameters);
|
||||
var endStatus = await WaitForCommandCompletion(result.url);
|
||||
var endStatus = await WaitForCommandCompletion(result.Url);
|
||||
return endStatus;
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ namespace GM.Api
|
||||
{
|
||||
var result = await InitiateCommandAndWait(command, requestParameters);
|
||||
if (result == null) return false;
|
||||
if ("success".Equals(result.status, StringComparison.OrdinalIgnoreCase))
|
||||
if ("success".Equals(result.Status, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -480,14 +480,14 @@ namespace GM.Api
|
||||
}
|
||||
|
||||
|
||||
async Task<Commandresponse> PollCommandStatus(string statusUrl)
|
||||
async Task<CommandResponse> PollCommandStatus(string statusUrl)
|
||||
{
|
||||
var response = await GetAsync($"{statusUrl}?units=METRIC");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var result = await response.Content.ReadAsAsync<CommandResponseRoot>();
|
||||
return result.commandResponse;
|
||||
var result = await response.Content.ReadAsAsync<CommandRequestResponse>();
|
||||
return result.CommandResponse;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace GM.Api
|
||||
}
|
||||
|
||||
|
||||
public async Task<Diagnosticresponse[]> GetDiagnostics()
|
||||
public async Task<DiagnosticResponse[]> GetDiagnostics()
|
||||
{
|
||||
var cmdInfo = ActiveVehicle.GetCommand("diagnostics");
|
||||
|
||||
@@ -28,9 +28,9 @@ namespace GM.Api
|
||||
|
||||
var result = await InitiateCommandAndWait("diagnostics", reqObj);
|
||||
if (result == null) return null;
|
||||
if ("success".Equals(result.status, StringComparison.OrdinalIgnoreCase))
|
||||
if ("success".Equals(result.Status, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return result.body.diagnosticResponse;
|
||||
return result.Body.DiagnosticResponse;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -40,7 +40,7 @@ namespace GM.Api
|
||||
|
||||
|
||||
|
||||
public async Task<Commandresponse> IssueCommand(string commandName, JObject parameters = null)
|
||||
public async Task<CommandResponse> IssueCommand(string commandName, JObject parameters = null)
|
||||
{
|
||||
return await InitiateCommandAndWait(commandName, parameters);
|
||||
}
|
||||
|
||||
@@ -1,23 +1,63 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace GM.Api.Models
|
||||
{
|
||||
public class CommandResponseRoot
|
||||
/// <summary>
|
||||
/// Root object returned by a command request, or a call to a status url
|
||||
/// </summary>
|
||||
public class CommandRequestResponse
|
||||
{
|
||||
public Commandresponse commandResponse { get; set; }
|
||||
/// <summary>
|
||||
/// Inner response
|
||||
/// </summary>
|
||||
[JsonProperty("commandResponse")]
|
||||
public CommandResponse CommandResponse { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class Commandresponse
|
||||
/// <summary>
|
||||
/// Command Response Object
|
||||
/// </summary>
|
||||
public class CommandResponse
|
||||
{
|
||||
public DateTime requestTime { get; set; }
|
||||
public DateTime completionTime { get; set; }
|
||||
public string url { get; set; }
|
||||
public string status { get; set; } //inProgress, success
|
||||
public string type { get; set; }
|
||||
public ResponseBody body { get; set; }
|
||||
/// <summary>
|
||||
/// Timestamp the request was received by the server
|
||||
/// </summary>
|
||||
[JsonProperty("requestTime")]
|
||||
public DateTime RequestTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp the server completed the request
|
||||
/// </summary>
|
||||
[JsonProperty("completionTime")]
|
||||
public DateTime CompletionTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Status URL to be polled for updates (commands are async)
|
||||
/// </summary>
|
||||
[JsonProperty("url")]
|
||||
public string Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Current status of the command request
|
||||
/// (e.g. "inProgress", "success")
|
||||
/// </summary>
|
||||
[JsonProperty("status")]
|
||||
public string Status { get; set; } //inProgress, success
|
||||
|
||||
/// <summary>
|
||||
/// Probably refers to the type of the response body
|
||||
/// </summary>
|
||||
[JsonProperty("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Response boldy for commands that include a response (e.g. diagnostics, location)
|
||||
/// </summary>
|
||||
[JsonProperty("body")]
|
||||
public ResponseBody Body { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -5,55 +5,168 @@ using System.Text;
|
||||
|
||||
namespace GM.Api.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Model of the encrypted Andorid configuration file
|
||||
/// </summary>
|
||||
|
||||
public class GmConfiguration
|
||||
{
|
||||
public Dictionary<string, BrandClientInfo> brand_client_info { get; set; }
|
||||
public ApiConfig[] configs { get; set; }
|
||||
public Telenav_Config telenav_config { get; set; }
|
||||
public string equip_key { get; set; }
|
||||
public string key_store_password { get; set; }
|
||||
public string key_password { get; set; }
|
||||
public Dictionary<string, RegionCert> certs { get; set; }
|
||||
/// <summary>
|
||||
/// Client Credentials by GM Brand
|
||||
/// </summary>
|
||||
[JsonProperty("brand_client_info")]
|
||||
public Dictionary<string, BrandClientInfo> BrandClientInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Endpoint Configuration collection
|
||||
/// </summary>
|
||||
[JsonProperty("configs")]
|
||||
public ApiConfig[] Configs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Presumably configuration used for navigation
|
||||
/// </summary>
|
||||
[JsonProperty("telenav_config")]
|
||||
public TelenavConfig TelenavConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
[JsonProperty("equip_key")]
|
||||
public string EquipKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Probably the key used to encrypt the saved OnStar PINs
|
||||
/// </summary>
|
||||
[JsonProperty("key_store_password")]
|
||||
public string KeyStorePassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unknown
|
||||
/// </summary>
|
||||
[JsonProperty("key_password")]
|
||||
public string KeyPassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Certificate pinning information used to prevent SSL spoofing
|
||||
/// </summary>
|
||||
[JsonProperty("certs")]
|
||||
public Dictionary<string, RegionCert> Certs { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Client Credentials for a given GM brand
|
||||
/// </summary>
|
||||
public class BrandClientInfo
|
||||
{
|
||||
public string client_id { get; set; }
|
||||
public string client_secret { get; set; }
|
||||
public string debug_client_id { get; set; }
|
||||
public string debug_client_secret { get; set; }
|
||||
/// <summary>
|
||||
/// OAuth Client ID
|
||||
/// </summary>
|
||||
[JsonProperty("client_id")]
|
||||
public string ClientId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OAuth Client Secret
|
||||
/// </summary>
|
||||
[JsonProperty("client_secret")]
|
||||
public string ClientSecret { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Debug environment Oauth Client ID
|
||||
/// </summary>
|
||||
[JsonProperty("debug_client_id")]
|
||||
public string DebugClientId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Debug environment Oauth Client Secret
|
||||
/// </summary>
|
||||
[JsonProperty("debug_client_secret")]
|
||||
public string DebugClientSecret { get; set; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// API configuration for a given GM brand
|
||||
/// </summary>
|
||||
public class ApiConfig
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string url { get; set; }
|
||||
public string required_client_scope { get; set; }
|
||||
public string optional_client_scope { get; set; }
|
||||
/// <summary>
|
||||
/// do not use this
|
||||
/// GM Brand name
|
||||
/// </summary>
|
||||
public string client_id { get; set; }
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// do not use this
|
||||
/// Base API endpoint URL (eg "https://api.gm.com/api")
|
||||
/// </summary>
|
||||
public string client_secret { get; set; }
|
||||
[JsonProperty("url")]
|
||||
public string Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Space separated scopes required for login
|
||||
/// </summary>
|
||||
[JsonProperty("required_client_scope")]
|
||||
public string RequiredClientScope { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Space separated scopes optional for login
|
||||
/// </summary>
|
||||
[JsonProperty("optional_client_scope")]
|
||||
public string OptionalClientScope { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Use the Brand config Client ID instead
|
||||
/// </summary>
|
||||
[JsonProperty("client_id")]
|
||||
public string ClientId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Use the Brand config Client Secret instead
|
||||
/// </summary>
|
||||
[JsonProperty("client_secret")]
|
||||
public string ClientSecret { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class Telenav_Config
|
||||
/// <summary>
|
||||
/// Client credentials for Telenav system
|
||||
/// </summary>
|
||||
public class TelenavConfig
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string client_id { get; set; }
|
||||
public string client_secret { get; set; }
|
||||
/// <summary>
|
||||
/// Name
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OAuth Client ID
|
||||
/// </summary>
|
||||
[JsonProperty("client_id")]
|
||||
public string ClientId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OAuth Client Secret
|
||||
/// </summary>
|
||||
[JsonProperty("client_secret")]
|
||||
public string ClientSecret { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Container for certificate pinning info
|
||||
/// </summary>
|
||||
public class RegionCert
|
||||
{
|
||||
public string pattern { get; set; }
|
||||
public string[] certificate_pins { get; set; }
|
||||
/// <summary>
|
||||
/// Pattern used by the expected certificate. Should match the CN I'm guessing
|
||||
/// </summary>
|
||||
[JsonProperty("pattern")]
|
||||
public string Pattern { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of certificate pins. There are usually 3 and only one matches the actual SSL cert of the server
|
||||
/// The other two do not match the intermediate / root certs - not sure what they are
|
||||
/// </summary>
|
||||
[JsonProperty("certificate_pins")]
|
||||
public string[] CertificatePins { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,27 +2,45 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GM.Api.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Response Body
|
||||
/// Note: this only contains a diagnostic response. there are likely others.
|
||||
/// </summary>
|
||||
public class ResponseBody
|
||||
{
|
||||
public Diagnosticresponse[] diagnosticResponse { get; set; }
|
||||
[JsonProperty("diagnosticResponse")]
|
||||
public DiagnosticResponse[] DiagnosticResponse { get; set; }
|
||||
}
|
||||
|
||||
public class Diagnosticresponse
|
||||
public class DiagnosticResponse
|
||||
{
|
||||
public string name { get; set; }
|
||||
public Diagnosticelement[] diagnosticElement { get; set; }
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("diagnosticElement")]
|
||||
public DiagnosticElement[] DiagnosticElement { get; set; }
|
||||
}
|
||||
|
||||
public class Diagnosticelement
|
||||
public class DiagnosticElement
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string status { get; set; }
|
||||
public string message { get; set; }
|
||||
public string value { get; set; }
|
||||
public string unit { get; set; }
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("status")]
|
||||
public string Status { get; set; }
|
||||
|
||||
[JsonProperty("message")]
|
||||
public string Message { get; set; }
|
||||
|
||||
[JsonProperty("value")]
|
||||
public string Value { get; set; }
|
||||
|
||||
[JsonProperty("unit")]
|
||||
public string Unit { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,33 +16,64 @@ namespace GM.Api.Models
|
||||
|
||||
public class Vehicles
|
||||
{
|
||||
/// <summary>
|
||||
/// Size of the Vehicle array, or full size. One would need to have more than 10 cars to find out...
|
||||
/// </summary>
|
||||
[JsonProperty("size")]
|
||||
public string Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of vehicles associated with the account
|
||||
/// Note that there is paging and by default the page size is 10
|
||||
/// </summary>
|
||||
[JsonProperty("vehicle")]
|
||||
public Vehicle[] Vehicle { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vehicle description
|
||||
/// </summary>
|
||||
public class Vehicle
|
||||
{
|
||||
/// <summary>
|
||||
/// Vehicle VIN
|
||||
/// </summary>
|
||||
[JsonProperty("vin")]
|
||||
public string Vin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Vehicle Make
|
||||
/// </summary>
|
||||
[JsonProperty("make")]
|
||||
public string Make { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Vehicle Model
|
||||
/// </summary>
|
||||
[JsonProperty("model")]
|
||||
public string Model { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Vehicle Year
|
||||
/// </summary>
|
||||
[JsonProperty("year")]
|
||||
public string Year { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Vehicle Manufacturer - not sure why this is required...
|
||||
/// </summary>
|
||||
[JsonProperty("manufacturer")]
|
||||
public string Manufacturer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// (e.g. car, maybe truck)
|
||||
/// </summary>
|
||||
[JsonProperty("bodyStyle")]
|
||||
public string BodyStyle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Vehicle cellular / OnStar phone number
|
||||
/// </summary>
|
||||
[JsonProperty("phone")]
|
||||
public string Phone { get; set; }
|
||||
|
||||
@@ -52,6 +83,9 @@ namespace GM.Api.Models
|
||||
[JsonProperty("onstarStatus")]
|
||||
public string OnStarStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Base URL for API calls regarding this vehicle
|
||||
/// </summary>
|
||||
[JsonProperty("url")]
|
||||
public string Url { get; set; }
|
||||
|
||||
@@ -64,12 +98,21 @@ namespace GM.Api.Models
|
||||
[JsonProperty("enrolledInContinuousCoverage")]
|
||||
public bool? EnrolledInContinuousCoverage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Details on supported commands
|
||||
/// </summary>
|
||||
[JsonProperty("commands")]
|
||||
public Commands Commands { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Details on available modules
|
||||
/// </summary>
|
||||
[JsonProperty("modules")]
|
||||
public Modules Modules { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Details on available entitlements
|
||||
/// </summary>
|
||||
[JsonProperty("entitlements")]
|
||||
public Entitlements Entitlements { get; set; }
|
||||
|
||||
@@ -102,24 +145,46 @@ namespace GM.Api.Models
|
||||
|
||||
public class Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// List of commands supported by the vehicle
|
||||
/// </summary>
|
||||
[JsonProperty("command")]
|
||||
public Command[] Command { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Details about a supported command
|
||||
/// </summary>
|
||||
public class Command
|
||||
{
|
||||
/// <summary>
|
||||
/// Command name
|
||||
/// </summary>
|
||||
[JsonProperty("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Description of what the command does
|
||||
/// </summary>
|
||||
[JsonProperty("description")]
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// API URL to be used for issuing the command
|
||||
/// This SDK uses this url rather than constructing it
|
||||
/// </summary>
|
||||
[JsonProperty("url")]
|
||||
public string Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True or False if the command requires the token to be upgraded with an OnStar PIN
|
||||
/// </summary>
|
||||
[JsonProperty("isPrivSessionRequired")]
|
||||
public bool? IsPrivSessionRequired { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// For commands with additional data such as diagnostics
|
||||
/// </summary>
|
||||
[JsonProperty("commandData")]
|
||||
public CommandData CommandData { get; set; }
|
||||
}
|
||||
@@ -132,12 +197,18 @@ namespace GM.Api.Models
|
||||
|
||||
public class SupportedDiagnostics
|
||||
{
|
||||
/// <summary>
|
||||
/// List of the diagnostic elements that may be requsted for the vehicle
|
||||
/// </summary>
|
||||
[JsonProperty("supportedDiagnostic")]
|
||||
public string[] SupportedDiagnostic { get; set; }
|
||||
}
|
||||
|
||||
public class Modules
|
||||
{
|
||||
/// <summary>
|
||||
/// List of modules - not much here
|
||||
/// </summary>
|
||||
[JsonProperty("module")]
|
||||
public Module[] Module { get; set; }
|
||||
}
|
||||
@@ -153,23 +224,43 @@ namespace GM.Api.Models
|
||||
|
||||
public class Entitlements
|
||||
{
|
||||
/// <summary>
|
||||
/// List of entitlements - features and activities vehicles are capable of
|
||||
/// List contains things the vehicle or account may or may not support
|
||||
/// Check the Elligible flag
|
||||
/// </summary>
|
||||
[JsonProperty("entitlement")]
|
||||
public Entitlement[] Entitlement { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Details about an Entitlement
|
||||
/// </summary>
|
||||
public class Entitlement
|
||||
{
|
||||
/// <summary>
|
||||
/// ID or name of entitlement
|
||||
/// </summary>
|
||||
[JsonProperty("id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True or false if the entitlement is available on this vehicle or account
|
||||
/// </summary>
|
||||
[JsonProperty("eligible")]
|
||||
public bool? Eligible { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Reason for inelligibility (whether the car is incapable or the owner isn't subscribed)
|
||||
/// </summary>
|
||||
[JsonProperty("ineligibleReasonCode")]
|
||||
public string IneligibleReasonCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True or false if the entitlement can send notifications
|
||||
/// </summary>
|
||||
[JsonProperty("notificationCapable")]
|
||||
public string NotificationCapable { get; set; }
|
||||
public bool? NotificationCapable { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace GM.WindowsUI
|
||||
_config = configuration;
|
||||
InitializeComponent();
|
||||
|
||||
foreach (var brandName in _config.brand_client_info.Keys.OrderBy((val) => val, StringComparer.OrdinalIgnoreCase))
|
||||
foreach (var brandName in _config.BrandClientInfo.Keys.OrderBy((val) => val, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
lstBrands.Items.Add(brandName.Substring(0, 1).ToUpperInvariant() + brandName.Substring(1));
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace GM.WindowsUI
|
||||
}
|
||||
|
||||
//todo: maybe the client reads the config and takes the brand and device id as param?
|
||||
_client = new GenericGMClient(_clientCredentials.client_id, Properties.Settings.Default.DeviceId, _clientCredentials.client_secret, _apiConfig.url);
|
||||
_client = new GenericGMClient(_clientCredentials.ClientId, Properties.Settings.Default.DeviceId, _clientCredentials.ClientSecret, _apiConfig.Url);
|
||||
_client.TokenUpdateCallback = TokenUpdateHandler;
|
||||
|
||||
if (!string.IsNullOrEmpty(Properties.Settings.Default.LoginData))
|
||||
@@ -119,8 +119,8 @@ namespace GM.WindowsUI
|
||||
|
||||
Title = _brandDisplay + " Vehicle Control";
|
||||
|
||||
_clientCredentials = _globalConfig.brand_client_info[_brand];
|
||||
_apiConfig = (from f in _globalConfig.configs where f.name.Equals(_brand, StringComparison.OrdinalIgnoreCase) select f).FirstOrDefault();
|
||||
_clientCredentials = _globalConfig.BrandClientInfo[_brand];
|
||||
_apiConfig = (from f in _globalConfig.Configs where f.Name.Equals(_brand, StringComparison.OrdinalIgnoreCase) select f).FirstOrDefault();
|
||||
}
|
||||
|
||||
void LoadConfiguration()
|
||||
@@ -393,7 +393,7 @@ namespace GM.WindowsUI
|
||||
lblStatus.Content = "Getting Diagnostics (Please Wait)...";
|
||||
var details = await _client.GetDiagnostics();
|
||||
txtOutput.Text = JsonConvert.SerializeObject(details, Formatting.Indented);
|
||||
|
||||
lblStatus.Content = "Getting Diagnostics Complete";
|
||||
grpActions.IsEnabled = true;
|
||||
btnLogin.IsEnabled = true;
|
||||
}
|
||||
|
||||
17
README.md
17
README.md
@@ -25,16 +25,11 @@ VERY IMPORTANT: Unless you want an international incident on your hands DO NOT S
|
||||
# TODO
|
||||
This is very early, unpolished, incomplete code. No judgement please.
|
||||
|
||||
* Implement more commands
|
||||
* Analyze and implement vehicle location capability
|
||||
* consider using MS JWT implementation
|
||||
* Implement secure means of saving onstar pin. If possible.
|
||||
* recognize response from calling priv'd command without upgrade and trigger upgrade using saved pin.
|
||||
|
||||
Notes: The android app saves the onstar pin using biometrics to unlock - no difference in the api calls. It does not use a different token refresh mechanism after elevating permissions, but the elevation persists across a refresh. The upgrade request does not specify an expiration. Testing will be required to determine the lifespan of token upgrades.
|
||||
|
||||
TODO: implement lots more actions
|
||||
|
||||
TODO: Complete updating JSON model property names
|
||||
|
||||
Note: the android app saves the onstar pin using biometrics to unlock - no difference in the api calls
|
||||
Note: the android app does not use a different token refresh mechanism after elevating permissions, but the elevation persists across a refresh. The upgrade request does not specify an expiration. Testing will be required to determine the lifespan of token upgrades.
|
||||
|
||||
TODO: Implement secure means of saving onstar pin. If possible.
|
||||
TODO: recognize response from calling priv'd command without upgrade and trigger upgrade using saved pin.
|
||||
|
||||
TODO: consider using MS JWT implementation
|
||||
|
||||
Reference in New Issue
Block a user