wip: A tool to scrape the fleet api website
This commit is contained in:
parent
65f13033a6
commit
503effc7ef
2
scrape_fleet_api/.gitignore
vendored
Normal file
2
scrape_fleet_api/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/target
|
||||||
|
/Cargo.lock
|
1755
scrape_fleet_api/Cargo.lock
generated
Normal file
1755
scrape_fleet_api/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
12
scrape_fleet_api/Cargo.toml
Normal file
12
scrape_fleet_api/Cargo.toml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
[package]
|
||||||
|
name = "scrape_fleet_api"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
reqwest = "0.11.22"
|
||||||
|
tokio = { version = "1.33.0", features = ["full"] }
|
||||||
|
clap = { version = "4.4.6", features = ["derive"] }
|
||||||
|
tracing-subscriber = "0.3.17"
|
||||||
|
scraper = "0.17.1"
|
||||||
|
strum = { version = "0.25.0", features = ["derive"] }
|
9566
scrape_fleet_api/fleet.html
Normal file
9566
scrape_fleet_api/fleet.html
Normal file
File diff suppressed because it is too large
Load diff
425
scrape_fleet_api/src/main.rs
Normal file
425
scrape_fleet_api/src/main.rs
Normal file
|
@ -0,0 +1,425 @@
|
||||||
|
use clap::{Command, Parser};
|
||||||
|
use scraper::{Element, ElementRef, Html, Selector};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[clap(author, version)]
|
||||||
|
struct Cli {
|
||||||
|
/// Only use the cached html to avoid making a request.
|
||||||
|
#[clap(short, long)]
|
||||||
|
cache: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
let args = Cli::parse();
|
||||||
|
|
||||||
|
let html = get_and_save_html(&args).await;
|
||||||
|
|
||||||
|
let fleet_api = parse(&html);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_and_save_html(args: &Cli) -> String {
|
||||||
|
// Write to where this project root is, not in the parent project.
|
||||||
|
let mut path = PathBuf::new();
|
||||||
|
path.push(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
path.push("fleet.html");
|
||||||
|
|
||||||
|
if args.cache {
|
||||||
|
return std::fs::read_to_string(path).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = reqwest::get("https://developer.tesla.com/docs/fleet-api")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let html = response.text().await.unwrap();
|
||||||
|
|
||||||
|
std::fs::write(path, &html).unwrap();
|
||||||
|
|
||||||
|
html
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FleetApiSpec {
|
||||||
|
calls: HashMap<String, Call>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// e.g. serialize to similar: vehicle-endpoints
|
||||||
|
#[derive(Debug, strum::EnumString)]
|
||||||
|
#[strum(serialize_all = "kebab-case")]
|
||||||
|
enum Category {
|
||||||
|
ChargingEndpoints,
|
||||||
|
PartnerEndpoints,
|
||||||
|
UserEndpoints,
|
||||||
|
VehicleCommands,
|
||||||
|
VehicleEndpoints,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Profile Information user_data Contact information, home address, profile picture, and referral information
|
||||||
|
Vehicle Information vehicle_device_data Vehicle live data, location, eligible upgrades, nearby superchargers, ownership, and service scheduling data
|
||||||
|
Vehicle Commands vehicle_cmds Commands like add/remove driver, access Live Camera, unlock, wake up, remote start, and schedule software updates
|
||||||
|
Vehicle Charging Management vehicle_charging_cmds Vehicle charging history, billed amount, charging location, commands to schedule, and start/stop charging
|
||||||
|
Energy Product Information energy_device_data Energy flow history, saving forecast, tariff rates, grid import, calendar, site status, time of use, and ownership
|
||||||
|
Energy Product Commands energy_cmds Commands like update storm mode
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[derive(Debug, strum::EnumString)]
|
||||||
|
#[strum(serialize_all = "snake_case")]
|
||||||
|
enum Scope {
|
||||||
|
/// Profile Information
|
||||||
|
///
|
||||||
|
/// Contact information, home address, profile picture, and referral information.
|
||||||
|
UserData,
|
||||||
|
|
||||||
|
/// Vehicle Information
|
||||||
|
///
|
||||||
|
/// Vehicle live data, location, eligible upgrades, nearby superchargers, ownership, and service scheduling data.
|
||||||
|
VehicleDeviceData,
|
||||||
|
|
||||||
|
/// Vehicle Commands
|
||||||
|
///
|
||||||
|
/// Commands like add/remove driver, access Live Camera, unlock, wake up, remote start, and schedule software updates.
|
||||||
|
VehicleCmds,
|
||||||
|
|
||||||
|
/// Vehicle Charging Management
|
||||||
|
///
|
||||||
|
/// Vehicle charging history, billed amount, charging location, commands to schedule, and start/stop charging.
|
||||||
|
VehicleChargingCmds,
|
||||||
|
|
||||||
|
/// Energy Product Information
|
||||||
|
///
|
||||||
|
/// Energy flow history, saving forecast, tariff rates, grid import, calendar, site status, time of use, and ownership.
|
||||||
|
EnergyDeviceData,
|
||||||
|
|
||||||
|
/// Energy Product Commands
|
||||||
|
///
|
||||||
|
/// Commands like update storm mode.
|
||||||
|
EnergyCmds,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Name In Type Required Description
|
||||||
|
vin query string No VIN
|
||||||
|
startTime query string No StartTime
|
||||||
|
endTime query string No EndTime
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum InRequestData {
|
||||||
|
Query,
|
||||||
|
Body,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Parameter {
|
||||||
|
name: String,
|
||||||
|
request: InRequestData,
|
||||||
|
var_type: String,
|
||||||
|
required: bool,
|
||||||
|
description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Call {
|
||||||
|
name: String,
|
||||||
|
method: reqwest::Method,
|
||||||
|
url_definition: String,
|
||||||
|
description: String,
|
||||||
|
category: Category,
|
||||||
|
scopes: Vec<Scope>,
|
||||||
|
parameters: Vec<Parameter>,
|
||||||
|
request_example: String,
|
||||||
|
response_example: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Example HTML docs for two calls:
|
||||||
|
|
||||||
|
|
||||||
|
<h1 id='vehicle-commands'>Vehicle Commands</h1><h2 id='actuate_trunk'>actuate_trunk</h2>
|
||||||
|
<p><span class="endpoint"><code>POST /api/1/vehicles/{id}/command/actuate_trunk</code></span></p>
|
||||||
|
|
||||||
|
<p>scopes: <em>vehicle_cmds</em></p>
|
||||||
|
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">--header</span> <span class="s1">'Content-Type: application/json'</span> <span class="se">\</span>
|
||||||
|
<span class="nt">--header</span> <span class="s2">"Authorization: Bearer </span><span class="nv">$TESLA_API_TOKEN</span><span class="s2">"</span> <span class="se">\</span>
|
||||||
|
<span class="nt">--data</span> <span class="s1">'{"which_trunk":"string"}'</span> <span class="se">\</span>
|
||||||
|
<span class="s1">'https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/actuate_trunk'</span>
|
||||||
|
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="kd">const</span> <span class="nx">myHeaders</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Headers</span><span class="p">();</span>
|
||||||
|
<span class="nx">myHeaders</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="dl">"</span><span class="s2">Content-Type</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">application/json</span><span class="dl">"</span><span class="p">);</span>
|
||||||
|
<span class="nx">myHeaders</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="dl">"</span><span class="s2">Authorization</span><span class="dl">"</span><span class="p">,</span> <span class="s2">`Bearer </span><span class="p">${</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">TESLA_API_TOKEN</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
|
||||||
|
|
||||||
|
<span class="kd">const</span> <span class="nx">body</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span>
|
||||||
|
<span class="dl">"</span><span class="s2">which_trunk</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">string</span><span class="dl">"</span>
|
||||||
|
<span class="p">});</span>
|
||||||
|
|
||||||
|
<span class="kd">const</span> <span class="nx">requestOptions</span> <span class="o">=</span> <span class="p">{</span>
|
||||||
|
<span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">POST</span><span class="dl">'</span><span class="p">,</span>
|
||||||
|
<span class="na">headers</span><span class="p">:</span> <span class="nx">myHeaders</span><span class="p">,</span>
|
||||||
|
<span class="nx">body</span><span class="p">,</span>
|
||||||
|
<span class="na">redirect</span><span class="p">:</span> <span class="dl">'</span><span class="s1">follow</span><span class="dl">'</span>
|
||||||
|
<span class="p">};</span>
|
||||||
|
|
||||||
|
<span class="nx">fetch</span><span class="p">(</span><span class="dl">"</span><span class="s2">https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/actuate_trunk</span><span class="dl">"</span><span class="p">,</span> <span class="nx">requestOptions</span><span class="p">)</span>
|
||||||
|
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span> <span class="o">=></span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">())</span>
|
||||||
|
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">result</span> <span class="o">=></span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">result</span><span class="p">))</span>
|
||||||
|
<span class="p">.</span><span class="k">catch</span><span class="p">(</span><span class="nx">error</span> <span class="o">=></span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">error</span><span class="dl">'</span><span class="p">,</span> <span class="nx">error</span><span class="p">));</span>
|
||||||
|
</code></pre></div><div class="highlight"><pre class="highlight ruby tab-ruby"><code><span class="nb">require</span> <span class="s2">"uri"</span>
|
||||||
|
<span class="nb">require</span> <span class="s2">"json"</span>
|
||||||
|
<span class="nb">require</span> <span class="s2">"net/http"</span>
|
||||||
|
|
||||||
|
<span class="n">url</span> <span class="o">=</span> <span class="no">URI</span><span class="p">(</span><span class="s2">"https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/actuate_trunk"</span><span class="p">)</span>
|
||||||
|
|
||||||
|
<span class="n">https</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">url</span><span class="p">.</span><span class="nf">host</span><span class="p">,</span> <span class="n">url</span><span class="p">.</span><span class="nf">port</span><span class="p">)</span>
|
||||||
|
<span class="n">https</span><span class="p">.</span><span class="nf">use_ssl</span> <span class="o">=</span> <span class="kp">true</span>
|
||||||
|
|
||||||
|
<span class="n">request</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">::</span><span class="no">Post</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
|
||||||
|
<span class="n">request</span><span class="p">[</span><span class="s2">"Content-Type"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"application/json"</span>
|
||||||
|
<span class="n">request</span><span class="p">[</span><span class="s2">"Authorization"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"Bearer ENV_TESLA_API_TOKEN"</span>
|
||||||
|
<span class="n">request</span><span class="p">.</span><span class="nf">body</span> <span class="o">=</span> <span class="no">JSON</span><span class="p">.</span><span class="nf">dump</span><span class="p">({</span>
|
||||||
|
<span class="s2">"which_trunk"</span><span class="p">:</span> <span class="s2">"string"</span>
|
||||||
|
<span class="p">})</span>
|
||||||
|
|
||||||
|
<span class="n">response</span> <span class="o">=</span> <span class="n">https</span><span class="p">.</span><span class="nf">request</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
|
||||||
|
<span class="nb">puts</span> <span class="n">response</span><span class="p">.</span><span class="nf">read_body</span>
|
||||||
|
|
||||||
|
</code></pre></div><div class="highlight"><pre class="highlight python tab-python"><code><span class="kn">import</span> <span class="nn">os</span>
|
||||||
|
<span class="kn">import</span> <span class="nn">http.client</span>
|
||||||
|
<span class="kn">import</span> <span class="nn">json</span>
|
||||||
|
|
||||||
|
<span class="n">conn</span> <span class="o">=</span> <span class="n">http</span><span class="p">.</span><span class="n">client</span><span class="p">.</span><span class="n">HTTPSConnection</span><span class="p">(</span><span class="s">"fleet-api.prd.na.vn.cloud.tesla.com"</span><span class="p">)</span>
|
||||||
|
<span class="n">payload</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">dumps</span><span class="p">({</span>
|
||||||
|
<span class="s">"which_trunk"</span><span class="p">:</span> <span class="s">"string"</span>
|
||||||
|
<span class="p">})</span>
|
||||||
|
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
|
||||||
|
<span class="s">'Content-Type'</span><span class="p">:</span> <span class="s">'application/json'</span><span class="p">,</span>
|
||||||
|
<span class="s">'Authorization'</span><span class="p">:</span> <span class="s">'Bearer ENV_TESLA_API_TOKEN'</span>
|
||||||
|
<span class="p">}</span>
|
||||||
|
<span class="n">conn</span><span class="p">.</span><span class="n">request</span><span class="p">(</span><span class="s">"POST"</span><span class="p">,</span> <span class="s">"/api/1/vehicles/{id}/command/actuate_trunk"</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">headers</span><span class="p">)</span>
|
||||||
|
<span class="n">res</span> <span class="o">=</span> <span class="n">conn</span><span class="p">.</span><span class="n">getresponse</span><span class="p">()</span>
|
||||||
|
<span class="n">data</span> <span class="o">=</span> <span class="n">res</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
|
||||||
|
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">decode</span><span class="p">(</span><span class="s">"utf-8"</span><span class="p">))</span>
|
||||||
|
</code></pre></div>
|
||||||
|
<p>Controls the front (which_trunk: "front") or rear (which_trunk: "rear") trunk.</p>
|
||||||
|
<h3 id='parameters-10'>Parameters</h3>
|
||||||
|
<table><thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>In</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Required</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead><tbody>
|
||||||
|
<tr>
|
||||||
|
<td>id</td>
|
||||||
|
<td>path</td>
|
||||||
|
<td>integer</td>
|
||||||
|
<td>Yes</td>
|
||||||
|
<td>vehicle id</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>which_trunk</td>
|
||||||
|
<td>body</td>
|
||||||
|
<td>string</td>
|
||||||
|
<td>Yes</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<div class="highlight"><pre class="highlight json tab-json"><code><details><summary> Click to view successful response</summary><span class="p">{</span><span class="w">
|
||||||
|
</span><span class="nl">"result"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
||||||
|
</span><span class="nl">"reason"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
|
||||||
|
</span><span class="p">}</span><span class="w">
|
||||||
|
</span></details></code></pre></div>
|
||||||
|
|
||||||
|
<h2 id='adjust_volume'>adjust_volume</h2>
|
||||||
|
<p><span class="endpoint"><code>POST /api/1/vehicles/{id}/command/adjust_volume</code></span></p>
|
||||||
|
|
||||||
|
<p>scopes: <em>vehicle_cmds</em></p>
|
||||||
|
<div class="highlight"><pre class="highlight shell tab-shell"><code>curl <span class="nt">--header</span> <span class="s1">'Content-Type: application/json'</span> <span class="se">\</span>
|
||||||
|
<span class="nt">--header</span> <span class="s2">"Authorization: Bearer </span><span class="nv">$TESLA_API_TOKEN</span><span class="s2">"</span> <span class="se">\</span>
|
||||||
|
<span class="nt">--data</span> <span class="s1">'{"volume":"integer"}'</span> <span class="se">\</span>
|
||||||
|
<span class="s1">'https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/adjust_volume'</span>
|
||||||
|
</code></pre></div><div class="highlight"><pre class="highlight javascript tab-javascript"><code><span class="kd">const</span> <span class="nx">myHeaders</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Headers</span><span class="p">();</span>
|
||||||
|
<span class="nx">myHeaders</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="dl">"</span><span class="s2">Content-Type</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">application/json</span><span class="dl">"</span><span class="p">);</span>
|
||||||
|
<span class="nx">myHeaders</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="dl">"</span><span class="s2">Authorization</span><span class="dl">"</span><span class="p">,</span> <span class="s2">`Bearer </span><span class="p">${</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">TESLA_API_TOKEN</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
|
||||||
|
|
||||||
|
<span class="kd">const</span> <span class="nx">body</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span>
|
||||||
|
<span class="dl">"</span><span class="s2">volume</span><span class="dl">"</span><span class="p">:</span> <span class="dl">"</span><span class="s2">integer</span><span class="dl">"</span>
|
||||||
|
<span class="p">});</span>
|
||||||
|
|
||||||
|
<span class="kd">const</span> <span class="nx">requestOptions</span> <span class="o">=</span> <span class="p">{</span>
|
||||||
|
<span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">POST</span><span class="dl">'</span><span class="p">,</span>
|
||||||
|
<span class="na">headers</span><span class="p">:</span> <span class="nx">myHeaders</span><span class="p">,</span>
|
||||||
|
<span class="nx">body</span><span class="p">,</span>
|
||||||
|
<span class="na">redirect</span><span class="p">:</span> <span class="dl">'</span><span class="s1">follow</span><span class="dl">'</span>
|
||||||
|
<span class="p">};</span>
|
||||||
|
|
||||||
|
<span class="nx">fetch</span><span class="p">(</span><span class="dl">"</span><span class="s2">https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/adjust_volume</span><span class="dl">"</span><span class="p">,</span> <span class="nx">requestOptions</span><span class="p">)</span>
|
||||||
|
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">response</span> <span class="o">=></span> <span class="nx">response</span><span class="p">.</span><span class="nx">json</span><span class="p">())</span>
|
||||||
|
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">result</span> <span class="o">=></span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">result</span><span class="p">))</span>
|
||||||
|
<span class="p">.</span><span class="k">catch</span><span class="p">(</span><span class="nx">error</span> <span class="o">=></span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">error</span><span class="dl">'</span><span class="p">,</span> <span class="nx">error</span><span class="p">));</span>
|
||||||
|
</code></pre></div><div class="highlight"><pre class="highlight ruby tab-ruby"><code><span class="nb">require</span> <span class="s2">"uri"</span>
|
||||||
|
<span class="nb">require</span> <span class="s2">"json"</span>
|
||||||
|
<span class="nb">require</span> <span class="s2">"net/http"</span>
|
||||||
|
|
||||||
|
<span class="n">url</span> <span class="o">=</span> <span class="no">URI</span><span class="p">(</span><span class="s2">"https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/adjust_volume"</span><span class="p">)</span>
|
||||||
|
|
||||||
|
<span class="n">https</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">url</span><span class="p">.</span><span class="nf">host</span><span class="p">,</span> <span class="n">url</span><span class="p">.</span><span class="nf">port</span><span class="p">)</span>
|
||||||
|
<span class="n">https</span><span class="p">.</span><span class="nf">use_ssl</span> <span class="o">=</span> <span class="kp">true</span>
|
||||||
|
|
||||||
|
<span class="n">request</span> <span class="o">=</span> <span class="no">Net</span><span class="o">::</span><span class="no">HTTP</span><span class="o">::</span><span class="no">Post</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
|
||||||
|
<span class="n">request</span><span class="p">[</span><span class="s2">"Content-Type"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"application/json"</span>
|
||||||
|
<span class="n">request</span><span class="p">[</span><span class="s2">"Authorization"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"Bearer ENV_TESLA_API_TOKEN"</span>
|
||||||
|
<span class="n">request</span><span class="p">.</span><span class="nf">body</span> <span class="o">=</span> <span class="no">JSON</span><span class="p">.</span><span class="nf">dump</span><span class="p">({</span>
|
||||||
|
<span class="s2">"volume"</span><span class="p">:</span> <span class="s2">"integer"</span>
|
||||||
|
<span class="p">})</span>
|
||||||
|
|
||||||
|
<span class="n">response</span> <span class="o">=</span> <span class="n">https</span><span class="p">.</span><span class="nf">request</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
|
||||||
|
<span class="nb">puts</span> <span class="n">response</span><span class="p">.</span><span class="nf">read_body</span>
|
||||||
|
|
||||||
|
</code></pre></div><div class="highlight"><pre class="highlight python tab-python"><code><span class="kn">import</span> <span class="nn">os</span>
|
||||||
|
<span class="kn">import</span> <span class="nn">http.client</span>
|
||||||
|
<span class="kn">import</span> <span class="nn">json</span>
|
||||||
|
|
||||||
|
<span class="n">conn</span> <span class="o">=</span> <span class="n">http</span><span class="p">.</span><span class="n">client</span><span class="p">.</span><span class="n">HTTPSConnection</span><span class="p">(</span><span class="s">"fleet-api.prd.na.vn.cloud.tesla.com"</span><span class="p">)</span>
|
||||||
|
<span class="n">payload</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="n">dumps</span><span class="p">({</span>
|
||||||
|
<span class="s">"volume"</span><span class="p">:</span> <span class="s">"integer"</span>
|
||||||
|
<span class="p">})</span>
|
||||||
|
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
|
||||||
|
<span class="s">'Content-Type'</span><span class="p">:</span> <span class="s">'application/json'</span><span class="p">,</span>
|
||||||
|
<span class="s">'Authorization'</span><span class="p">:</span> <span class="s">'Bearer ENV_TESLA_API_TOKEN'</span>
|
||||||
|
<span class="p">}</span>
|
||||||
|
<span class="n">conn</span><span class="p">.</span><span class="n">request</span><span class="p">(</span><span class="s">"POST"</span><span class="p">,</span> <span class="s">"/api/1/vehicles/{id}/command/adjust_volume"</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">headers</span><span class="p">)</span>
|
||||||
|
<span class="n">res</span> <span class="o">=</span> <span class="n">conn</span><span class="p">.</span><span class="n">getresponse</span><span class="p">()</span>
|
||||||
|
<span class="n">data</span> <span class="o">=</span> <span class="n">res</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>
|
||||||
|
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">decode</span><span class="p">(</span><span class="s">"utf-8"</span><span class="p">))</span>
|
||||||
|
</code></pre></div>
|
||||||
|
<p>Adjusts vehicle media playback volume.</p>
|
||||||
|
<h3 id='parameters-11'>Parameters</h3>
|
||||||
|
<table><thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>In</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Required</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead><tbody>
|
||||||
|
<tr>
|
||||||
|
<td>id</td>
|
||||||
|
<td>path</td>
|
||||||
|
<td>integer</td>
|
||||||
|
<td>Yes</td>
|
||||||
|
<td>vehicle id</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>volume</td>
|
||||||
|
<td>body</td>
|
||||||
|
<td>integer</td>
|
||||||
|
<td>Yes</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
<div class="highlight"><pre class="highlight json tab-json"><code><details><summary> Click to view successful response</summary><span class="p">{</span><span class="w">
|
||||||
|
</span><span class="nl">"result"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
|
||||||
|
</span><span class="nl">"reason"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
|
||||||
|
</span><span class="p">}</span><span class="w">
|
||||||
|
</span></details></code></pre></div>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn parse(html: &str) -> FleetApiSpec {
|
||||||
|
let document = Html::parse_document(html);
|
||||||
|
let content_selector = selector(".content h1");
|
||||||
|
let mut element = document.select(&content_selector).next().unwrap();
|
||||||
|
let mut category = None;
|
||||||
|
|
||||||
|
// Iterate over all the elements in the content section until we see a h1 or h2.
|
||||||
|
loop {
|
||||||
|
match element.value().name() {
|
||||||
|
"h1" => {
|
||||||
|
let category_name = element.value().id().unwrap();
|
||||||
|
category = Category::from_str(&category_name).ok();
|
||||||
|
}
|
||||||
|
"h2" => {
|
||||||
|
if category.is_some() {
|
||||||
|
let name = element.inner_html();
|
||||||
|
println!("{category:?} {name:?}");
|
||||||
|
// let call = parse_call(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(next_element) = element.next_sibling_element() else {
|
||||||
|
println!("exiting...");
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
element = next_element;
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return None if this is not an endpoint.
|
||||||
|
///
|
||||||
|
/// Will panic if it looks like an endpoint and has trouble parsing.
|
||||||
|
fn parse_call(element: ElementRef) -> Option<Call> {
|
||||||
|
let name = element.value().id().unwrap();
|
||||||
|
|
||||||
|
// <p><span class="endpoint"><code>POST /api/1/vehicles/{id}/command/auto_conditioning_start</code></span></p>
|
||||||
|
// This section determines if this is an endpoint or not.
|
||||||
|
let (fragment, element) = next(element);
|
||||||
|
let url = fragment.select(&selector("code")).next()?.inner_html();
|
||||||
|
if !url.starts_with("GET ") && !url.starts_with("POST ") {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (method, url) = url.split_once(' ').unwrap();
|
||||||
|
println!("{} {}", method, url);
|
||||||
|
|
||||||
|
// <p>scopes: <em>vehicle_cmds</em></p>
|
||||||
|
let (fragment, element) = next(element);
|
||||||
|
let scopes = fragment
|
||||||
|
.select(&selector("em"))
|
||||||
|
.map(|e| e.inner_html())
|
||||||
|
.map(|e| Scope::from_str(&e))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// 4 <div class="highlight"> nodes containing example requests in different languages.
|
||||||
|
// TODO: Skip for now
|
||||||
|
let mut count = 0;
|
||||||
|
let mut element = element;
|
||||||
|
loop {
|
||||||
|
let (fragment, new_element) = next(element);
|
||||||
|
element = new_element;
|
||||||
|
if fragment
|
||||||
|
.select(&selector(r#"div[class="highlight"]"#))
|
||||||
|
.next()
|
||||||
|
.is_none()
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
count += 1;
|
||||||
|
if count == 10 {
|
||||||
|
panic!("Too many examples");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if count == 0 && name != "api-status" {
|
||||||
|
panic!("No examples for {}", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next(element: ElementRef) -> (Html, ElementRef) {
|
||||||
|
let element = element.next_sibling_element().unwrap();
|
||||||
|
let html = Html::parse_fragment(&element.html());
|
||||||
|
(html, element)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn selector(s: &str) -> Selector {
|
||||||
|
Selector::parse(s).unwrap()
|
||||||
|
}
|
Loading…
Reference in a new issue