├── .nuget
├── NuGet.exe
├── NuGet.Config
└── NuGet.targets
├── README.md
├── TeslaConsole
├── App.config
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── TeslaConsole.csproj
├── TeslaLib
├── packages.config
├── Models
│ ├── ResultStatus.cs
│ ├── LoginToken.cs
│ ├── GuiSettingsStatus.cs
│ ├── DriveStateStatus.cs
│ ├── ClimateStateStatus.cs
│ ├── VehicleStateStatus.cs
│ ├── ChargeStateStatus.cs
│ └── VehicleOptions.cs
├── Converters
│ ├── UnixTimeConverter.cs
│ ├── VehicleOptionsConverter.cs
│ └── UnixTimestampConverter.cs
├── Extensions.cs
├── LoginTokenCache.cs
├── TeslaClient.cs
├── TeslaLib.csproj
└── TeslaVehicle.cs
├── TeslaLib.sln
└── .gitignore
/.nuget/NuGet.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/arch/TeslaLib/master/.nuget/NuGet.exe
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | TeslaLib
2 | ========
3 |
4 | Tesla Model S C# API Implementation
5 |
--------------------------------------------------------------------------------
/.nuget/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/TeslaConsole/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/TeslaLib/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/TeslaLib/Models/ResultStatus.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace TeslaLib.Models
4 | {
5 | public class ResultStatus
6 | {
7 |
8 | [JsonProperty(PropertyName = "reason")]
9 | public string Reason { get; set; }
10 |
11 | [JsonProperty(PropertyName = "result")]
12 | public bool Result { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/TeslaLib/Converters/UnixTimeConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace TeslaLib.Converters
8 | {
9 | public static class UnixTimeConverter
10 | {
11 | public static DateTimeOffset FromUnixTime(long unixTimeStamp)
12 | {
13 | DateTimeOffset time = new DateTimeOffset(1970, 1, 1, 0, 0, 0, 0, new TimeSpan(0));
14 | time = time.AddSeconds(unixTimeStamp).ToLocalTime();
15 | return time;
16 | }
17 |
18 | public static TimeSpan FromUnixTimeSpan(long unixTimeSpan)
19 | {
20 | TimeSpan timeSpan = TimeSpan.FromSeconds(unixTimeSpan);
21 | return timeSpan;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/TeslaConsole/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using TeslaLib;
3 |
4 | namespace TeslaConsole
5 | {
6 | public class Program
7 | {
8 | public static void Main(string[] args)
9 | {
10 | string clientId = "";
11 | string clientSecret = "";
12 |
13 | string email = "";
14 | string password = "";
15 |
16 | TeslaClient client = new TeslaClient(email, clientId, clientSecret);
17 |
18 | client.Login(password);
19 |
20 | var vehicles = client.LoadVehicles();
21 |
22 | foreach (TeslaVehicle car in vehicles)
23 | {
24 | Console.WriteLine(car.Id + " " + car.VIN);
25 | }
26 |
27 | Console.ReadKey();
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/TeslaLib/Models/LoginToken.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using TeslaLib.Converters;
3 | using Newtonsoft.Json;
4 |
5 | namespace TeslaLib.Models
6 | {
7 | // Represents all the info for logging in, including a token, a type, and a creation time & expiration time
8 | // for the token. Times are in Unix times (seconds from 1970).
9 | // Example:
10 | // {"access_token":64 hex characters,"token_type":"bearer","expires_in":7776000,"created_at":1451181413}
11 | public class LoginToken
12 | {
13 | [JsonProperty(PropertyName = "access_token")]
14 | public string AccessToken { get; set; }
15 |
16 | [JsonProperty(PropertyName = "token_type")]
17 | public string TokenType { get; set; }
18 |
19 | // Returns a DateTime in UTC time.
20 | [JsonProperty(PropertyName = "created_at")]
21 | public DateTime CreatedAt { get; set; }
22 |
23 | // This should be a TimeSpan, but we can't deserialize it appropriately. Instead, this is the number of seconds to add to CreatedAt.
24 | // I couldn't get this to convert using the JsonConverter attribute.
25 | [JsonProperty(PropertyName = "expires_in")]
26 | public long ExpiresIn { get; set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/TeslaLib/Converters/VehicleOptionsConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using TeslaLib.Models;
4 |
5 | namespace TeslaLib.Converters
6 | {
7 | class VehicleOptionsConverter : JsonConverter
8 | {
9 | public override bool CanConvert(Type objectType)
10 | {
11 | return (objectType == typeof(VehicleOptions));
12 | }
13 |
14 | ///
15 | /// Convert the Option Codes into a VehicleOptions instance
16 | ///
17 | ///
18 | ///
19 | ///
20 | ///
21 | ///
22 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
23 | {
24 | string encoded = serializer.Deserialize(reader);
25 |
26 | VehicleOptions options = new VehicleOptions(encoded);
27 |
28 | return options;
29 | }
30 |
31 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
32 | {
33 | throw new NotImplementedException();
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/TeslaLib/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Runtime.Serialization;
4 |
5 | namespace TeslaLib
6 | {
7 | public static class Extensions
8 | {
9 | public static string GetEnumValue(this Enum enumValue)
10 | {
11 | //Look for DescriptionAttributes on the enum field
12 | object[] attr = enumValue.GetType().GetField(enumValue.ToString())
13 | .GetCustomAttributes(typeof(EnumMemberAttribute), false);
14 |
15 | if (attr.Length > 0) // a DescriptionAttribute exists; use it
16 | return ((EnumMemberAttribute)attr[0]).Value;
17 |
18 | string result = enumValue.ToString();
19 |
20 | return result;
21 | }
22 |
23 | public static T ToEnum(string str)
24 | {
25 | var enumType = typeof(T);
26 | foreach (var name in Enum.GetNames(enumType))
27 | {
28 | var enumMemberAttribute = ((EnumMemberAttribute[])enumType.GetField(name).GetCustomAttributes(typeof(EnumMemberAttribute), true)).Single();
29 | if (enumMemberAttribute.Value == str) return (T)Enum.Parse(enumType, name);
30 | }
31 |
32 |
33 | return default(T);
34 | }
35 |
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/TeslaLib/Models/GuiSettingsStatus.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Converters;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Runtime.Serialization;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace TeslaLib.Models
11 | {
12 | public class GuiSettingsStatus
13 | {
14 |
15 | public GuiSettingsStatus()
16 | {
17 |
18 | }
19 |
20 | [JsonProperty(PropertyName = "gui_distance_units")]
21 | public string DistanceUnits { get; set; }
22 |
23 | [JsonProperty(PropertyName = "gui_temperature_units")]
24 | [JsonConverter(typeof(StringEnumConverter))]
25 | public TemperatureUnits TemperatureUnits { get; set; }
26 |
27 | [JsonProperty(PropertyName = "gui_charge_rate_units")]
28 | public string ChargeRateUnits { get; set; }
29 |
30 | [JsonProperty(PropertyName = "gui_24_hour_time")]
31 | public bool Is24HourTime { get; set; }
32 |
33 | [JsonProperty(PropertyName = "gui_range_display")]
34 | public string RangeDisplay { get; set; }
35 |
36 | }
37 |
38 | public enum TemperatureUnits
39 | {
40 | [EnumMember(Value = "F")]
41 | FAHRENHEIT,
42 |
43 | [EnumMember(Value = "C")]
44 | CELSIUS,
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/TeslaLib/Converters/UnixTimestampConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace TeslaLib.Converters
5 | {
6 | class UnixTimestampConverter: JsonConverter
7 | {
8 | public override bool CanConvert(Type objectType)
9 | {
10 | return (objectType == typeof(DateTime));
11 | }
12 |
13 | ///
14 | /// Convert Unix Timestamp to a DateTime object
15 | ///
16 | ///
17 | ///
18 | ///
19 | ///
20 | ///
21 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
22 | {
23 | long unixTimestamp = serializer.Deserialize(reader);
24 |
25 | // Convert the Unix Timestamp to a readable DateTime
26 | DateTime time = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
27 | time = time.AddSeconds(unixTimestamp).ToLocalTime();
28 |
29 | return time;
30 | }
31 |
32 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
33 | {
34 | throw new NotImplementedException();
35 | }
36 | }
37 | }
38 |
39 |
40 |
--------------------------------------------------------------------------------
/TeslaConsole/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TeslaConsole")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TeslaConsole")]
13 | [assembly: AssemblyCopyright("Copyright © 2013")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("5ee8a776-d5ef-45c0-8871-6ce97f1cf43d")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/TeslaLib/Models/DriveStateStatus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 | using Newtonsoft.Json;
4 | using Newtonsoft.Json.Converters;
5 | using TeslaLib.Converters;
6 |
7 | namespace TeslaLib.Models
8 | {
9 | public class DriveStateStatus
10 | {
11 | public DriveStateStatus()
12 | {
13 |
14 | }
15 |
16 | [JsonProperty(PropertyName = "shift_state")]
17 | [JsonConverter(typeof(StringEnumConverter))]
18 | public ShiftState? ShiftState { get; set; }
19 |
20 | [JsonProperty(PropertyName = "speed")]
21 | public int? Speed { get; set; }
22 |
23 | ///
24 | /// Degrees N of the equator
25 | ///
26 | [JsonProperty(PropertyName = "latitude")]
27 | public double Latitude { get; set; }
28 |
29 | ///
30 | /// Degrees W of the prime meridian
31 | ///
32 | [JsonProperty(PropertyName = "longitude")]
33 | public double Longitude { get; set; }
34 |
35 | ///
36 | /// Integer compass heading (0-359)
37 | ///
38 | [JsonProperty(PropertyName = "heading")]
39 | public int Heading { get; set; }
40 |
41 | [JsonProperty(PropertyName = "gps_as_of")]
42 | [JsonConverter(typeof(UnixTimestampConverter))]
43 | public DateTime GpsAsOf { get; set; }
44 |
45 | }
46 |
47 | public enum ShiftState
48 | {
49 | [EnumMember(Value = "D")]
50 | DRIVE,
51 |
52 | [EnumMember(Value = "N")]
53 | NEUTRAL,
54 |
55 | [EnumMember(Value = "P")]
56 | PARK,
57 |
58 | [EnumMember(Value = "R")]
59 | REVERSE,
60 | }
61 | }
--------------------------------------------------------------------------------
/TeslaLib/Models/ClimateStateStatus.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace TeslaLib.Models
4 | {
5 | public class ClimateStateStatus
6 | {
7 |
8 | public ClimateStateStatus()
9 | {
10 |
11 | }
12 |
13 | ///
14 | /// Degrees C inside the car
15 | ///
16 | [JsonProperty(PropertyName = "inside_temp")]
17 | public double? InsideTemperature { get; set; }
18 |
19 | ///
20 | /// Degrees C outside of the car
21 | ///
22 | [JsonProperty(PropertyName = "outside_temp")]
23 | public double? OutsideTemperature { get; set; }
24 |
25 | ///
26 | /// Degrees C of the driver temperature setpoint
27 | ///
28 | [JsonProperty(PropertyName = "driver_temp_setting")]
29 | public double DriverTemperatureSetting { get; set; }
30 |
31 | ///
32 | /// Degrees C of the passenger temperature setpoint
33 | ///
34 | [JsonProperty(PropertyName = "passenger_temp_setting")]
35 | public double PassengerTemperatureSetting { get; set; }
36 |
37 | [JsonProperty(PropertyName = "is_auto_conditioning_on")]
38 | public bool? IsAutoAirConditioning { get; set; }
39 |
40 | [JsonProperty(PropertyName = "is_front_defroster_on")]
41 | public bool? IsFrontDefrosterOn { get; set; }
42 |
43 | [JsonProperty(PropertyName = "is_rear_defroster_on")]
44 | public bool? IsRearDefrosterOn { get; set; }
45 |
46 | ///
47 | /// Fan Speed
48 | /// 0-6 or null
49 | ///
50 | [JsonProperty(PropertyName = "fan_status")]
51 | public int? FanStatus { get; set; }
52 | }
53 | }
--------------------------------------------------------------------------------
/TeslaConsole/TeslaConsole.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {E13E5860-B0B5-4218-B22E-E8ED6FA19736}
8 | Exe
9 | Properties
10 | TeslaConsole
11 | TeslaConsole
12 | v4.5
13 | 512
14 |
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | {c8a33d14-7634-4ae2-a849-ac7308e4b137}
54 | TeslaLib
55 |
56 |
57 |
58 |
65 |
--------------------------------------------------------------------------------
/TeslaLib.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.23107.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeslaLib", "TeslaLib\TeslaLib.csproj", "{C8A33D14-7634-4AE2-A849-AC7308E4B137}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeslaConsole", "TeslaConsole\TeslaConsole.csproj", "{E13E5860-B0B5-4218-B22E-E8ED6FA19736}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{47B43B52-E49F-4766-804B-21C553930D2B}"
11 | ProjectSection(SolutionItems) = preProject
12 | .nuget\NuGet.Config = .nuget\NuGet.Config
13 | .nuget\NuGet.exe = .nuget\NuGet.exe
14 | .nuget\NuGet.targets = .nuget\NuGet.targets
15 | EndProjectSection
16 | EndProject
17 | Global
18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
19 | Debug|Any CPU = Debug|Any CPU
20 | Debug|Mixed Platforms = Debug|Mixed Platforms
21 | Debug|x86 = Debug|x86
22 | Release|Any CPU = Release|Any CPU
23 | Release|Mixed Platforms = Release|Mixed Platforms
24 | Release|x86 = Release|x86
25 | EndGlobalSection
26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
27 | {C8A33D14-7634-4AE2-A849-AC7308E4B137}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {C8A33D14-7634-4AE2-A849-AC7308E4B137}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {C8A33D14-7634-4AE2-A849-AC7308E4B137}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
30 | {C8A33D14-7634-4AE2-A849-AC7308E4B137}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
31 | {C8A33D14-7634-4AE2-A849-AC7308E4B137}.Debug|x86.ActiveCfg = Debug|Any CPU
32 | {C8A33D14-7634-4AE2-A849-AC7308E4B137}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {C8A33D14-7634-4AE2-A849-AC7308E4B137}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {C8A33D14-7634-4AE2-A849-AC7308E4B137}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
35 | {C8A33D14-7634-4AE2-A849-AC7308E4B137}.Release|Mixed Platforms.Build.0 = Release|Any CPU
36 | {C8A33D14-7634-4AE2-A849-AC7308E4B137}.Release|x86.ActiveCfg = Release|Any CPU
37 | {E13E5860-B0B5-4218-B22E-E8ED6FA19736}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38 | {E13E5860-B0B5-4218-B22E-E8ED6FA19736}.Debug|Any CPU.Build.0 = Debug|Any CPU
39 | {E13E5860-B0B5-4218-B22E-E8ED6FA19736}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
40 | {E13E5860-B0B5-4218-B22E-E8ED6FA19736}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
41 | {E13E5860-B0B5-4218-B22E-E8ED6FA19736}.Debug|x86.ActiveCfg = Debug|Any CPU
42 | {E13E5860-B0B5-4218-B22E-E8ED6FA19736}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {E13E5860-B0B5-4218-B22E-E8ED6FA19736}.Release|Any CPU.Build.0 = Release|Any CPU
44 | {E13E5860-B0B5-4218-B22E-E8ED6FA19736}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
45 | {E13E5860-B0B5-4218-B22E-E8ED6FA19736}.Release|Mixed Platforms.Build.0 = Release|Any CPU
46 | {E13E5860-B0B5-4218-B22E-E8ED6FA19736}.Release|x86.ActiveCfg = Release|Any CPU
47 | EndGlobalSection
48 | GlobalSection(SolutionProperties) = preSolution
49 | HideSolutionNode = FALSE
50 | EndGlobalSection
51 | GlobalSection(ExtensibilityGlobals) = postSolution
52 | VisualSVNWorkingCopyRoot = .
53 | EndGlobalSection
54 | EndGlobal
55 |
--------------------------------------------------------------------------------
/TeslaLib/LoginTokenCache.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using TeslaLib.Converters;
6 | using TeslaLib.Models;
7 |
8 | namespace TeslaLib
9 | {
10 | internal static class LoginTokenCache
11 | {
12 | private const String CacheFileName = "TeslaLoginTokenCache.cache";
13 | // Make sure the token from the cache is valid for this long.
14 | private static readonly TimeSpan ExpirationTimeWindow = TimeSpan.FromDays(1);
15 |
16 | private static Dictionary Tokens = new Dictionary();
17 | private static bool haveReadCacheFile = false;
18 |
19 | private static void ReadCacheFile()
20 | {
21 | Tokens.Clear();
22 | if (!File.Exists(CacheFileName))
23 | return;
24 |
25 | JsonSerializer serializer = new JsonSerializer();
26 | using(StreamReader reader = File.OpenText(CacheFileName))
27 | {
28 | JsonReader jsonReader = new JsonTextReader(reader);
29 | String emailAddress = null;
30 | while (!reader.EndOfStream)
31 | {
32 | emailAddress = reader.ReadLine();
33 | LoginToken token = serializer.Deserialize(jsonReader);
34 | Tokens.Add(emailAddress, token);
35 | }
36 | }
37 | }
38 |
39 | private static void WriteCacheFile()
40 | {
41 | using (StreamWriter writer = File.CreateText(CacheFileName))
42 | {
43 | JsonSerializer serializer = new JsonSerializer();
44 | foreach (var pair in Tokens)
45 | {
46 | writer.WriteLine(pair.Key);
47 | serializer.Serialize(writer, pair.Value);
48 | writer.WriteLine();
49 | }
50 | }
51 | }
52 |
53 | public static LoginToken GetToken(String emailAddress)
54 | {
55 | if (!haveReadCacheFile)
56 | {
57 | ReadCacheFile();
58 | haveReadCacheFile = true;
59 | }
60 |
61 | LoginToken token;
62 | if (!Tokens.TryGetValue(emailAddress, out token))
63 | {
64 | return null;
65 | }
66 |
67 | // Ensure the LoginToken is still valid.
68 | DateTime expirationTime = token.CreatedAt.ToLocalTime() + UnixTimeConverter.FromUnixTimeSpan(token.ExpiresIn);
69 | if (DateTime.Now + ExpirationTimeWindow >= expirationTime)
70 | {
71 | Tokens.Remove(emailAddress);
72 | WriteCacheFile();
73 | token = null;
74 | }
75 | return token;
76 | }
77 |
78 | public static void AddToken(String emailAddress, LoginToken token)
79 | {
80 | Tokens[emailAddress] = token;
81 | WriteCacheFile();
82 | }
83 |
84 | public static void ClearCache()
85 | {
86 | Tokens.Clear();
87 | File.Delete(CacheFileName);
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/TeslaLib/TeslaClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Newtonsoft.Json;
4 | using Newtonsoft.Json.Linq;
5 | using RestSharp;
6 | using TeslaLib.Models;
7 | using TeslaLib.Converters;
8 |
9 | namespace TeslaLib
10 | {
11 |
12 | public class TeslaClient
13 | {
14 | public string Email { get; }
15 | public string TeslaClientID { get; }
16 | public string TeslaClientSecret { get; }
17 | public string AccessToken { get; private set; }
18 |
19 | public RestClient Client { get; set; }
20 |
21 | public static readonly string BASE_URL = "https://owner-api.teslamotors.com/api/1";
22 | public static readonly string VERSION = "1.1.0";
23 |
24 | public TeslaClient(string email, string teslaClientId, string teslaClientSecret)
25 | {
26 | Email = email;
27 | TeslaClientID = teslaClientId;
28 | TeslaClientSecret = teslaClientSecret;
29 |
30 | Client = new RestClient(BASE_URL);
31 | Client.Authenticator = new TeslaAuthenticator();
32 | }
33 |
34 | public class TeslaAuthenticator : RestSharp.Authenticators.IAuthenticator
35 | {
36 | public string Token { get; set; }
37 | public void Authenticate(IRestClient client, IRestRequest request)
38 | {
39 | request.AddHeader("Authorization", $"Bearer {Token}");
40 | }
41 | }
42 |
43 | public void LoginUsingCache(string password)
44 | {
45 | LoginToken token = LoginTokenCache.GetToken(Email);
46 | if (token != null)
47 | {
48 | SetToken(token);
49 | }
50 | else
51 | {
52 | token = GetLoginToken(password);
53 | SetToken(token);
54 | LoginTokenCache.AddToken(Email, token);
55 | }
56 | }
57 |
58 | public void Login(string password)
59 | {
60 | LoginToken token = GetLoginToken(password);
61 | SetToken(token);
62 | }
63 |
64 | private LoginToken GetLoginToken(string password)
65 | {
66 | var loginClient = new RestClient("https://owner-api.teslamotors.com/oauth");
67 | var request = new RestRequest("token");
68 | request.RequestFormat = DataFormat.Json;
69 | request.AddBody(new
70 | {
71 | grant_type = "password",
72 | client_id = TeslaClientID,
73 | client_secret = TeslaClientSecret,
74 | email = Email,
75 | password = password
76 | });
77 | var response = loginClient.Post(request);
78 | var token = response.Data;
79 | return token;
80 | }
81 |
82 | internal void SetToken(LoginToken token)
83 | {
84 | var auth = Client.Authenticator as TeslaAuthenticator;
85 | auth.Token = token.AccessToken;
86 | AccessToken = token.AccessToken;
87 | }
88 |
89 | public void ClearLoginTokenCache()
90 | {
91 | LoginTokenCache.ClearCache();
92 | }
93 |
94 | public List LoadVehicles()
95 | {
96 | var request = new RestRequest("vehicles");
97 | var response = Client.Get(request);
98 |
99 | var json = JObject.Parse(response.Content)["response"];
100 | var data = JsonConvert.DeserializeObject>(json.ToString());
101 |
102 | data.ForEach(x => x.Client = Client);
103 |
104 | return data;
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 | [Dd]ebug/
11 | [Dd]ebugPublic/
12 | [Rr]elease/
13 | [Rr]eleases/
14 | x64/
15 | build/
16 | bld/
17 | [Bb]in/
18 | [Oo]bj/
19 |
20 | # Roslyn cache directories
21 | *.ide/
22 |
23 | # MSTest test Results
24 | [Tt]est[Rr]esult*/
25 | [Bb]uild[Ll]og.*
26 |
27 | #NUNIT
28 | *.VisualState.xml
29 | TestResult.xml
30 |
31 | # Build Results of an ATL Project
32 | [Dd]ebugPS/
33 | [Rr]eleasePS/
34 | dlldata.c
35 |
36 | *_i.c
37 | *_p.c
38 | *_i.h
39 | *.ilk
40 | *.meta
41 | *.obj
42 | *.pch
43 | *.pdb
44 | *.pgc
45 | *.pgd
46 | *.rsp
47 | *.sbr
48 | *.tlb
49 | *.tli
50 | *.tlh
51 | *.tmp
52 | *.tmp_proj
53 | *.log
54 | *.vspscc
55 | *.vssscc
56 | .builds
57 | *.pidb
58 | *.svclog
59 | *.scc
60 |
61 | # Chutzpah Test files
62 | _Chutzpah*
63 |
64 | # Visual C++ cache files
65 | ipch/
66 | *.aps
67 | *.ncb
68 | *.opensdf
69 | *.sdf
70 | *.cachefile
71 |
72 | # Visual Studio profiler
73 | *.psess
74 | *.vsp
75 | *.vspx
76 |
77 | # TFS 2012 Local Workspace
78 | $tf/
79 |
80 | # Guidance Automation Toolkit
81 | *.gpState
82 |
83 | # ReSharper is a .NET coding add-in
84 | _ReSharper*/
85 | *.[Rr]e[Ss]harper
86 | *.DotSettings.user
87 |
88 | # JustCode is a .NET coding addin-in
89 | .JustCode
90 |
91 | # TeamCity is a build add-in
92 | _TeamCity*
93 |
94 | # DotCover is a Code Coverage Tool
95 | *.dotCover
96 |
97 | # NCrunch
98 | _NCrunch_*
99 | .*crunch*.local.xml
100 |
101 | # MightyMoose
102 | *.mm.*
103 | AutoTest.Net/
104 |
105 | # Web workbench (sass)
106 | .sass-cache/
107 |
108 | # Installshield output folder
109 | [Ee]xpress/
110 |
111 | # DocProject is a documentation generator add-in
112 | DocProject/buildhelp/
113 | DocProject/Help/*.HxT
114 | DocProject/Help/*.HxC
115 | DocProject/Help/*.hhc
116 | DocProject/Help/*.hhk
117 | DocProject/Help/*.hhp
118 | DocProject/Help/Html2
119 | DocProject/Help/html
120 |
121 | # Click-Once directory
122 | publish/
123 |
124 | # Publish Web Output
125 | *.[Pp]ublish.xml
126 | *.azurePubxml
127 | ## TODO: Comment the next line if you want to checkin your
128 | ## web deploy settings but do note that will include unencrypted
129 | ## passwords
130 | *.pubxml
131 |
132 | # NuGet Packages
133 | packages/*
134 | *.nupkg
135 | ## TODO: If the tool you use requires repositories.config
136 | ## uncomment the next line
137 | #!packages/repositories.config
138 |
139 | # Enable "build/" folder in the NuGet Packages folder since
140 | # NuGet packages use it for MSBuild targets.
141 | # This line needs to be after the ignore of the build folder
142 | # (and the packages folder if the line above has been uncommented)
143 | !packages/build/
144 |
145 | # Windows Azure Build Output
146 | csx/
147 | *.build.csdef
148 |
149 | # Windows Store app package directory
150 | AppPackages/
151 |
152 | # Others
153 | sql/
154 | *.Cache
155 | ClientBin/
156 | [Ss]tyle[Cc]op.*
157 | ~$*
158 | *~
159 | *.dbmdl
160 | *.dbproj.schemaview
161 | *.pfx
162 | *.publishsettings
163 | node_modules/
164 |
165 | # RIA/Silverlight projects
166 | Generated_Code/
167 |
168 | # Backup & report files from converting an old project file
169 | # to a newer Visual Studio version. Backup files are not needed,
170 | # because we have git ;-)
171 | _UpgradeReport_Files/
172 | Backup*/
173 | UpgradeLog*.XML
174 | UpgradeLog*.htm
175 |
176 | # SQL Server files
177 | *.mdf
178 | *.ldf
179 |
180 | # Business Intelligence projects
181 | *.rdl.data
182 | *.bim.layout
183 | *.bim_*.settings
184 |
185 | # Microsoft Fakes
186 | FakesAssemblies/
--------------------------------------------------------------------------------
/TeslaLib/Models/VehicleStateStatus.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Converters;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Runtime.Serialization;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace TeslaLib.Models
11 | {
12 | public class VehicleStateStatus
13 | {
14 |
15 | public VehicleStateStatus()
16 | {
17 |
18 | }
19 |
20 | [JsonProperty(PropertyName = "df")]
21 | public bool IsDriverFrontDoorOpen { get; set; }
22 |
23 | [JsonProperty(PropertyName = "dr")]
24 | public bool IsDriverRearDoorOpen { get; set; }
25 |
26 | [JsonProperty(PropertyName = "pf")]
27 | public bool IsPassengerFrontDoorOpen { get; set; }
28 |
29 | [JsonProperty(PropertyName = "pr")]
30 | public bool IsPassengerRearDoorOpen { get; set; }
31 |
32 | [JsonProperty(PropertyName = "ft")]
33 | public bool IsFrontTrunkOpen { get; set; }
34 |
35 | [JsonProperty(PropertyName = "rt")]
36 | public bool IsRearTrunkOpen { get; set; }
37 |
38 | [JsonProperty(PropertyName = "car_version")]
39 | public string CarVersion { get; set; }
40 |
41 | [JsonProperty(PropertyName = "locked")]
42 | public bool IsLocked { get; set; }
43 |
44 | [JsonProperty(PropertyName = "sun_roof_installed")]
45 | public bool HasPanoramicRoof { get; set; }
46 |
47 | [JsonProperty(PropertyName = "sun_roof_state")]
48 | [JsonConverter(typeof(StringEnumConverter))]
49 | public PanoramicRoofState PanoramicRoofState { get; set; }
50 |
51 | [JsonProperty(PropertyName = "sun_roof_percent_open")]
52 | public int PanoramicRoofPercentOpen { get; set; }
53 |
54 | [JsonProperty(PropertyName = "dark_rims")]
55 | public bool HasDarkRims { get; set; }
56 |
57 | [JsonProperty(PropertyName = "wheel_type")]
58 | [JsonConverter(typeof(StringEnumConverter))]
59 | public WheelType WheelType { get; set; }
60 |
61 | [JsonProperty(PropertyName = "has_spoiler")]
62 | public bool HasSpoiler { get; set; }
63 |
64 | [JsonProperty(PropertyName = "roof_color")]
65 | [JsonConverter(typeof(StringEnumConverter))]
66 | public RoofType RoofColor { get; set; }
67 |
68 | [JsonProperty(PropertyName = "perf_config")]
69 | [JsonConverter(typeof(StringEnumConverter))]
70 | public PerformanceConfiguration PerformanceConfiguration { get; set; }
71 |
72 | // Updates to Tesla API's around December 2015:
73 | // Updated firmware from v7.0 (2.7.56) to v7(2.9.12) Some new fields added:
74 |
75 | [JsonProperty(PropertyName = "car_type")]
76 | public String CarType { get; set; } // "s"
77 |
78 | [JsonProperty(PropertyName = "third_row_seats")]
79 | public String ThirdRowSeats { get; set; } // "None"
80 | }
81 |
82 | public enum PanoramicRoofState
83 | {
84 | [EnumMember(Value = "Open")]
85 | OPEN,
86 |
87 | [EnumMember(Value = "Comfort")]
88 | COMFORT,
89 |
90 | [EnumMember(Value = "Vent")]
91 | VENT,
92 |
93 | [EnumMember(Value = "Close")]
94 | CLOSE,
95 |
96 | [EnumMember(Value = "MOve")]
97 | MOVE,
98 |
99 | [EnumMember(Value = "Unknown")]
100 | UNKNOWN,
101 | }
102 |
103 | public enum WheelType
104 | {
105 |
106 | [EnumMember(Value = "Base19")]
107 | BASE_19,
108 |
109 | [EnumMember(Value = "Silver21")]
110 | SILVER_21,
111 |
112 | [EnumMember(Value = "Charcoal21")]
113 | CHARCOAL_21,
114 |
115 | CHARCOAL_PERFORMANCE_21
116 | }
117 |
118 | public enum RoofType
119 | {
120 | [EnumMember(Value ="Colored")]
121 | COLORED,
122 |
123 | [EnumMember(Value = "None")]
124 | NONE,
125 |
126 | [EnumMember(Value = "Black")]
127 | BLACK
128 | }
129 |
130 | public enum PerformanceConfiguration
131 | {
132 | [EnumMember(Value = "Base")]
133 | BASE,
134 |
135 | [EnumMember(Value = "Sport")]
136 | SPORT,
137 |
138 | [EnumMember(Value = "P2")]
139 | P2
140 | }
141 | }
--------------------------------------------------------------------------------
/TeslaLib/TeslaLib.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C8A33D14-7634-4AE2-A849-AC7308E4B137}
8 | Library
9 | Properties
10 | TeslaLib
11 | TeslaLib
12 | v4.5
13 | 512
14 | ..\
15 | true
16 |
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | AnyCPU
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 |
37 |
38 |
39 |
40 |
41 |
42 | ..\packages\Newtonsoft.Json.8.0.1\lib\net45\Newtonsoft.Json.dll
43 | True
44 |
45 |
46 | ..\packages\RestSharp.105.2.3\lib\net45\RestSharp.dll
47 | True
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | Designer
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
92 |
--------------------------------------------------------------------------------
/TeslaLib/Models/ChargeStateStatus.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Converters;
3 | using System;
4 | using System.Runtime.Serialization;
5 |
6 | namespace TeslaLib.Models
7 | {
8 | public class ChargeStateStatus
9 | {
10 | [JsonProperty(PropertyName = "charging_state")]
11 | [JsonConverter(typeof(StringEnumConverter))]
12 | public ChargingState ChargingState { get; set; }
13 |
14 | [JsonProperty(PropertyName = "battery_current")]
15 | public double? BatteryCurrent { get; set; }
16 |
17 | [JsonProperty(PropertyName = "battery_heater_on")]
18 | public bool? IsBatteryHeaterOn { get; set; }
19 |
20 | [JsonProperty(PropertyName = "battery_level")]
21 | public int BatteryLevel { get; set; }
22 |
23 | [JsonProperty(PropertyName = "battery_range")]
24 | public double BatteryRange { get; set; }
25 |
26 | [JsonProperty(PropertyName = "charge_enable_request")]
27 | public bool IsChargeEnableRequest { get; set; }
28 |
29 | [JsonProperty(PropertyName = "charge_limit_soc")]
30 | public int ChargeLimitSoc { get; set; }
31 |
32 | [JsonProperty(PropertyName = "charge_limit_soc_max")]
33 | public int ChargeLimitSocMax { get; set; }
34 |
35 | [JsonProperty(PropertyName = "charge_limit_soc_min")]
36 | public int ChargeLimitSocMin { get; set; }
37 |
38 | [JsonProperty(PropertyName = "charge_limit_soc_std")]
39 | public int ChargeLimitSocStd { get; set; }
40 |
41 | [JsonProperty(PropertyName = "charge_port_door_open")]
42 | public bool? IsChargePortDoorOpen { get; set; }
43 |
44 | [JsonProperty(PropertyName = "charge_rate")]
45 | public double ChargeRate { get; set; }
46 |
47 | // No longer returned as of Jan 2016.
48 | //[JsonProperty(PropertyName = "charge_starting_range")]
49 | //public int? ChargeStartingRange { get; set; }
50 |
51 | //[JsonProperty(PropertyName = "charge_starting_soc")]
52 | //public int? ChargeStartingSoc { get; set; }
53 |
54 | [JsonProperty(PropertyName = "charge_to_max_range")]
55 | public bool IsChargeToMaxRange { get; set; }
56 |
57 | [JsonProperty(PropertyName = "charger_actual_current")]
58 | public int? ChargerActualCurrent { get; set; }
59 |
60 | [JsonProperty(PropertyName = "charger_pilot_current")]
61 | public int? ChargerPilotCurrent { get; set; }
62 |
63 | [JsonProperty(PropertyName = "charger_power")]
64 | public int? ChargerPower { get; set; }
65 |
66 | [JsonProperty(PropertyName = "charger_voltage")]
67 | public int? ChargerVoltage { get; set; } // null when a car is starting to charge.
68 |
69 | [JsonProperty(PropertyName = "est_battery_range")]
70 | public double EstimatedBatteryRange { get; set; }
71 |
72 | [JsonProperty(PropertyName = "fast_charger_present")]
73 | public bool? IsUsingSupercharger { get; set; }
74 |
75 | [JsonProperty(PropertyName = "ideal_battery_range")]
76 | public double IdealBatteryRange { get; set; }
77 |
78 | [JsonProperty(PropertyName = "max_range_charge_counter")]
79 | public int MaxRangeChargeCounter { get; set; }
80 |
81 | [JsonProperty(PropertyName = "not_enough_power_to_heat")]
82 | public bool? IsNotEnoughPowerToHeat { get; set; }
83 |
84 | [JsonProperty(PropertyName = "scheduled_charging_pending")]
85 | public bool ScheduledChargingPending { get; set; }
86 |
87 | [JsonProperty(PropertyName = "scheduled_charging_start_time")]
88 | public DateTime? ScheduledChargingStartTime { get; set; }
89 |
90 | [JsonProperty(PropertyName = "time_to_full_charge")]
91 | public double? TimeUntilFullCharge { get; set; }
92 |
93 | [JsonProperty(PropertyName = "user_charge_enable_request")]
94 | public bool? IsUserChargeEnableRequest { get; set; }
95 |
96 | // Updates to Tesla API's
97 | // Updated at an unknown time
98 |
99 | [JsonProperty(PropertyName = "trip_charging")]
100 | public bool? IsTripCharging { get; set; }
101 |
102 | [JsonProperty(PropertyName = "charger_phases")]
103 | public int? ChargerPhases { get; set; }
104 |
105 | [JsonProperty(PropertyName = "motorized_charge_port")]
106 | public bool? IsMotorizedChargePort { get; set; }
107 |
108 | // Seen values "\u003Cinvalid\u003E"
109 | [JsonProperty(PropertyName = "fast_charger_type")]
110 | public String FastChargerType { get; set; }
111 |
112 | [JsonProperty(PropertyName = "usable_battery_level")]
113 | public int? UsableBatteryLevel { get; set; }
114 |
115 | [JsonProperty(PropertyName = "charge_energy_added")]
116 | public double? ChargeEnergyAdded { get; set; }
117 |
118 | [JsonProperty(PropertyName = "charge_miles_added_rated")]
119 | public double? ChargeMilesAddedRated { get; set; }
120 |
121 | [JsonProperty(PropertyName = "charge_miles_added_ideal")]
122 | public double? ChargeMilesAddedIdeal { get; set; }
123 |
124 | [JsonProperty(PropertyName = "eu_vehicle")]
125 | public bool IsEUVehicle { get; set; }
126 |
127 | // Updates to Tesla API's around December 2015:
128 | // Updated firmware from v7.0 (2.7.56) to v7(2.9.12) Some new fields added:
129 |
130 | [JsonProperty(PropertyName = "charge_port_latch")]
131 | public String ChargePortLatch { get; set; } // "Engaged"
132 |
133 | [JsonProperty(PropertyName = "charge_current_request")]
134 | public int? ChargeCurrentRequest { get; set; } // amps
135 |
136 | [JsonProperty(PropertyName = "charge_current_request_max")]
137 | public int? ChargeCurrentRequestMax { get; set; } // amps
138 |
139 | [JsonProperty(PropertyName = "managed_charging_active")]
140 | public bool? ManagedChargingActive { get; set; }
141 |
142 | [JsonProperty(PropertyName = "managed_charging_user_canceled")]
143 | public bool? ManagedChargingUserCanceled { get; set; }
144 |
145 | [JsonProperty(PropertyName = "managed_charging_start_time")]
146 | public DateTime? ManagedChargingStartTime { get; set; }
147 | }
148 |
149 | public enum ChargingState
150 | {
151 | [EnumMember(Value = "Complete")]
152 | Complete,
153 |
154 | [EnumMember(Value = "Charging")]
155 | Charging,
156 |
157 | [EnumMember(Value = "Disconnected")]
158 | Disconnected,
159 |
160 | [EnumMember(Value = "Pending")]
161 | Pending,
162 |
163 | [EnumMember(Value = "NotCharging")]
164 | NotCharging,
165 |
166 | [EnumMember(Value = "Starting")]
167 | Starting,
168 |
169 | [EnumMember(Value = "Stopped")]
170 | Stopped,
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/.nuget/NuGet.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildProjectDirectory)\..\
5 |
6 |
7 | false
8 |
9 |
10 | false
11 |
12 |
13 | true
14 |
15 |
16 | false
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget"))
31 | $([System.IO.Path]::Combine($(ProjectDir), "packages.config"))
32 |
33 |
34 |
35 |
36 | $(SolutionDir).nuget
37 | packages.config
38 |
39 |
40 |
41 |
42 | $(NuGetToolsPath)\NuGet.exe
43 | @(PackageSource)
44 |
45 | "$(NuGetExePath)"
46 | mono --runtime=v4.0.30319 $(NuGetExePath)
47 |
48 | $(TargetDir.Trim('\\'))
49 |
50 | -RequireConsent
51 | -NonInteractive
52 |
53 |
54 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir "$(SolutionDir) "
55 | $(NuGetCommand) pack "$(ProjectPath)" -Properties Configuration=$(Configuration) $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols
56 |
57 |
58 |
59 | RestorePackages;
60 | $(BuildDependsOn);
61 |
62 |
63 |
64 |
65 | $(BuildDependsOn);
66 | BuildPackage;
67 |
68 |
69 |
70 |
71 |
72 |
73 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
88 |
89 |
92 |
93 |
94 |
95 |
97 |
98 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/TeslaLib/Models/VehicleOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.Serialization;
5 | using System.Text;
6 |
7 | namespace TeslaLib.Models
8 | {
9 | public class VehicleOptions
10 | {
11 |
12 | public VehicleOptions()
13 | {
14 |
15 | }
16 |
17 | public VehicleOptions(string optionCodes)
18 | {
19 | ParseOptionCodes(optionCodes);
20 | }
21 |
22 | public RoofType RoofType { get; set; }
23 |
24 | public Region Region { get; set; }
25 |
26 | public int YearModel { get; set; }
27 |
28 | public TrimLevel TrimLevel { get; set; }
29 |
30 | public DriverSide DriverSide { get; set; }
31 |
32 | public bool IsPerformance { get; set; }
33 |
34 | public int BatterySize { get; set; }
35 |
36 | public TeslaColor Color { get; set; }
37 |
38 | public WheelType WheelType { get; set; }
39 |
40 | public InteriorDecor InteriorDecor { get; set; }
41 |
42 | public bool HasPowerLiftgate { get; set; }
43 |
44 | public bool HasNavigation { get; set; }
45 |
46 | public bool HasPremiumExteriorLighting { get; set; }
47 |
48 | public bool HasHomeLink { get; set; }
49 |
50 | public bool HasSatelliteRadio { get; set; }
51 |
52 | public bool HasPerformanceExterior { get; set; }
53 |
54 | public bool HasPerformancePowertrain { get; set; }
55 |
56 | public bool HasThirdRowSeating { get; set; }
57 |
58 | public bool HasAirSuspension { get; set; }
59 |
60 | public bool HasSuperCharging { get; set; }
61 |
62 | public bool HasTechPackage { get; set; }
63 |
64 | public bool HasAudioUpgrade { get; set; }
65 |
66 | public bool HasTwinChargers { get; set; }
67 |
68 | public bool HasHPWC { get; set; }
69 |
70 | public bool HasPaintArmor { get; set; }
71 |
72 | public bool HasParcelShelf { get; set; }
73 |
74 | // 02 = NEMA 14-50
75 | public int AdapterTypeOrdered { get; set; }
76 |
77 | public bool IsPerformancePlus { get; set; }
78 |
79 | public void ParseOptionCodes(string optionCodes)
80 | {
81 | // MS01,RENA,TM00,DRLH,PF00,BT85,PBCW,RFPO,WT19,IBMB,IDPB,TR00,SU01,SC01,TP01,AU01,CH00,HP00,PA00,PS00,AD02,X020,X025,X001,X003,X007,X011,X013
82 |
83 | List options = optionCodes.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
84 |
85 | foreach (string option in options)
86 | {
87 |
88 | switch (option)
89 | {
90 | case "X001":
91 | HasPowerLiftgate = true;
92 | break;
93 | case "X002":
94 | HasPowerLiftgate = false;
95 | break;
96 | case "X003":
97 | HasNavigation = true;
98 | break;
99 | case "X004":
100 | HasNavigation = false;
101 | break;
102 | case "X007":
103 | HasPremiumExteriorLighting = true;
104 | break;
105 | case "X008":
106 | HasPremiumExteriorLighting = false;
107 | break;
108 | case "X011":
109 | HasHomeLink = true;
110 | break;
111 | case "X012":
112 | HasHomeLink = false;
113 | break;
114 | case "X013":
115 | HasSatelliteRadio = true;
116 | break;
117 | case "X014":
118 | HasSatelliteRadio = false;
119 | break;
120 | case "X019":
121 | HasPerformanceExterior = true;
122 | break;
123 | case "X020":
124 | HasPerformanceExterior = false;
125 | break;
126 | case "X024":
127 | HasPerformancePowertrain = true;
128 | break;
129 | case "X025":
130 | HasPerformancePowertrain = false;
131 | break;
132 | }
133 |
134 | string value2 = option.Substring(2, 2);
135 |
136 | switch (option.Substring(0, 2))
137 | {
138 | case "MS":
139 | YearModel = int.Parse(value2);
140 | break;
141 | case "RE":
142 | Region = Extensions.ToEnum(value2);
143 | break;
144 | case "TM":
145 | TrimLevel = Extensions.ToEnum(value2);
146 | break;
147 | case "DR":
148 | DriverSide = Extensions.ToEnum(value2);
149 | break;
150 | case "PF":
151 | IsPerformance = int.Parse(value2) > 0;
152 | break;
153 | case "BT":
154 | BatterySize = int.Parse(value2);
155 | break;
156 | case "RF":
157 | if (value2 == "BC")
158 | {
159 | RoofType = Models.RoofType.COLORED;
160 | }
161 | else if (value2 == "PO")
162 | {
163 | RoofType = Models.RoofType.NONE;
164 | }
165 | else if (value2 == "BK")
166 | {
167 | RoofType = Models.RoofType.BLACK;
168 | }
169 | break;
170 | case "WT":
171 | if (value2 == "19")
172 | {
173 | WheelType = Models.WheelType.BASE_19;
174 | }
175 | else if (value2 == "21")
176 | {
177 | WheelType = Models.WheelType.SILVER_21;
178 | }
179 | else if (value2 == "SP")
180 | {
181 | WheelType = Models.WheelType.CHARCOAL_21;
182 | }
183 | else if (value2 == "SG")
184 | {
185 | WheelType = Models.WheelType.CHARCOAL_PERFORMANCE_21;
186 | }
187 | break;
188 | case "ID":
189 | InteriorDecor = Extensions.ToEnum(value2);
190 | break;
191 | case "TR":
192 | HasThirdRowSeating = int.Parse(value2) > 0;
193 | break;
194 | case "SU":
195 | HasAirSuspension = int.Parse(value2) > 0;
196 | break;
197 | case "SC":
198 | HasSuperCharging = int.Parse(value2) > 0;
199 | break;
200 | case "TP":
201 | HasTechPackage = int.Parse(value2) > 0;
202 | break;
203 | case "AU":
204 | HasAudioUpgrade = int.Parse(value2) > 0;
205 | break;
206 | case "CH":
207 | HasTwinChargers = int.Parse(value2) > 0;
208 | break;
209 | case "HP":
210 | HasHPWC = int.Parse(value2) > 0;
211 | break;
212 | case "PA":
213 | HasPaintArmor = int.Parse(value2) > 0;
214 | break;
215 | case "PS":
216 | HasParcelShelf = int.Parse(value2) > 0;
217 | break;
218 | case "AD":
219 | break;
220 | case "PX":
221 | IsPerformancePlus = int.Parse(value2) > 0;
222 | break;
223 | }
224 |
225 | string value3 = option.Substring(1,3);
226 | switch (option.Substring(0, 1))
227 | {
228 | case "P":
229 | Color = Extensions.ToEnum(value3);
230 | break;
231 | case "I":
232 | break;
233 | }
234 | }
235 | }
236 | }
237 |
238 | public enum Region
239 | {
240 | [EnumMember(Value = "NA")]
241 | USA,
242 |
243 | [EnumMember(Value = "NC")]
244 | CANADA
245 | }
246 |
247 | public enum TrimLevel
248 | {
249 | [EnumMember(Value = "00")]
250 | STANDARD,
251 |
252 | //[EnumMember(Value = "01")]
253 | //PERFORMANCE,
254 |
255 | [EnumMember(Value = "02")]
256 | SIGNATURE_PERFORMANCE
257 | }
258 |
259 | public enum TeslaColor
260 | {
261 | [EnumMember(Value = "BSB")]
262 | BLACK,
263 |
264 | [EnumMember(Value = "BCW")]
265 | WHITE,
266 |
267 | [EnumMember(Value = "MSS")]
268 | SILVER,
269 |
270 | [EnumMember(Value = "MTG")]
271 | METALLIC_DOLPHIN_GREY,
272 |
273 | [EnumMember(Value = "MAB")]
274 | METALLIC_BROWN,
275 |
276 | [EnumMember(Value = "MMB")]
277 | METALLIC_BLUE,
278 |
279 | [EnumMember(Value = "MSG")]
280 | METALLIC_GREEN,
281 |
282 | [EnumMember(Value = "PSW")]
283 | PEARL_WHITE,
284 |
285 | [EnumMember(Value = "PMR")]
286 | MULTICOAT_READ,
287 |
288 | [EnumMember(Value = "PSR")]
289 | SIGNATURE_RED,
290 | }
291 |
292 | public enum InteriorDecor
293 | {
294 | [EnumMember(Value = "CF")]
295 | CARBON_FIBER,
296 |
297 | [EnumMember(Value = "LW")]
298 | LACEWOOD,
299 |
300 | [EnumMember(Value = "OM")]
301 | OBECHE_WOOD_MATTE,
302 |
303 | [EnumMember(Value = "OG")]
304 | OBECHE_WOOD_GLOSS,
305 |
306 | [EnumMember(Value = "PB")]
307 | PIANO_BLACK,
308 | }
309 |
310 | public enum DriverSide
311 | {
312 |
313 | [EnumMember(Value = "LH")]
314 | LEFT_HAND_DRIVE,
315 |
316 | [EnumMember(Value = "RH")]
317 | RIGHT_HAND_DRIVE,
318 | }
319 | }
--------------------------------------------------------------------------------
/TeslaLib/TeslaVehicle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Runtime.Serialization;
4 | using Newtonsoft.Json;
5 | using Newtonsoft.Json.Converters;
6 | using Newtonsoft.Json.Linq;
7 | using Newtonsoft.Json.Serialization;
8 | using RestSharp;
9 | using TeslaLib.Converters;
10 | using TeslaLib.Models;
11 |
12 | namespace TeslaLib
13 | {
14 |
15 | public class TeslaVehicle
16 | {
17 |
18 | #region Properties
19 |
20 | [JsonProperty(PropertyName = "color")]
21 | public string Color { get; set; }
22 |
23 | [JsonProperty(PropertyName = "display_name")]
24 | public string DisplayName { get; set; }
25 |
26 | [JsonProperty(PropertyName = "id")]
27 | public long Id { get; set; }
28 |
29 | [JsonProperty(PropertyName = "option_codes")]
30 | [JsonConverter(typeof(VehicleOptionsConverter))]
31 | public VehicleOptions Options { get; set; }
32 |
33 | [JsonProperty(PropertyName = "user_id")]
34 | public int UserId { get; set; }
35 |
36 | [JsonProperty(PropertyName = "vehicle_id")]
37 | public int VehicleId { get; set; }
38 |
39 | [JsonProperty(PropertyName = "vin")]
40 | public string VIN { get; set; }
41 |
42 | [JsonProperty(PropertyName = "tokens")]
43 | public List Tokens { get; set; }
44 |
45 | [JsonProperty(PropertyName = "state")]
46 | [JsonConverter(typeof(StringEnumConverter))]
47 | public VehicleState State { get; set; }
48 |
49 | [JsonIgnore]
50 | public RestClient Client { get; set; }
51 |
52 | #endregion
53 |
54 | #region State and Settings
55 |
56 | public bool LoadMobileEnabledStatus()
57 | {
58 | var request = new RestRequest("vehicles/{id}/mobile_enabled");
59 | request.AddParameter("id", Id, ParameterType.UrlSegment);
60 |
61 | var response = Client.Get(request);
62 | var json = JObject.Parse(response.Content)["response"];
63 | var data = bool.Parse(json.ToString());
64 |
65 | return data;
66 | }
67 |
68 | public ChargeStateStatus LoadChargeStateStatus()
69 | {
70 | var request = new RestRequest("vehicles/{id}/data_request/charge_state");
71 | request.AddParameter("id", Id, ParameterType.UrlSegment);
72 |
73 | var response = Client.Get(request);
74 | var json = JObject.Parse(response.Content)["response"];
75 | var data = JsonConvert.DeserializeObject(json.ToString());
76 |
77 | return data;
78 | }
79 |
80 | public ClimateStateStatus LoadClimateStateStatus()
81 | {
82 | var request = new RestRequest("vehicles/{id}/data_request/climate_state");
83 | request.AddParameter("id", Id, ParameterType.UrlSegment);
84 |
85 | var response = Client.Get(request);
86 | var json = JObject.Parse(response.Content)["response"];
87 | var data = JsonConvert.DeserializeObject(json.ToString());
88 |
89 | return data;
90 | }
91 |
92 | public DriveStateStatus LoadDriveStateStatus()
93 | {
94 | var request = new RestRequest("vehicles/{id}/data_request/drive_state");
95 | request.AddParameter("id", Id, ParameterType.UrlSegment);
96 |
97 | var response = Client.Get(request);
98 | var json = JObject.Parse(response.Content)["response"];
99 | var data = JsonConvert.DeserializeObject(json.ToString());
100 |
101 | return data;
102 | }
103 |
104 | public GuiSettingsStatus LoadGuiStateStatus()
105 | {
106 | var request = new RestRequest("vehicles/{id}/data_request/gui_settings");
107 | request.AddParameter("id", Id, ParameterType.UrlSegment);
108 |
109 | var response = Client.Get(request);
110 | var json = JObject.Parse(response.Content)["response"];
111 | var data = JsonConvert.DeserializeObject(json.ToString());
112 |
113 | return data;
114 | }
115 |
116 | public VehicleStateStatus LoadVehicleStateStatus()
117 | {
118 | var request = new RestRequest("vehicles/{id}/data_request/vehicle_state");
119 | request.AddParameter("id", Id, ParameterType.UrlSegment);
120 |
121 | var response = Client.Get(request);
122 | var json = JObject.Parse(response.Content)["response"];
123 | var data = JsonConvert.DeserializeObject(json.ToString());
124 |
125 | return data;
126 | }
127 |
128 | #endregion
129 |
130 | #region Commands
131 |
132 | public VehicleState WakeUp()
133 | {
134 | var request = new RestRequest("vehicles/{id}/wake_up");
135 | request.AddParameter("id", Id, ParameterType.UrlSegment);
136 |
137 | var response = Client.Post(request);
138 | var json = JObject.Parse(response.Content)["response"];
139 | var data = JsonConvert.DeserializeObject(json.ToString());
140 | if (data == null)
141 | return VehicleState.Asleep;
142 | return data.State;
143 | }
144 |
145 | public ResultStatus OpenChargePortDoor()
146 | {
147 | var request = new RestRequest("vehicles/{id}/command/charge_port_door_open");
148 | request.AddParameter("id", Id, ParameterType.UrlSegment);
149 |
150 | var response = Client.Post(request);
151 | var json = JObject.Parse(response.Content)["response"];
152 | var data = JsonConvert.DeserializeObject(json.ToString());
153 |
154 | return data;
155 | }
156 |
157 | public ResultStatus SetChargeLimitToStandard()
158 | {
159 | var request = new RestRequest("vehicles/{id}/command/charge_standard");
160 | request.AddParameter("id", Id, ParameterType.UrlSegment);
161 | var response = Client.Post(request);
162 | var json = JObject.Parse(response.Content)["response"];
163 | var data = JsonConvert.DeserializeObject(json.ToString());
164 |
165 | return data;
166 | }
167 |
168 | // Don't use this very often as it damages the battery.
169 | public ResultStatus SetChargeLimitToMaxRange()
170 | {
171 | var request = new RestRequest("vehicles/{id}/command/charge_max_range");
172 | request.AddParameter("id", Id, ParameterType.UrlSegment);
173 | var response = Client.Post(request);
174 | var json = JObject.Parse(response.Content)["response"];
175 | var data = JsonConvert.DeserializeObject(json.ToString());
176 |
177 | return data;
178 | }
179 |
180 | public ResultStatus SetChargeLimit(int stateOfChargePercent)
181 | {
182 | var request = new RestRequest("vehicles/{id}/command/set_charge_limit", Method.POST);
183 | request.AddParameter("id", Id, ParameterType.UrlSegment);
184 | /* This throws an exception - RestSharp serializes this out incorrectly, perhaps?
185 | request.AddBody(new
186 | {
187 | state = "set",
188 | percent = socPercent
189 | });
190 | */
191 | request.AddParameter("state", "set");
192 | request.AddParameter("percent", stateOfChargePercent.ToString());
193 |
194 | var response = Client.Post(request);
195 | var json = JObject.Parse(response.Content)["response"];
196 | var data = JsonConvert.DeserializeObject(json.ToString());
197 |
198 | return data;
199 | }
200 |
201 | public ResultStatus StartCharge()
202 | {
203 | var request = new RestRequest("vehicles/{id}/command/charge_start");
204 | request.AddParameter("id", Id, ParameterType.UrlSegment);
205 |
206 | var response = Client.Post(request);
207 | var json = JObject.Parse(response.Content)["response"];
208 | var data = JsonConvert.DeserializeObject(json.ToString());
209 |
210 | return data;
211 | }
212 |
213 | public ResultStatus StopCharge()
214 | {
215 | var request = new RestRequest("vehicles/{id}/command/charge_stop");
216 | request.AddParameter("id", Id, ParameterType.UrlSegment);
217 |
218 | var response = Client.Post(request);
219 | var json = JObject.Parse(response.Content)["response"];
220 | var data = JsonConvert.DeserializeObject(json.ToString());
221 |
222 | return data;
223 | }
224 |
225 | public ResultStatus FlashLights()
226 | {
227 | var request = new RestRequest("vehicles/{id}/command/flash_lights");
228 | request.AddParameter("id", Id, ParameterType.UrlSegment);
229 |
230 | var response = Client.Post(request);
231 | var json = JObject.Parse(response.Content)["response"];
232 | var data = JsonConvert.DeserializeObject(json.ToString());
233 |
234 | return data;
235 | }
236 |
237 | public ResultStatus HonkHorn()
238 | {
239 | var request = new RestRequest("vehicles/{id}/command/honk_horn");
240 | request.AddParameter("id", Id, ParameterType.UrlSegment);
241 |
242 | var response = Client.Post(request);
243 | var json = JObject.Parse(response.Content)["response"];
244 | var data = JsonConvert.DeserializeObject(json.ToString());
245 |
246 | return data;
247 | }
248 |
249 | public ResultStatus UnlockDoors()
250 | {
251 | var request = new RestRequest("vehicles/{id}/command/door_unlock");
252 | request.AddParameter("id", Id, ParameterType.UrlSegment);
253 |
254 | var response = Client.Post(request);
255 | var json = JObject.Parse(response.Content)["response"];
256 | var data = JsonConvert.DeserializeObject(json.ToString());
257 |
258 | return data;
259 | }
260 |
261 | public ResultStatus LockDoors()
262 | {
263 | var request = new RestRequest("vehicles/{id}/command/door_lock");
264 | request.AddParameter("id", Id, ParameterType.UrlSegment);
265 |
266 | var response = Client.Post(request);
267 | var json = JObject.Parse(response.Content)["response"];
268 | var data = JsonConvert.DeserializeObject(json.ToString());
269 |
270 | return data;
271 | }
272 |
273 | public ResultStatus SetTemperatureSettings(int driverTemp = 17, int passengerTemp = 17)
274 | {
275 |
276 | int TEMP_MAX = 32;
277 | int TEMP_MIN = 17;
278 |
279 | driverTemp = Math.Max(driverTemp, TEMP_MIN);
280 | driverTemp = Math.Min(driverTemp, TEMP_MAX);
281 |
282 | passengerTemp = Math.Max(passengerTemp, TEMP_MIN);
283 | passengerTemp = Math.Min(passengerTemp, TEMP_MAX);
284 |
285 |
286 | var request = new RestRequest("vehicles/{id}/command/set_temps?driver_temp={driver_degC}&passenger_temp={pass_degC}");
287 | request.AddParameter("id", Id, ParameterType.UrlSegment);
288 | request.AddParameter("driver_degC", driverTemp, ParameterType.UrlSegment);
289 | request.AddParameter("pass_degC", passengerTemp, ParameterType.UrlSegment);
290 |
291 | var response = Client.Post(request);
292 | var json = JObject.Parse(response.Content)["response"];
293 | var data = JsonConvert.DeserializeObject(json.ToString());
294 |
295 | return data;
296 | }
297 |
298 | public ResultStatus StartHVAC()
299 | {
300 | var request = new RestRequest("vehicles/{id}/command/auto_conditioning_start");
301 | request.AddParameter("id", Id, ParameterType.UrlSegment);
302 |
303 | var response = Client.Post(request);
304 | var json = JObject.Parse(response.Content)["response"];
305 | var data = JsonConvert.DeserializeObject(json.ToString());
306 |
307 | return data;
308 | }
309 |
310 | public ResultStatus StopHVAC()
311 | {
312 | var request = new RestRequest("vehicles/{id}/command/auto_conditioning_stop");
313 | request.AddParameter("id", Id, ParameterType.UrlSegment);
314 |
315 | var response = Client.Post(request);
316 | var json = JObject.Parse(response.Content)["response"];
317 | var data = JsonConvert.DeserializeObject(json.ToString());
318 |
319 | return data;
320 | }
321 |
322 | public ResultStatus SetPanoramicRoofLevel(PanoramicRoofState roofState, int percentOpen = 0)
323 | {
324 | var request = new RestRequest("vehicles/{id}/command/sun_roof_control?state={state}&percent={percent}");
325 | request.AddParameter("id", Id, ParameterType.UrlSegment);
326 | request.AddParameter("state", roofState.GetEnumValue(), ParameterType.UrlSegment);
327 |
328 | if (roofState == PanoramicRoofState.MOVE)
329 | {
330 | request.AddParameter("percent", percentOpen, ParameterType.UrlSegment);
331 | }
332 |
333 | var response = Client.Post(request);
334 | var json = JObject.Parse(response.Content)["response"];
335 | var data = JsonConvert.DeserializeObject(json.ToString());
336 |
337 | return data;
338 | }
339 |
340 | public ResultStatus RemoteStart(string password)
341 | {
342 | var request = new RestRequest("vehicles/{id}/command/remote_start_drive?password={password}");
343 | request.AddParameter("id", Id, ParameterType.UrlSegment);
344 | request.AddParameter("password", password, ParameterType.UrlSegment);
345 |
346 | var response = Client.Post(request);
347 | var json = JObject.Parse(response.Content)["response"];
348 | var data = JsonConvert.DeserializeObject(json.ToString());
349 |
350 | return data;
351 | }
352 |
353 | public ResultStatus OpenFrontTrunk()
354 | {
355 | return OpenTrunk("front");
356 | }
357 |
358 | public ResultStatus OpenRearTrunk()
359 | {
360 | return OpenTrunk("rear");
361 | }
362 |
363 | public ResultStatus OpenTrunk(string trunkType)
364 | {
365 | var request = new RestRequest("vehicles/{id}/command/trunk_open");
366 | request.AddParameter("id", Id, ParameterType.UrlSegment);
367 | request.AddBody(new
368 | {
369 | which_trunk = trunkType
370 | });
371 | var response = Client.Post(request);
372 | var json = JObject.Parse(response.Content)["response"];
373 | var data = JsonConvert.DeserializeObject(json.ToString());
374 |
375 | return data;
376 | }
377 |
378 | #endregion
379 |
380 |
381 | public string LoadStreamingValues(string values)
382 | {
383 | return null;
384 |
385 | //values = "speed,odometer,soc,elevation,est_heading,est_lat,est_lng,power,shift_state,range,est_range";
386 | //string response = webClient.DownloadString(Path.Combine(TESLA_SERVER, string.Format("stream/{0}/?values={1}", vehicle.VehicleId, values)));
387 | //return response;
388 | }
389 |
390 | }
391 |
392 | public enum VehicleState
393 | {
394 | [EnumMember(Value = "Online")]
395 | Online,
396 |
397 | [EnumMember(Value = "Asleep")]
398 | Asleep,
399 |
400 | [EnumMember(Value = "Offline")]
401 | Offline,
402 |
403 | [EnumMember(Value = "Waking")]
404 | Waking
405 | }
406 | }
--------------------------------------------------------------------------------