WiFi support for configuration
parent
822f7002a1
commit
df6a468e21
|
@ -8,4 +8,7 @@
|
||||||
CMakeLists.txt
|
CMakeLists.txt
|
||||||
CMakeListsPrivate.txt
|
CMakeListsPrivate.txt
|
||||||
CMakeListsUser.txt
|
CMakeListsUser.txt
|
||||||
cmake-build-*
|
cmake-build-*
|
||||||
|
/include/version.h
|
||||||
|
/data_embed/*.out
|
||||||
|
/src/TTGO_T-Beam_LoRa_APRS.ino.cpp
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>TTGO-T-Beam-LoRa-APRS <!--VERSION--></title>
|
||||||
|
<link rel="stylesheet" href="/style.css" type="text/css">
|
||||||
|
<script src="/js.js" type="text/javascript"></script>
|
||||||
|
<link rel="icon" href="data:,">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<section>
|
||||||
|
<div class="grid-container full">
|
||||||
|
<h2 class="u-full-width">WiFi Settings</h2>
|
||||||
|
</div>
|
||||||
|
<article>
|
||||||
|
<form action="/save_wifi_cfg" method="post">
|
||||||
|
<div class="grid-container quarters">
|
||||||
|
<div>
|
||||||
|
<div id="wifi_list">
|
||||||
|
</div>
|
||||||
|
<input type="button" value="Scan WiFi" id="scan_wifi_btn" onclick="scanWifi();">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="wifi_ssid">SSID</label>
|
||||||
|
<input class="u-full-width" type="text" name="wifi_ssid" placeholder="Your Wifi SSID"
|
||||||
|
id="wifi_ssid">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="wifi_password">Password</label>
|
||||||
|
<input class="u-full-width" type="password" name="wifi_password" id="wifi_password">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<input class="button-primary" type="submit" value="Save">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<div class="grid-container full">
|
||||||
|
<h2 class="u-full-width">APRS Settings</h2>
|
||||||
|
</div>
|
||||||
|
<article>
|
||||||
|
<form action="/save_aprs_cfg" method="post">
|
||||||
|
<div class="grid-container quarters">
|
||||||
|
<div>
|
||||||
|
<label for="aprs_callsign">Callsign and SSID</label>
|
||||||
|
<input class="u-full-width" type="text" minlength="3" name="aprs_callsign"
|
||||||
|
placeholder="NOCALL-1" id="aprs_callsign">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="aprs_relay_path">Relay Path</label>
|
||||||
|
<input class="u-full-width" type="text" minlength="0" name="aprs_relay_path"
|
||||||
|
id="aprs_relay_path">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="aprs_s_table">Symbol Table</label>
|
||||||
|
<input class="u-full-width" type="text" minlength="1" maxlength="1" name="aprs_s_table"
|
||||||
|
id="aprs_s_table">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="aprs_symbol">Symbol</label>
|
||||||
|
<input class="u-full-width" type="text" minlength="1" maxlength="1" name="aprs_symbol"
|
||||||
|
id="aprs_symbol">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="aprs_comment">Comment</label>
|
||||||
|
<input class="u-full-width" type="text" minlength="0" maxlength="64" name="aprs_comment"
|
||||||
|
id="aprs_comment">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="aprs_batt">Show Battery</label>
|
||||||
|
<input name="aprs_batt" id="aprs_batt" type="checkbox" value="1">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="aprs_alt">Show Altitude</label>
|
||||||
|
<input name="aprs_alt" id="aprs_alt" type="checkbox" value="1">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid-container quarters">
|
||||||
|
<div>
|
||||||
|
<label for="aprs_fixed_beac">Fixed Beacon (when no GPS)</label>
|
||||||
|
<input name="aprs_alt" id="aprs_fixed_beac" type="checkbox" value="1">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="aprs_fb_interv">Fixed Beacon Interval (s)</label>
|
||||||
|
<input name="aprs_fb_interv" id="aprs_fb_interv" type="number" min="120">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="aprs_lat_p">Latitude Preset</label>
|
||||||
|
<input class="u-full-width" type="text" minlength="0" name="aprs_lat_p" id="aprs_lat_p">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="aprs_lon_p">Longitude Preset</label>
|
||||||
|
<input class="u-full-width" type="text" minlength="0" name="aprs_lon_p" id="aprs_lon_p">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid-container full">
|
||||||
|
<div>
|
||||||
|
<input class="button-primary u-full-width" type="submit" value="Save">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<div class="grid-container full">
|
||||||
|
<h2 class="u-full-width">Actions</h2>
|
||||||
|
</div>
|
||||||
|
<article>
|
||||||
|
<div class="grid-container quarters">
|
||||||
|
<form action="/reboot" method="post">
|
||||||
|
<div>
|
||||||
|
<input class="button-primary" type="submit" value="Reboot">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form action="/restore" method="post">
|
||||||
|
<div>
|
||||||
|
<input class="button-primary" type="submit" value="Factory reset">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<footer>
|
||||||
|
<p><!--VERSION--></p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,42 @@
|
||||||
|
/**/
|
||||||
|
function scanWifi() {
|
||||||
|
let scanBtn = document.getElementById('scan_wifi_btn');
|
||||||
|
let wifiListContainer = document.getElementById("wifi_list");
|
||||||
|
wifiListContainer.innerHTML = 'Scanning...';
|
||||||
|
scanBtn.disabled = true;
|
||||||
|
var xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
scanBtn.disabled = false;
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
wifiListContainer.innerHTML = this.responseText;
|
||||||
|
const networks_found_list = document.querySelector('#networks_found_list');
|
||||||
|
|
||||||
|
networks_found_list.addEventListener('change', event => {
|
||||||
|
document.getElementById('wifi_ssid').value = networks_found_list.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.open("GET", "/scan_wifi", true);
|
||||||
|
xhttp.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = function () {
|
||||||
|
var xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
const response = JSON.parse(this.responseText);
|
||||||
|
for (const [key, value] of Object.entries(response)) {
|
||||||
|
let element = document.getElementById(key);
|
||||||
|
if (element){
|
||||||
|
if (element.type && element.type == "checkbox"){
|
||||||
|
element.checked = value;
|
||||||
|
} else {
|
||||||
|
element.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhttp.open("GET", "/cfg", true);
|
||||||
|
xhttp.send();
|
||||||
|
};
|
|
@ -0,0 +1,843 @@
|
||||||
|
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
|
||||||
|
|
||||||
|
/* Document
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the line height in all browsers.
|
||||||
|
* 2. Prevent adjustments of font size after orientation changes in iOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
html {
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
-webkit-text-size-adjust: 100%; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the margin in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the `main` element consistently in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the font size and margin on `h1` elements within `section` and
|
||||||
|
* `article` contexts in Chrome, Firefox, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grouping content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in Firefox.
|
||||||
|
* 2. Show the overflow in Edge and IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box; /* 1 */
|
||||||
|
height: 0; /* 1 */
|
||||||
|
overflow: visible; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-level semantics
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the gray background on active links in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the bottom border in Chrome 57-
|
||||||
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none; /* 1 */
|
||||||
|
text-decoration: underline; /* 2 */
|
||||||
|
text-decoration: underline dotted; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font size in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||||
|
* all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Embedded content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the border on images inside links in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Change the font styles in all browsers.
|
||||||
|
* 2. Remove the margin in Firefox and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: inherit; /* 1 */
|
||||||
|
font-size: 100%; /* 1 */
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
margin: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the overflow in IE.
|
||||||
|
* 1. Show the overflow in Edge.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input { /* 1 */
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||||
|
* 1. Remove the inheritance of text transform in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
select { /* 1 */
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
[type="button"],
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner border and padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
border-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the focus styles unset by the previous rule.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button:-moz-focusring,
|
||||||
|
[type="button"]:-moz-focusring,
|
||||||
|
[type="reset"]:-moz-focusring,
|
||||||
|
[type="submit"]:-moz-focusring {
|
||||||
|
outline: 1px dotted ButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
padding: 0.35em 0.75em 0.625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the text wrapping in Edge and IE.
|
||||||
|
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||||
|
* 3. Remove the padding so developers are not caught out when they zero out
|
||||||
|
* `fieldset` elements in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
legend {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
color: inherit; /* 2 */
|
||||||
|
display: table; /* 1 */
|
||||||
|
max-width: 100%; /* 1 */
|
||||||
|
padding: 0; /* 3 */
|
||||||
|
white-space: normal; /* 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||||
|
*/
|
||||||
|
|
||||||
|
progress {
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the default vertical scrollbar in IE 10+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in IE 10.
|
||||||
|
* 2. Remove the padding in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="checkbox"],
|
||||||
|
[type="radio"] {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
padding: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the odd appearance in Chrome and Safari.
|
||||||
|
* 2. Correct the outline style in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
-webkit-appearance: textfield; /* 1 */
|
||||||
|
outline-offset: -2px; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner padding in Chrome and Safari on macOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
* 2. Change font properties to `inherit` in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button; /* 1 */
|
||||||
|
font: inherit; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interactive
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in Edge, IE 10+, and Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
details {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Misc
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Barebones V3
|
||||||
|
* Copyright 2019 Steve Cochran
|
||||||
|
*
|
||||||
|
* Based of Skeleton by Dave Gamache
|
||||||
|
*
|
||||||
|
* Free to use under the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Table of contents
|
||||||
|
––––––––––––––––––––––––––––––––––––––––––––––––––
|
||||||
|
- Media Breakpoints
|
||||||
|
- Variables
|
||||||
|
- Grid
|
||||||
|
- Base Styles
|
||||||
|
- Typography
|
||||||
|
- Links
|
||||||
|
- Buttons
|
||||||
|
- Forms
|
||||||
|
- Lists
|
||||||
|
- Code
|
||||||
|
- Tables
|
||||||
|
- Spacing
|
||||||
|
- Utilities
|
||||||
|
- Clearing
|
||||||
|
- Media Queries
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ENV Variables
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
/* Media breakpoint variables for use in media queries
|
||||||
|
* Note: this section is currently commented out pending release of
|
||||||
|
* final CSS env() spec
|
||||||
|
* Breakpoints based on
|
||||||
|
* https://medium.freecodecamp.org/the-100-correct-way-to-do-css-breakpoints-88d6a5ba1862
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* CSS Variables
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
html {
|
||||||
|
|
||||||
|
/* default theme: light background, dark text, blue accent */
|
||||||
|
--theme-hue: 0; /* white */
|
||||||
|
--accent-hue: 194; /* blue */
|
||||||
|
|
||||||
|
--text-color-richer: hsl(var(--theme-hue), 0%, 5%); /* #0d0d0d */
|
||||||
|
--text-color-normal: hsl(var(--theme-hue), 0%, 13%); /* #222222 text color; button:hover:focus color */
|
||||||
|
--text-color-softer: hsl(var(--theme-hue), 0%, 33%); /* #555555 button color; button:hover border */
|
||||||
|
|
||||||
|
--accent-color: hsl(var(--accent-hue), 86%, 57%); /* #33C3F0 link; button-primary bg+border; textarea,select:focus border */
|
||||||
|
--accent-color-hover: hsl(var(--accent-hue), 76%, 49%); /* #1EAEDB link hover; button-primary:hover:focus bg+border */
|
||||||
|
|
||||||
|
--border-color: hsl(var(--theme-hue), 0%, 73%); /* #bbbbbb button border */
|
||||||
|
--border-color-softer: hsl(var(--theme-hue), 0%, 82%); /* #d1d1d1 textarea,select,code,td,hr border */
|
||||||
|
|
||||||
|
--background-color: white; /* transparent body background; textarea,select background */
|
||||||
|
--background-color-softer: hsl(var(--theme-hue), 0%, 95%);
|
||||||
|
--code-background: hsl(var(--theme-hue), 0%, 95%); /* #f1f1f1 code background*/
|
||||||
|
|
||||||
|
--button-primary-color: white;
|
||||||
|
|
||||||
|
|
||||||
|
/* Note: Skeleton was based off a 10px font sizing for REM */
|
||||||
|
/* 62.5% of typical 16px browser default = 10px */
|
||||||
|
--base-font-size: 62.5%;
|
||||||
|
|
||||||
|
/* Grid Defaults - default to match orig skeleton settings */
|
||||||
|
--grid-max-width: 960px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark Theme
|
||||||
|
Note: prefers-color-scheme selector support is still limited, but
|
||||||
|
included for future and an example of defining a different base 'theme'
|
||||||
|
*/
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:html {
|
||||||
|
/* dark theme: light background, dark text, blue accent */
|
||||||
|
--theme-hue: 0; /* black */
|
||||||
|
--accent-hue: 194; /* blue */
|
||||||
|
|
||||||
|
--text-color-richer: hsl(var(--theme-hue), 0%, 95%); /* */
|
||||||
|
--text-color-normal: hsl(var(--theme-hue), 0%, 80%); /* text color; button:hover:focus color */
|
||||||
|
--text-color-softer: hsl(var(--theme-hue), 0%, 67%); /* button color; button:hover border */
|
||||||
|
|
||||||
|
--accent-color: hsl(var(--accent-hue), 76%, 49%); /* link; button-primary bg+border; textarea,select:focus border */
|
||||||
|
--accent-color-hover: hsl(var(--accent-hue), 86%, 57%); /* link hover; button-primary:hover:focus bg+border */
|
||||||
|
|
||||||
|
--border-color: hsl(var(--theme-hue), 0%, 27%); /* button border */
|
||||||
|
--border-color-softer: hsl(var(--theme-hue), 0%, 20%); /* textarea,select,code,td,hr border */
|
||||||
|
|
||||||
|
--background-color: hsl(var(--theme-hue), 0%, 12%); /* body background; textarea,select background */
|
||||||
|
--background-color-softer: hsl(var(--theme-hue), 0%, 18%);
|
||||||
|
--code-background: hsl(var(--theme-hue), 0%, 5%); /* code background*/
|
||||||
|
|
||||||
|
--button-primary-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.value-img {
|
||||||
|
filter: invert(0.8);
|
||||||
|
}
|
||||||
|
/* TODO - test dialing back image intensity on dark background
|
||||||
|
img {
|
||||||
|
opacity: .80;
|
||||||
|
transition: opacity .5s ease-in-out;
|
||||||
|
}
|
||||||
|
img:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Grid
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
/* CSS Grid depends much more on CSS than HTML, so there is less boilerplate
|
||||||
|
than with skeleton. Only basic 1-4 column grids are included.
|
||||||
|
Any additional needs should be made using custom CSS directives */
|
||||||
|
|
||||||
|
|
||||||
|
.grid-container {
|
||||||
|
position: relative;
|
||||||
|
max-width: var(--grid-max-width);
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
display: grid;
|
||||||
|
grid-gap: 20px;
|
||||||
|
gap: 20px;
|
||||||
|
|
||||||
|
/* by default use min 200px wide columns auto-fit into width */
|
||||||
|
grid-template-columns: minmax(200px, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* grids to 3 columns above mobile sizes */
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
.grid-container {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* basic grids */
|
||||||
|
.grid-container.fifths {
|
||||||
|
grid-template-columns: repeat(5, 1fr);
|
||||||
|
}
|
||||||
|
.grid-container.quarters {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
}
|
||||||
|
.grid-container.thirds {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
.grid-container.halves {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
.grid-container.full {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Base Styles
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
html {
|
||||||
|
font-size: var(--base-font-size);
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font-size: 1.6rem; /* changed from 15px in orig skeleton */
|
||||||
|
line-height: 1.6;
|
||||||
|
font-weight: 400;
|
||||||
|
font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||||
|
color: var(--text-color-normal);
|
||||||
|
background-color: var(--background-color);;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Typography
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
font-weight: 300; }
|
||||||
|
h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
|
||||||
|
h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
|
||||||
|
h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
|
||||||
|
h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
|
||||||
|
h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
|
||||||
|
h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
|
||||||
|
|
||||||
|
/* Larger than phablet */
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
h1 { font-size: 5.0rem; }
|
||||||
|
h2 { font-size: 4.2rem; }
|
||||||
|
h3 { font-size: 3.6rem; }
|
||||||
|
h4 { font-size: 3.0rem; }
|
||||||
|
h5 { font-size: 2.4rem; }
|
||||||
|
h6 { font-size: 1.5rem; }
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: 0; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Links
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
a {
|
||||||
|
color: var(--accent-color); }
|
||||||
|
a:hover {
|
||||||
|
color: var(--accent-color-hover); }
|
||||||
|
|
||||||
|
|
||||||
|
/* Buttons
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
.button,
|
||||||
|
button,
|
||||||
|
input[type="submit"],
|
||||||
|
input[type="reset"],
|
||||||
|
input[type="button"] {
|
||||||
|
display: inline-block;
|
||||||
|
height: 38px;
|
||||||
|
padding: 0 30px;
|
||||||
|
color: var(--text-color-softer);
|
||||||
|
text-align: center;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 38px;
|
||||||
|
letter-spacing: .1rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-decoration: none;
|
||||||
|
white-space: nowrap;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
cursor: pointer;
|
||||||
|
box-sizing: border-box; }
|
||||||
|
.button:hover,
|
||||||
|
button:hover,
|
||||||
|
input[type="submit"]:hover,
|
||||||
|
input[type="reset"]:hover,
|
||||||
|
input[type="button"]:hover,
|
||||||
|
.button:focus,
|
||||||
|
button:focus,
|
||||||
|
input[type="submit"]:focus,
|
||||||
|
input[type="reset"]:focus,
|
||||||
|
input[type="button"]:focus {
|
||||||
|
color: var(--text-color-normal);
|
||||||
|
border-color: var(--text-color-softer);
|
||||||
|
outline: 0; }
|
||||||
|
.button.button-primary,
|
||||||
|
button.button-primary,
|
||||||
|
input[type="submit"].button-primary,
|
||||||
|
input[type="reset"].button-primary,
|
||||||
|
input[type="button"].button-primary {
|
||||||
|
color: var(--button-primary-color);
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
border-color: var(--accent-color); }
|
||||||
|
.button.button-primary:hover,
|
||||||
|
button.button-primary:hover,
|
||||||
|
input[type="submit"].button-primary:hover,
|
||||||
|
input[type="reset"].button-primary:hover,
|
||||||
|
input[type="button"].button-primary:hover,
|
||||||
|
.button.button-primary:focus,
|
||||||
|
button.button-primary:focus,
|
||||||
|
input[type="submit"].button-primary:focus,
|
||||||
|
input[type="reset"].button-primary:focus,
|
||||||
|
input[type="button"].button-primary:focus {
|
||||||
|
color: var(--button-primary-color);
|
||||||
|
background-color: var(--accent-color-hover);
|
||||||
|
border-color: var(--accent-color-hover); }
|
||||||
|
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
input[type="email"],
|
||||||
|
input[type="number"],
|
||||||
|
input[type="search"],
|
||||||
|
input[type="text"],
|
||||||
|
input[type="tel"],
|
||||||
|
input[type="url"],
|
||||||
|
input[type="password"],
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
height: 38px;
|
||||||
|
padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
|
||||||
|
background-color: var(--background-color);
|
||||||
|
border: 1px solid var(--border-color-softer);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: none;
|
||||||
|
box-sizing: border-box; }
|
||||||
|
/* Removes awkward default styles on some inputs for iOS */
|
||||||
|
input[type="email"],
|
||||||
|
input[type="number"],
|
||||||
|
input[type="search"],
|
||||||
|
input[type="text"],
|
||||||
|
input[type="tel"],
|
||||||
|
input[type="url"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="button"],
|
||||||
|
input[type="submit"],
|
||||||
|
textarea {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
appearance: none; }
|
||||||
|
textarea {
|
||||||
|
min-height: 65px;
|
||||||
|
padding-top: 6px;
|
||||||
|
padding-bottom: 6px; }
|
||||||
|
input[type="email"]:focus,
|
||||||
|
input[type="number"]:focus,
|
||||||
|
input[type="search"]:focus,
|
||||||
|
input[type="text"]:focus,
|
||||||
|
input[type="tel"]:focus,
|
||||||
|
input[type="url"]:focus,
|
||||||
|
input[type="password"]:focus,
|
||||||
|
textarea:focus,
|
||||||
|
select:focus {
|
||||||
|
border: 1px solid var(--accent-color);
|
||||||
|
outline: 0; }
|
||||||
|
label,
|
||||||
|
legend {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
font-weight: 600; }
|
||||||
|
fieldset {
|
||||||
|
padding: 0;
|
||||||
|
border-width: 0; }
|
||||||
|
input[type="checkbox"],
|
||||||
|
input[type="radio"] {
|
||||||
|
display: inline; }
|
||||||
|
label > .label-body {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: .5rem;
|
||||||
|
font-weight: normal; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Lists
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
ul {
|
||||||
|
list-style: circle inside; }
|
||||||
|
ol {
|
||||||
|
list-style: decimal inside; }
|
||||||
|
ol, ul {
|
||||||
|
padding-left: 0;
|
||||||
|
margin-top: 0; }
|
||||||
|
ul ul, ul ol, ol ol, ol ul {
|
||||||
|
font-size: 100%;
|
||||||
|
margin: 1rem 0 1rem 3rem;
|
||||||
|
color: var(--text-color-softer);
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
margin-bottom: 0.5rem; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Code
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
code {
|
||||||
|
padding: .2rem .5rem;
|
||||||
|
margin: 0 .2rem;
|
||||||
|
font-size: 90%;
|
||||||
|
white-space: nowrap;
|
||||||
|
background: var(--code-background);
|
||||||
|
border: 1px solid var(--border-color-softer);
|
||||||
|
border-radius: 4px; }
|
||||||
|
pre > code {
|
||||||
|
display: block;
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
white-space: pre;
|
||||||
|
overflow: auto; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Tables
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
padding: 12px 15px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid var(--border-color-softer); }
|
||||||
|
th:first-child,
|
||||||
|
td:first-child {
|
||||||
|
padding-left: 0; }
|
||||||
|
th:last-child,
|
||||||
|
td:last-child {
|
||||||
|
padding-right: 0; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Spacing
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
button,
|
||||||
|
.button {
|
||||||
|
margin-bottom: 1rem; }
|
||||||
|
input,
|
||||||
|
textarea,
|
||||||
|
select,
|
||||||
|
fieldset {
|
||||||
|
margin-bottom: 1.5rem; }
|
||||||
|
pre,
|
||||||
|
blockquote,
|
||||||
|
dl,
|
||||||
|
figure,
|
||||||
|
table,
|
||||||
|
p,
|
||||||
|
ul,
|
||||||
|
ol,
|
||||||
|
form {
|
||||||
|
margin-bottom: 2.5rem; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Utilities
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
.u-full-width {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box; }
|
||||||
|
.u-max-full-width {
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box; }
|
||||||
|
.u-pull-right {
|
||||||
|
float: right; }
|
||||||
|
.u-pull-left {
|
||||||
|
float: left; }
|
||||||
|
.u-align-left {
|
||||||
|
text-align: left; }
|
||||||
|
.u-align-right {
|
||||||
|
text-align: right; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Misc
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
hr {
|
||||||
|
margin-top: 3rem;
|
||||||
|
margin-bottom: 3.5rem;
|
||||||
|
border-width: 0;
|
||||||
|
border-top: 1px solid var(--border-color-softer); }
|
||||||
|
|
||||||
|
|
||||||
|
/* Clearing
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
|
||||||
|
/* Self Clearing Goodness */
|
||||||
|
.container:after,
|
||||||
|
.row:after,
|
||||||
|
.u-cf {
|
||||||
|
content: "";
|
||||||
|
display: table;
|
||||||
|
clear: both; }
|
||||||
|
|
||||||
|
|
||||||
|
/* Media Queries
|
||||||
|
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||||
|
/*
|
||||||
|
Note: The best way to structure the use of media queries is to create the queries
|
||||||
|
near the relevant code. For example, if you wanted to change the styles for buttons
|
||||||
|
on small devices, paste the mobile query code up in the buttons section and style it
|
||||||
|
there.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* Larger than mobile (default point when grid becomes active) */
|
||||||
|
@media (min-width: 600px) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Larger than phablet */
|
||||||
|
@media (min-width: 900px) {
|
||||||
|
.container {
|
||||||
|
max-width: 900px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Larger than tablet */
|
||||||
|
@media (min-width: 1200px) {}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
text-align: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
position: relative;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
margin-top: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "TTGO_T-Beam_LoRa_APRS_config.h"
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WebServer.h>
|
||||||
|
#include <ESPmDNS.h>
|
||||||
|
#include <Preferences.h>
|
||||||
|
|
||||||
|
#define ENABLE_PREFERENCES
|
||||||
|
|
||||||
|
extern Preferences preferences;
|
||||||
|
// MAX 15 chars for preferenece key!!!
|
||||||
|
static const char *const PREF_APRS_CALLSIGN = "aprs_callsign";
|
||||||
|
static const char *const PREF_APRS_RELAY_PATH = "aprs_relay_path";
|
||||||
|
static const char *const PREF_APRS_RELAY_PATH_INIT = "aprs_relay_init";
|
||||||
|
static const char *const PREF_APRS_SYMBOL_TABLE = "aprs_s_table";
|
||||||
|
static const char *const PREF_APRS_SYMBOL = "aprs_symbol";
|
||||||
|
static const char *const PREF_APRS_COMMENT = "aprs_comment";
|
||||||
|
static const char *const PREF_APRS_COMMENT_INIT = "aprs_comm_init";
|
||||||
|
static const char *const PREF_APRS_SHOW_ALTITUDE = "aprs_alt";
|
||||||
|
static const char *const PREF_APRS_SHOW_ALTITUDE_INIT = "aprs_alt_init";
|
||||||
|
static const char *const PREF_APRS_SHOW_BATTERY = "aprs_batt";
|
||||||
|
static const char *const PREF_APRS_SHOW_BATTERY_INIT = "aprs_batt_init";
|
||||||
|
static const char *const PREF_APRS_LATITUDE_PRESET = "aprs_lat_p";
|
||||||
|
static const char *const PREF_APRS_LATITUDE_PRESET_INIT = "aprs_lat_p_init";
|
||||||
|
static const char *const PREF_APRS_LONGITUDE_PRESET = "aprs_lon_p";
|
||||||
|
static const char *const PREF_APRS_LONGITUDE_PRESET_INIT = "aprs_lon_p_init";
|
||||||
|
static const char *const PREF_APRS_FIXED_BEACON_PRESET = "aprs_fixed_beac";
|
||||||
|
static const char *const PREF_APRS_FIXED_BEACON_PRESET_INIT = "aprs_fix_b_init";
|
||||||
|
static const char *const PREF_APRS_FIXED_BEACON_INTERVAL_PRESET = "aprs_fb_interv";
|
||||||
|
static const char *const PREF_APRS_FIXED_BEACON_INTERVAL_PRESET_INIT = "aprs_fb_in_init";
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
String callsign;
|
||||||
|
} tWebServerCfg;
|
||||||
|
|
||||||
|
[[noreturn]] void taskWebServer(void *parameter);
|
|
@ -14,7 +14,15 @@ board = ttgo-t-beam
|
||||||
framework = arduino
|
framework = arduino
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
build_flags = -Wl,--gc-sections,--relax
|
build_flags = -Wl,--gc-sections,--relax
|
||||||
lib_deps =
|
board_build.partitions = no_ota.csv
|
||||||
|
board_build.embed_files =
|
||||||
|
data_embed/index.html.out
|
||||||
|
data_embed/style.css.out
|
||||||
|
data_embed/js.js.out
|
||||||
|
extra_scripts =
|
||||||
|
pre:tools/buildscript_versioning.py
|
||||||
|
pre:tools/compress_assets.py
|
||||||
|
lib_deps =
|
||||||
RadioHead
|
RadioHead
|
||||||
TinyGPSPlus
|
TinyGPSPlus
|
||||||
#DHT sensor library for ESPx
|
#DHT sensor library for ESPx
|
||||||
|
|
|
@ -25,7 +25,10 @@
|
||||||
#ifdef KISS_PROTOCOL
|
#ifdef KISS_PROTOCOL
|
||||||
#include "taskTNC.h"
|
#include "taskTNC.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ENABLE_WIFI
|
||||||
|
#include "taskWebServer.h"
|
||||||
|
#endif
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
// I2C LINES
|
// I2C LINES
|
||||||
#define I2C_SDA 21
|
#define I2C_SDA 21
|
||||||
|
@ -66,6 +69,16 @@ boolean gps_state = true;
|
||||||
boolean key_up = true;
|
boolean key_up = true;
|
||||||
boolean t_lock = false;
|
boolean t_lock = false;
|
||||||
boolean fixed_beacon_enabled = false;
|
boolean fixed_beacon_enabled = false;
|
||||||
|
#ifdef SHOW_ALT
|
||||||
|
boolean showAltitude = true;
|
||||||
|
#else
|
||||||
|
boolean showAltitude = false;
|
||||||
|
#endif
|
||||||
|
#ifdef SHOW_BATT
|
||||||
|
boolean showBattery = true;
|
||||||
|
#else
|
||||||
|
boolean showBattery = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Variables and Constants
|
// Variables and Constants
|
||||||
String loraReceivedFrameString = ""; //data on buff is copied to this string
|
String loraReceivedFrameString = ""; //data on buff is copied to this string
|
||||||
|
@ -115,6 +128,11 @@ float average_course[ANGLE_AVGS];
|
||||||
float avg_c_y, avg_c_x;
|
float avg_c_y, avg_c_x;
|
||||||
uint8_t txPower = TXdbmW;
|
uint8_t txPower = TXdbmW;
|
||||||
|
|
||||||
|
#ifdef ENABLE_WIFI
|
||||||
|
tWebServerCfg webServerCfg;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static const adc_atten_t atten = ADC_ATTEN_DB_6;
|
static const adc_atten_t atten = ADC_ATTEN_DB_6;
|
||||||
static const adc_unit_t unit = ADC_UNIT_1;
|
static const adc_unit_t unit = ADC_UNIT_1;
|
||||||
|
|
||||||
|
@ -153,10 +171,9 @@ void prepareAPRSFrame(){
|
||||||
double Tspeed=0, Tcourse=0;
|
double Tspeed=0, Tcourse=0;
|
||||||
String Speedx, Coursex;
|
String Speedx, Coursex;
|
||||||
int i;
|
int i;
|
||||||
#ifdef SHOW_ALT
|
|
||||||
String Altx;
|
String Altx;
|
||||||
int Talt;
|
int Talt;
|
||||||
#endif
|
|
||||||
|
|
||||||
Tlat=gps.location.lat();
|
Tlat=gps.location.lat();
|
||||||
Tlon=gps.location.lng();
|
Tlon=gps.location.lng();
|
||||||
|
@ -183,31 +200,31 @@ void prepareAPRSFrame(){
|
||||||
outString += ">APLM0:!";
|
outString += ">APLM0:!";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gps_state && gps.location.isValid()){
|
if(gps_state && gps.location.isValid()) {
|
||||||
outString += aprsSymbolTable;
|
outString += aprsSymbolTable;
|
||||||
ax25_base91enc(helper_base91, 4, aprs_lat);
|
ax25_base91enc(helper_base91, 4, aprs_lat);
|
||||||
for (i=0; i<4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
outString += helper_base91[i];
|
outString += helper_base91[i];
|
||||||
}
|
}
|
||||||
ax25_base91enc(helper_base91, 4, aprs_lon);
|
ax25_base91enc(helper_base91, 4, aprs_lon);
|
||||||
for (i=0; i<4; i++) {
|
for (i = 0; i < 4; i++) {
|
||||||
outString += helper_base91[i];
|
outString += helper_base91[i];
|
||||||
}
|
}
|
||||||
outString += aprsSymbol;
|
outString += aprsSymbol;
|
||||||
ax25_base91enc(helper_base91, 1, (uint32_t) Tcourse/4 );
|
ax25_base91enc(helper_base91, 1, (uint32_t) Tcourse / 4);
|
||||||
outString += helper_base91[0];
|
outString += helper_base91[0];
|
||||||
ax25_base91enc(helper_base91, 1, (uint32_t) (log1p(Tspeed)/0.07696));
|
ax25_base91enc(helper_base91, 1, (uint32_t) (log1p(Tspeed) / 0.07696));
|
||||||
outString += helper_base91[0];
|
outString += helper_base91[0];
|
||||||
outString += "H";
|
outString += "H";
|
||||||
#ifdef SHOW_ALT
|
if (showAltitude) {
|
||||||
Talt=gps.altitude.meters() * 3.28d;
|
Talt = gps.altitude.meters() * 3.28d;
|
||||||
Altx = Talt;
|
Altx = Talt;
|
||||||
outString += "/A=";
|
outString += "/A=";
|
||||||
for (i = 0; i < (6-Altx.length()); ++i) {
|
for (i = 0; i < (6 - Altx.length()); ++i) {
|
||||||
outString += "0";
|
outString += "0";
|
||||||
}
|
}
|
||||||
outString += Talt;
|
outString += Talt;
|
||||||
#endif
|
}
|
||||||
}else{
|
}else{
|
||||||
outString += aprsLonPreset;
|
outString += aprsLonPreset;
|
||||||
outString += aprsSymbolTable;
|
outString += aprsSymbolTable;
|
||||||
|
@ -217,11 +234,11 @@ void prepareAPRSFrame(){
|
||||||
|
|
||||||
outString += aprsComment;
|
outString += aprsComment;
|
||||||
|
|
||||||
#ifdef SHOW_BATT // battery is not frame part move after comment
|
if (showBattery) {
|
||||||
outString += " Batt=";
|
outString += " Batt=";
|
||||||
outString += String(BattVolts, 2);
|
outString += String(BattVolts, 2);
|
||||||
outString += ("V");
|
outString += ("V");
|
||||||
#endif
|
}
|
||||||
|
|
||||||
#ifdef KISS_PROTOCOL
|
#ifdef KISS_PROTOCOL
|
||||||
sendToTNC(outString);
|
sendToTNC(outString);
|
||||||
|
@ -373,8 +390,77 @@ void sendTelemetryFrame() {
|
||||||
// + SETUP --------------------------------------------------------------+//
|
// + SETUP --------------------------------------------------------------+//
|
||||||
|
|
||||||
void setup(){
|
void setup(){
|
||||||
|
#ifdef DIGI_PATH
|
||||||
|
relay_path = DIGI_PATH;
|
||||||
|
#else
|
||||||
|
relay_path = "";
|
||||||
|
#endif
|
||||||
#ifdef FIXED_BEACON_EN
|
#ifdef FIXED_BEACON_EN
|
||||||
fixed_beacon_enabled = true;
|
fixed_beacon_enabled = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_PREFERENCES
|
||||||
|
preferences.begin("cfg", false);
|
||||||
|
aprsSymbolTable = preferences.getString(PREF_APRS_SYMBOL_TABLE);
|
||||||
|
if (aprsSymbolTable.isEmpty()){
|
||||||
|
preferences.putString(PREF_APRS_SYMBOL_TABLE, APRS_SYMBOL_TABLE);
|
||||||
|
aprsSymbolTable = preferences.getString(PREF_APRS_SYMBOL_TABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
aprsSymbol = preferences.getString(PREF_APRS_SYMBOL);
|
||||||
|
if (aprsSymbol.isEmpty()){
|
||||||
|
preferences.putString(PREF_APRS_SYMBOL, APRS_SYMBOL);
|
||||||
|
aprsSymbol = preferences.getString(PREF_APRS_SYMBOL, APRS_SYMBOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!preferences.getBool(PREF_APRS_COMMENT_INIT)){
|
||||||
|
preferences.putBool(PREF_APRS_COMMENT_INIT, true);
|
||||||
|
preferences.putString(PREF_APRS_COMMENT, MY_COMMENT);
|
||||||
|
}
|
||||||
|
aprsComment = preferences.getString(PREF_APRS_COMMENT);
|
||||||
|
|
||||||
|
if (!preferences.getBool(PREF_APRS_RELAY_PATH_INIT)){
|
||||||
|
preferences.putBool(PREF_APRS_RELAY_PATH_INIT, true);
|
||||||
|
preferences.putString(PREF_APRS_RELAY_PATH, DIGI_PATH);
|
||||||
|
}
|
||||||
|
relay_path = preferences.getString(PREF_APRS_RELAY_PATH);
|
||||||
|
|
||||||
|
if (!preferences.getBool(PREF_APRS_SHOW_ALTITUDE_INIT)){
|
||||||
|
preferences.putBool(PREF_APRS_SHOW_ALTITUDE_INIT, true);
|
||||||
|
preferences.putBool(PREF_APRS_SHOW_ALTITUDE, showAltitude);
|
||||||
|
}
|
||||||
|
showAltitude = preferences.getBool(PREF_APRS_SHOW_ALTITUDE);
|
||||||
|
|
||||||
|
if (!preferences.getBool(PREF_APRS_SHOW_BATTERY_INIT)){
|
||||||
|
preferences.putBool(PREF_APRS_SHOW_BATTERY_INIT, true);
|
||||||
|
preferences.putBool(PREF_APRS_SHOW_BATTERY, showBattery);
|
||||||
|
}
|
||||||
|
showBattery = preferences.getBool(PREF_APRS_SHOW_BATTERY);
|
||||||
|
|
||||||
|
if (!preferences.getBool(PREF_APRS_LATITUDE_PRESET_INIT)){
|
||||||
|
preferences.putBool(PREF_APRS_LATITUDE_PRESET_INIT, true);
|
||||||
|
preferences.putString(PREF_APRS_LATITUDE_PRESET, LATIDUDE_PRESET);
|
||||||
|
}
|
||||||
|
aprsLatPreset = preferences.getString(LATIDUDE_PRESET);
|
||||||
|
|
||||||
|
if (!preferences.getBool(PREF_APRS_LONGITUDE_PRESET_INIT)){
|
||||||
|
preferences.putBool(PREF_APRS_LONGITUDE_PRESET_INIT, true);
|
||||||
|
preferences.putString(PREF_APRS_LONGITUDE_PRESET, LONGITUDE_PRESET);
|
||||||
|
}
|
||||||
|
aprsLonPreset = preferences.getString(PREF_APRS_LONGITUDE_PRESET);
|
||||||
|
|
||||||
|
if (!preferences.getBool(PREF_APRS_FIXED_BEACON_PRESET_INIT)){
|
||||||
|
preferences.putBool(PREF_APRS_FIXED_BEACON_PRESET_INIT, true);
|
||||||
|
preferences.putBool(PREF_APRS_FIXED_BEACON_PRESET, fixed_beacon_enabled);
|
||||||
|
}
|
||||||
|
fixed_beacon_enabled = preferences.getBool(PREF_APRS_FIXED_BEACON_PRESET);
|
||||||
|
|
||||||
|
if (!preferences.getBool(PREF_APRS_FIXED_BEACON_INTERVAL_PRESET_INIT)){
|
||||||
|
preferences.putBool(PREF_APRS_FIXED_BEACON_INTERVAL_PRESET_INIT, true);
|
||||||
|
preferences.putInt(PREF_APRS_FIXED_BEACON_INTERVAL_PRESET, fix_beacon_interval/1000);
|
||||||
|
}
|
||||||
|
fix_beacon_interval = preferences.getInt(PREF_APRS_FIXED_BEACON_PRESET) * 1000;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
for (int i=0;i<ANGLE_AVGS;i++) { // set average_course to "0"
|
for (int i=0;i<ANGLE_AVGS;i++) { // set average_course to "0"
|
||||||
|
@ -406,11 +492,14 @@ void setup(){
|
||||||
}
|
}
|
||||||
|
|
||||||
writedisplaytext("LoRa-APRS","","Init:","Display OK!","","",1000);
|
writedisplaytext("LoRa-APRS","","Init:","Display OK!","","",1000);
|
||||||
|
|
||||||
Tcall = prepareCallsign(String(CALLSIGN));
|
Tcall = prepareCallsign(String(CALLSIGN));
|
||||||
#ifdef DIGI_PATH
|
#ifdef ENABLE_PREFERENCES
|
||||||
relay_path = DIGI_PATH;
|
Tcall = preferences.getString(PREF_APRS_CALLSIGN);
|
||||||
#else
|
if (Tcall.isEmpty()){
|
||||||
relay_path = "";
|
preferences.putString(PREF_APRS_CALLSIGN, String(CALLSIGN));
|
||||||
|
Tcall = preferences.getString(PREF_APRS_CALLSIGN);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!rf95.init()) {
|
if (!rf95.init()) {
|
||||||
|
@ -446,6 +535,12 @@ void setup(){
|
||||||
SerialBT.begin(String("TTGO LORA APRS ") + Tcall);
|
SerialBT.begin(String("TTGO LORA APRS ") + Tcall);
|
||||||
writedisplaytext("LoRa-APRS","","Init:","BT OK!","","",250);
|
writedisplaytext("LoRa-APRS","","Init:","BT OK!","","",250);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef ENABLE_WIFI
|
||||||
|
webServerCfg = {.callsign = Tcall};
|
||||||
|
xTaskCreate(taskWebServer, "taskWebServer", 50000, (void*)(&webServerCfg), 1, nullptr);
|
||||||
|
writedisplaytext("LoRa-APRS","","Init:","WiFi task started"," =:-) ","",250);
|
||||||
|
#endif
|
||||||
|
|
||||||
writedisplaytext("LoRa-APRS","","Init:","FINISHED OK!"," =:-) ","",250);
|
writedisplaytext("LoRa-APRS","","Init:","FINISHED OK!"," =:-) ","",250);
|
||||||
writedisplaytext("","","","","","",0);
|
writedisplaytext("","","","","","",0);
|
||||||
time_to_refresh = millis() + showRXTime;
|
time_to_refresh = millis() + showRXTime;
|
||||||
|
|
|
@ -7,18 +7,18 @@
|
||||||
|
|
||||||
// USER DATA - USE THESE LINES TO MODIFY YOUR PREFERENCES
|
// USER DATA - USE THESE LINES TO MODIFY YOUR PREFERENCES
|
||||||
#define KISS_PROTOCOL // If enabled send and receive data in SIMPLE KISS format to serial port
|
#define KISS_PROTOCOL // If enabled send and receive data in SIMPLE KISS format to serial port
|
||||||
#define CALLSIGN "SQ9MDD-11" // enter your callsign here - less then 6 letter callsigns please add "spaces" so total length is 6 (without SSID)
|
#define CALLSIGN "NOCALL-0" // enter your callsign here - less then 6 letter callsigns please add "spaces" so total length is 6 (without SSID)
|
||||||
#define DIGI_PATH "WIDE1-1" // one hope please (WIDE1-1)
|
#define DIGI_PATH "WIDE1-1" // one hope please (WIDE1-1)
|
||||||
#define FIXED_BEACON_EN // allows cyclic sending of a bicon when GPS is turned off
|
#define FIXED_BEACON_EN // allows cyclic sending of a bicon when GPS is turned off
|
||||||
#define LATIDUDE_PRESET "5215.03N" // please in APRS notation: DDMM.mmN or DDMM.mmS (used for manual or fixed beacon sending)
|
#define LATIDUDE_PRESET "0000.00N" // please in APRS notation: DDMM.mmN or DDMM.mmS (used for manual or fixed beacon sending)
|
||||||
#define LONGITUDE_PRESET "02055.59E" // please in APRS notation: DDDMM.mmE or DDDMM.mmW (used for manual or fixed beacon sending)
|
#define LONGITUDE_PRESET "00000.00E" // please in APRS notation: DDDMM.mmE or DDDMM.mmW (used for manual or fixed beacon sending)
|
||||||
#define APRS_SYMBOL_TABLE "/"
|
#define APRS_SYMBOL_TABLE "/"
|
||||||
#define APRS_SYMBOL "[" // other symbols are: "[" => RUNNER, "b" => BICYCLE, "<" => MOTORCYCLE, "R" => Recreation Vehicle
|
#define APRS_SYMBOL "[" // other symbols are: "[" => RUNNER, "b" => BICYCLE, "<" => MOTORCYCLE, "R" => Recreation Vehicle
|
||||||
#define MY_COMMENT "LoRa tracker" // add your coment here - if empty then no comment is sent
|
#define MY_COMMENT "TTGO LoRa APRS Tracker" // add your coment here - if empty then no comment is sent
|
||||||
//#define SHOW_ALT // send Altitude in frame
|
#define SHOW_ALT // send Altitude in frame
|
||||||
#define SHOW_BATT // send battery voltage at the end of comment (we need beggining for QSY message format)
|
#define SHOW_BATT // send battery voltage at the end of comment (we need beggining for QSY message format)
|
||||||
#define SHOW_RX_PACKET // uncomment to show received LoRa APS packets for the time given below
|
#define SHOW_RX_PACKET // uncomment to show received LoRa APS packets for the time given below
|
||||||
#define SHOW_RX_TIME 10000 // show RX packet for milliseconds (5000 = 5secs)
|
#define SHOW_RX_TIME 2000 // show RX packet for milliseconds (5000 = 5secs)
|
||||||
#define TXFREQ 433.775 // Transmit frequency in MHz
|
#define TXFREQ 433.775 // Transmit frequency in MHz
|
||||||
#define TXdbmW 20 // Transmit power in dBm 17-50mW, 18-63mW, 19-80mW, 20-100mW
|
#define TXdbmW 20 // Transmit power in dBm 17-50mW, 18-63mW, 19-80mW, 20-100mW
|
||||||
//#define SHOW_GPS_DATA // uncomment to show on serial port, received data from GPS and debug information
|
//#define SHOW_GPS_DATA // uncomment to show on serial port, received data from GPS and debug information
|
||||||
|
@ -28,6 +28,7 @@
|
||||||
//#define LOCAL_KISS_ECHO // echoing KISS frame back
|
//#define LOCAL_KISS_ECHO // echoing KISS frame back
|
||||||
#define T_BEAM_V1_0 // if enabled t-beam v1.0 disabled t-beam V.0.7
|
#define T_BEAM_V1_0 // if enabled t-beam v1.0 disabled t-beam V.0.7
|
||||||
//#define KISS_DEBUG
|
//#define KISS_DEBUG
|
||||||
|
#define ENABLE_WIFI
|
||||||
|
|
||||||
#define MAX_TIME_TO_NEXT_TX 360000L // TRANSMIT INTERVAL set here MAXIMUM time in ms(!) for smart beaconing - minimum time is always 1 min = 60 secs = 60000L !!!
|
#define MAX_TIME_TO_NEXT_TX 360000L // TRANSMIT INTERVAL set here MAXIMUM time in ms(!) for smart beaconing - minimum time is always 1 min = 60 secs = 60000L !!!
|
||||||
#define FIX_BEACON_INTERVAL 1800000L // Fixed beacon interwal (when GPS is disabled and FIXED_BEACON_EN is enabled) 30min default
|
#define FIX_BEACON_INTERVAL 1800000L // Fixed beacon interwal (when GPS is disabled and FIXED_BEACON_EN is enabled) 30min default
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
#include "taskWebServer.h"
|
||||||
|
/**
|
||||||
|
* @see board_build.embed_txtfiles in platformio.ini
|
||||||
|
*/
|
||||||
|
extern const char web_index_html[] asm("_binary_data_embed_index_html_out_start");
|
||||||
|
extern const char web_index_html_end[] asm("_binary_data_embed_index_html_out_end");
|
||||||
|
extern const char web_style_css[] asm("_binary_data_embed_style_css_out_start");
|
||||||
|
extern const char web_style_css_end[] asm("_binary_data_embed_style_css_out_end");
|
||||||
|
extern const char web_js_js[] asm("_binary_data_embed_js_js_out_start");
|
||||||
|
extern const char web_js_js_end[] asm("_binary_data_embed_js_js_out_end");
|
||||||
|
|
||||||
|
|
||||||
|
String apSSID = "";
|
||||||
|
String apPassword = "xxxxxxxxxx";
|
||||||
|
WebServer server(80);
|
||||||
|
Preferences preferences;
|
||||||
|
|
||||||
|
void sendCacheHeader() { server.sendHeader("Cache-Control", "max-age=3600"); }
|
||||||
|
void sendGzipHeader() { server.sendHeader("Content-Encoding", "gzip"); }
|
||||||
|
|
||||||
|
String jsonEscape(String s){
|
||||||
|
s.replace("\"", "\\\"");
|
||||||
|
s.replace("\\", "\\\\");
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
String jsonLineFromPreferenceString(const char *preferenceName, bool last=false){
|
||||||
|
return String("\"") + preferenceName + "\":\"" + jsonEscape(preferences.getString(preferenceName)) + (last ? + R"(")" : + R"(",)");
|
||||||
|
}
|
||||||
|
String jsonLineFromPreferenceBool(const char *preferenceName, bool last=false){
|
||||||
|
return String("\"") + preferenceName + "\":" + (preferences.getBool(preferenceName) ? "true" : "false") + (last ? + R"()" : + R"(,)");
|
||||||
|
}
|
||||||
|
String jsonLineFromPreferenceInt(const char *preferenceName, bool last=false){
|
||||||
|
return String("\"") + preferenceName + "\":" + (preferences.getInt(preferenceName)) + (last ? + R"()" : + R"(,)");
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_NotFound(){
|
||||||
|
sendCacheHeader();
|
||||||
|
server.send(404, "text/plain", "Not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_Index() {
|
||||||
|
sendGzipHeader();
|
||||||
|
server.send_P(200, "text/html", web_index_html, web_index_html_end - web_index_html);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_Style() {
|
||||||
|
sendCacheHeader();
|
||||||
|
sendGzipHeader();
|
||||||
|
server.send_P(200, "text/css", web_style_css, web_style_css_end - web_style_css);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_Js() {
|
||||||
|
sendCacheHeader();
|
||||||
|
sendGzipHeader();
|
||||||
|
server.send_P(200, "text/javascript", web_js_js, web_js_js_end-web_js_js);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_ScanWifi() {
|
||||||
|
String listResponse = R"(<label for="networks_found_list">Networks found:</label><select class="u-full-width" id="networks_found_list">)";
|
||||||
|
int n = WiFi.scanNetworks();
|
||||||
|
listResponse += "<option value=\"\">Select Network</option>";
|
||||||
|
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
listResponse += "<option value=\""+WiFi.SSID(i)+"\">" + WiFi.SSID(i) + "</option>";
|
||||||
|
}
|
||||||
|
listResponse += "</select>";
|
||||||
|
server.send(200,"text/html", listResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_SaveWifiCfg() {
|
||||||
|
if (!server.hasArg("wifi_ssid") || !server.hasArg("wifi_password")){
|
||||||
|
server.send(500, "text/plain", "Invalid request");
|
||||||
|
}
|
||||||
|
if (!server.arg("wifi_ssid").length() || !server.arg("wifi_password").length()){
|
||||||
|
server.send(403, "text/plain", "Empty SSID or Password");
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences.putString("wifi_ssid", server.arg("wifi_ssid"));
|
||||||
|
preferences.putString("wifi_password", server.arg("wifi_password"));
|
||||||
|
|
||||||
|
server.sendHeader("Location", "/");
|
||||||
|
server.send(302,"text/html", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_Reboot() {
|
||||||
|
server.sendHeader("Location", "/");
|
||||||
|
server.send(302,"text/html", "");
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_Restore() {
|
||||||
|
server.sendHeader("Location", "/");
|
||||||
|
server.send(302,"text/html", "");
|
||||||
|
preferences.clear();
|
||||||
|
preferences.end();
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_Cfg() {
|
||||||
|
String jsonData = "{";
|
||||||
|
jsonData += R"("wifi_ssid":")" + jsonEscape(preferences.getString("wifi_ssid")) + R"(",)";
|
||||||
|
jsonData += R"("wifi_password":")" + jsonEscape((preferences.getString("wifi_password").isEmpty() ? String("") : "*")) + R"(",)";
|
||||||
|
jsonData += jsonLineFromPreferenceString(PREF_APRS_CALLSIGN);
|
||||||
|
jsonData += jsonLineFromPreferenceString(PREF_APRS_RELAY_PATH);
|
||||||
|
jsonData += jsonLineFromPreferenceString(PREF_APRS_SYMBOL_TABLE);
|
||||||
|
jsonData += jsonLineFromPreferenceString(PREF_APRS_SYMBOL);
|
||||||
|
jsonData += jsonLineFromPreferenceString(PREF_APRS_COMMENT);
|
||||||
|
jsonData += jsonLineFromPreferenceString(PREF_APRS_LATITUDE_PRESET);
|
||||||
|
jsonData += jsonLineFromPreferenceString(PREF_APRS_LONGITUDE_PRESET);
|
||||||
|
jsonData += jsonLineFromPreferenceInt(PREF_APRS_FIXED_BEACON_INTERVAL_PRESET);
|
||||||
|
jsonData += jsonLineFromPreferenceBool(PREF_APRS_SHOW_BATTERY);
|
||||||
|
jsonData += jsonLineFromPreferenceBool(PREF_APRS_FIXED_BEACON_PRESET);
|
||||||
|
jsonData += jsonLineFromPreferenceBool(PREF_APRS_SHOW_ALTITUDE, true);
|
||||||
|
jsonData += "}";
|
||||||
|
server.send(200,"application/json", jsonData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_SaveAPRSCfg() {
|
||||||
|
if (server.hasArg(PREF_APRS_CALLSIGN) && !server.arg(PREF_APRS_CALLSIGN).isEmpty()){
|
||||||
|
preferences.putString(PREF_APRS_CALLSIGN, server.arg(PREF_APRS_CALLSIGN));
|
||||||
|
}
|
||||||
|
if (server.hasArg(PREF_APRS_SYMBOL_TABLE) && !server.arg(PREF_APRS_SYMBOL_TABLE).isEmpty()){
|
||||||
|
preferences.putString(PREF_APRS_SYMBOL_TABLE, server.arg(PREF_APRS_SYMBOL_TABLE));
|
||||||
|
}
|
||||||
|
if (server.hasArg(PREF_APRS_SYMBOL) && !server.arg(PREF_APRS_SYMBOL).isEmpty()){
|
||||||
|
preferences.putString(PREF_APRS_SYMBOL, server.arg(PREF_APRS_SYMBOL));
|
||||||
|
}
|
||||||
|
if (server.hasArg(PREF_APRS_RELAY_PATH)){
|
||||||
|
preferences.putString(PREF_APRS_RELAY_PATH, server.arg(PREF_APRS_RELAY_PATH));
|
||||||
|
}
|
||||||
|
if (server.hasArg(PREF_APRS_COMMENT)){
|
||||||
|
preferences.putString(PREF_APRS_COMMENT, server.arg(PREF_APRS_COMMENT));
|
||||||
|
}
|
||||||
|
if (server.hasArg(PREF_APRS_LATITUDE_PRESET)){
|
||||||
|
preferences.putString(PREF_APRS_LATITUDE_PRESET, server.arg(PREF_APRS_LATITUDE_PRESET));
|
||||||
|
}
|
||||||
|
if (server.hasArg(PREF_APRS_FIXED_BEACON_INTERVAL_PRESET)){
|
||||||
|
preferences.putInt(PREF_APRS_FIXED_BEACON_INTERVAL_PRESET, server.arg(PREF_APRS_FIXED_BEACON_INTERVAL_PRESET).toInt());
|
||||||
|
}
|
||||||
|
if (server.hasArg(PREF_APRS_LONGITUDE_PRESET)){
|
||||||
|
preferences.putString(PREF_APRS_LONGITUDE_PRESET, server.arg(PREF_APRS_LONGITUDE_PRESET));
|
||||||
|
}
|
||||||
|
preferences.putBool(PREF_APRS_SHOW_BATTERY, server.hasArg(PREF_APRS_SHOW_BATTERY));
|
||||||
|
preferences.putBool(PREF_APRS_SHOW_ALTITUDE, server.hasArg(PREF_APRS_SHOW_ALTITUDE));
|
||||||
|
preferences.putBool(PREF_APRS_FIXED_BEACON_PRESET, server.hasArg(PREF_APRS_FIXED_BEACON_PRESET));
|
||||||
|
|
||||||
|
|
||||||
|
server.sendHeader("Location", "/");
|
||||||
|
server.send(302,"text/html", "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[[noreturn]] void taskWebServer(void *parameter) {
|
||||||
|
auto *webServerCfg = (tWebServerCfg*)parameter;
|
||||||
|
apSSID = webServerCfg->callsign + " AP";
|
||||||
|
|
||||||
|
server.on("/", handle_Index);
|
||||||
|
server.on("/favicon.ico", handle_NotFound);
|
||||||
|
server.on("/style.css", handle_Style);
|
||||||
|
server.on("/js.js", handle_Js);
|
||||||
|
server.on("/scan_wifi", handle_ScanWifi);
|
||||||
|
server.on("/save_wifi_cfg", handle_SaveWifiCfg);
|
||||||
|
server.on("/reboot", handle_Reboot);
|
||||||
|
server.on("/cfg", handle_Cfg);
|
||||||
|
server.on("/save_aprs_cfg", handle_SaveAPRSCfg);
|
||||||
|
server.on("/restore", handle_Restore);
|
||||||
|
server.onNotFound(handle_NotFound);
|
||||||
|
|
||||||
|
String wifi_password = preferences.getString("wifi_password");
|
||||||
|
String wifi_ssid = preferences.getString("wifi_ssid");
|
||||||
|
if (!wifi_password.length() || !wifi_ssid.length()){
|
||||||
|
WiFi.softAP(apSSID.c_str(), apPassword.c_str());
|
||||||
|
} else {
|
||||||
|
WiFi.begin(wifi_ssid.c_str(), wifi_password.c_str());
|
||||||
|
Serial.println("Connecting to" + wifi_ssid);
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
Serial.println("Not connected");
|
||||||
|
vTaskDelay(500/portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
if (MDNS.begin(webServerCfg->callsign.c_str())) {
|
||||||
|
MDNS.addService("http", "tcp", 80);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true){
|
||||||
|
server.handleClient();
|
||||||
|
vTaskDelay(5/portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
FILENAME_BUILDNO = '.pio/versioning'
|
||||||
|
FILENAME_VERSION_H = 'include/version.h'
|
||||||
|
version = 'v0.1.'
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
build_no = 0
|
||||||
|
try:
|
||||||
|
with open(FILENAME_BUILDNO) as f:
|
||||||
|
build_no = int(f.readline()) + 1
|
||||||
|
except:
|
||||||
|
print('Starting build number from 1..')
|
||||||
|
build_no = 1
|
||||||
|
with open(FILENAME_BUILDNO, 'w+') as f:
|
||||||
|
f.write(str(build_no))
|
||||||
|
print('Build number: {}'.format(build_no))
|
||||||
|
|
||||||
|
version_string = "{} - {}".format(version+str(build_no), datetime.datetime.now())
|
||||||
|
hf = """
|
||||||
|
#ifndef BUILD_NUMBER
|
||||||
|
#define BUILD_NUMBER "{}"
|
||||||
|
#endif
|
||||||
|
#ifndef VERSION
|
||||||
|
#define VERSION "{}"
|
||||||
|
#endif
|
||||||
|
#ifndef VERSION_SHORT
|
||||||
|
#define VERSION_SHORT "{}"
|
||||||
|
#endif
|
||||||
|
""".format(build_no, version_string, version+str(build_no))
|
||||||
|
with open(FILENAME_VERSION_H, 'w+') as f:
|
||||||
|
f.write(hf)
|
||||||
|
|
||||||
|
with open("data_embed/index.html", "r") as f:
|
||||||
|
index_html_content = f.read()
|
||||||
|
|
||||||
|
index_html_content = index_html_content.replace('<!--VERSION-->', version_string)
|
||||||
|
|
||||||
|
with open("data_embed/index.html.out", "w") as f:
|
||||||
|
f.write(index_html_content)
|
|
@ -0,0 +1,13 @@
|
||||||
|
import gzip
|
||||||
|
assets_list = {
|
||||||
|
'data_embed/index.html.out': 'data_embed/index.html.out',
|
||||||
|
'data_embed/js.js': 'data_embed/js.js.out',
|
||||||
|
'data_embed/style.css': 'data_embed/style.css.out',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for src_file_name, out_file_name in assets_list.items():
|
||||||
|
with open(src_file_name, 'rb') as f:
|
||||||
|
content = f.read()
|
||||||
|
with open(out_file_name, 'wb') as f:
|
||||||
|
f.write(gzip.compress(content, compresslevel=9))
|
Loading…
Reference in New Issue