nicer webapp
This commit is contained in:
parent
f1807b2417
commit
502816dbfe
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -2567,7 +2567,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tesla-charge-controller"
|
name = "tesla-charge-controller"
|
||||||
version = "1.0.8"
|
version = "1.0.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "tesla-charge-controller"
|
name = "tesla-charge-controller"
|
||||||
version = "1.0.8"
|
version = "1.0.9"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MITNFA"
|
license = "MITNFA"
|
||||||
description = "Controls Tesla charge rate based on solar charge data"
|
description = "Controls Tesla charge rate based on solar charge data"
|
||||||
|
|
|
@ -6,7 +6,54 @@
|
||||||
<title>Tesla Charge Control</title>
|
<title>Tesla Charge Control</title>
|
||||||
<link id="favicon" rel="icon"
|
<link id="favicon" rel="icon"
|
||||||
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⏳</text></svg>">
|
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⏳</text></svg>">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
background-color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 40em;
|
||||||
|
margin: auto;
|
||||||
|
padding: 0.5em 2em;
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading,
|
||||||
|
.loading * {
|
||||||
|
cursor: progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selector {
|
||||||
|
padding: 1em;
|
||||||
|
background-color: gray;
|
||||||
|
width: max-content;
|
||||||
|
border: 0.2em;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
/* display: block; */
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
margin: 0.5em;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: all .2s 0s ease;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=radio] {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=radio]:checked+label {
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
const api_url = window.location.protocol + "//" + window.location.hostname + ":" + window.location.port;
|
const api_url = window.location.protocol + "//" + window.location.hostname + ":" + window.location.port;
|
||||||
|
|
||||||
|
@ -23,42 +70,51 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
function register() {
|
function register() {
|
||||||
return setInterval(refresh, 10000);
|
return setInterval(refresh, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function flash() {
|
function flash() {
|
||||||
fetch(api_url + "/flash", { method: "POST" });
|
fetch(api_url + "/flash", { method: "POST" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var is_automatic_control;
|
||||||
|
|
||||||
|
const delay = () => {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
};
|
||||||
|
|
||||||
function disable_automatic_control() {
|
function disable_automatic_control() {
|
||||||
|
if (is_automatic_control) {
|
||||||
|
document.getElementById('control-disabled').checked = true;
|
||||||
|
document.body.classList.add("loading");
|
||||||
|
|
||||||
fetch(api_url + "/disable-control", { method: "POST" })
|
fetch(api_url + "/disable-control", { method: "POST" })
|
||||||
.then((response) => {
|
.then(async (response) => {
|
||||||
|
let delayres = await delay();
|
||||||
refresh_buttons();
|
refresh_buttons();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function enable_automatic_control() {
|
function enable_automatic_control() {
|
||||||
|
if (!is_automatic_control) {
|
||||||
|
document.getElementById('control-enabled').checked = true;
|
||||||
|
document.body.classList.add("loading");
|
||||||
fetch(api_url + "/enable-control", { method: "POST" })
|
fetch(api_url + "/enable-control", { method: "POST" })
|
||||||
.then((response) => {
|
.then(async (response) => {
|
||||||
|
let delayres = await delay();
|
||||||
refresh_buttons();
|
refresh_buttons();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function update_control_buttons(data) {
|
function update_control_buttons(data) {
|
||||||
var button_container = document.getElementById("buttons");
|
document.body.classList.remove("loading");
|
||||||
while (button_container.childElementCount > 0) { button_container.removeChild(button_container.firstChild) }
|
is_automatic_control = data.control_enable;
|
||||||
if (data.control_enable) {
|
if (data.control_enable) {
|
||||||
// control enabled, so show disable button
|
document.getElementById('control-enabled').checked = true;
|
||||||
var button = document.createElement('button');
|
|
||||||
button.textContent = 'Disable automatic control';
|
|
||||||
button.addEventListener('click', disable_automatic_control);
|
|
||||||
button_container.appendChild(button);
|
|
||||||
} else {
|
} else {
|
||||||
// control disabled, so show enable button
|
document.getElementById('control-disabled').checked = true;
|
||||||
var button = document.createElement('button');
|
|
||||||
button.textContent = 'Enable automatic control';
|
|
||||||
button.addEventListener('click', enable_automatic_control);
|
|
||||||
button_container.appendChild(button);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,11 +128,11 @@
|
||||||
let favicon = document.getElementById("favicon");
|
let favicon = document.getElementById("favicon");
|
||||||
|
|
||||||
favicon.setAttribute("href", "data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>" + "⏳" + "</text></svg>");
|
favicon.setAttribute("href", "data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>" + "⏳" + "</text></svg>");
|
||||||
|
|
||||||
|
refresh_buttons();
|
||||||
fetch(api_url + "/car-state")
|
fetch(api_url + "/car-state")
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((json) => update_state(json));
|
.then((json) => update_state(json));
|
||||||
|
|
||||||
refresh_buttons();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function update_state(state) {
|
function update_state(state) {
|
||||||
|
@ -84,46 +140,15 @@
|
||||||
|
|
||||||
favicon.setAttribute("href", "data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>" + get_emoji(state.charge_state) + "</text></svg>");
|
favicon.setAttribute("href", "data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>" + get_emoji(state.charge_state) + "</text></svg>");
|
||||||
|
|
||||||
|
|
||||||
var info_div = document.getElementById("info");
|
var info_div = document.getElementById("info");
|
||||||
while (info_div.childElementCount > 0) { info_div.removeChild(info_div.firstChild) }
|
while (info_div.childElementCount > 0) { info_div.removeChild(info_div.firstChild) }
|
||||||
|
|
||||||
var arr = ["Battery " + state.charge_state.battery_level + "%", "Range: " + (state.charge_state.battery_range * 1.60934).toFixed(1) + "km", "Charging at " + state.charge_state.charge_rate.toFixed(1) + " amps", "Charging until battery at " + state.charge_state.charge_limit_soc + "%",
|
|
||||||
];
|
|
||||||
for (line in arr) {
|
|
||||||
el = document.createElement('p');
|
el = document.createElement('p');
|
||||||
el.appendChild(document.createTextNode(arr[line]));
|
|
||||||
info_div.appendChild(el)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
home = document.createElement('p');
|
|
||||||
if (state.location_data.home) {
|
|
||||||
home.appendChild(document.createTextNode("At home"));
|
|
||||||
} else {
|
|
||||||
home.appendChild(document.createTextNode("Not home"));
|
|
||||||
}
|
|
||||||
|
|
||||||
info_div.appendChild(home);
|
|
||||||
|
|
||||||
|
|
||||||
el = document.createElement('p');
|
|
||||||
el.appendChild(document.createTextNode("Full charge state:"));
|
|
||||||
|
|
||||||
state_json = document.createElement('pre');
|
state_json = document.createElement('pre');
|
||||||
state_json.appendChild(document.createTextNode(JSON.stringify(state.charge_state, null, '\t')));
|
state_json.appendChild(document.createTextNode(JSON.stringify(state, null, '\t')));
|
||||||
el.appendChild(state_json);
|
el.appendChild(state_json);
|
||||||
info_div.appendChild(el);
|
info_div.appendChild(el);
|
||||||
|
|
||||||
el = document.createElement('p');
|
|
||||||
el.appendChild(document.createTextNode("Full climate state:"));
|
|
||||||
|
|
||||||
state_json = document.createElement('pre');
|
|
||||||
state_json.appendChild(document.createTextNode(JSON.stringify(state.climate_state, null, '\t')));
|
|
||||||
el.appendChild(state_json);
|
|
||||||
info_div.appendChild(el);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_emoji(charge_state) {
|
function get_emoji(charge_state) {
|
||||||
|
@ -136,16 +161,24 @@
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body></body>
|
<body>
|
||||||
<div>
|
<div class="container">
|
||||||
<h2>
|
<h3>Automatic control:</h3>
|
||||||
<a href="/grafana">Grafana</a>
|
<div class="selector" id="control-selector">
|
||||||
</h2>
|
<input id="control-enabled" type="radio" name="control" onclick="enable_automatic_control()">
|
||||||
|
<label for="control-enabled">enabled</label>
|
||||||
|
<input id="control-disabled" type="radio" name="control" onclick="disable_automatic_control()">
|
||||||
|
<label for="control-disabled">disabled</label>
|
||||||
</div>
|
</div>
|
||||||
|
<br>
|
||||||
<button onclick="flash()">flash</button>
|
<button onclick="flash()">flash</button>
|
||||||
|
|
||||||
<p id="buttons"></p>
|
|
||||||
|
|
||||||
<div id="info"></div>
|
<div id="info"></div>
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
<a href="/grafana">Grafana</a>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
Loading…
Reference in a new issue