Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ef86500db | ||
|
|
0d2ff764ea |
No files matched your search
@@ -1,46 +1,78 @@
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
tags:
|
||||||
- "*"
|
- "v*"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: release-${{ gitea.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
env:
|
env:
|
||||||
RUNNER_TOOL_CACHE: /toolcache
|
RUNNER_TOOL_CACHE: /toolcache
|
||||||
PLATFORMIO_BUILD_CACHE_DIR: ~/.platformio/.build_cache
|
PLATFORMIO_BUILD_CACHE_DIR: ~/.platformio/.build_cache
|
||||||
PLATFORMIO_CACHE_DIR: ~/.platformio/.cachedir
|
PLATFORMIO_CACHE_DIR: ~/.platformio/.cachedir
|
||||||
name: Build
|
name: Build ${{ matrix.environment }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
environment:
|
||||||
|
- heltec_wifi_lora_32_V3_sailplane
|
||||||
|
- heltec_wifi_lora_32_V3_winde
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: catthehacker/ubuntu:act-latest
|
container: catthehacker/ubuntu:act-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Cache
|
- name: Cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
~/.cache/pip
|
~/.cache/pip
|
||||||
~/.platformio/.cache
|
~/.platformio/.cache
|
||||||
~/.platformio/.build_cache
|
~/.platformio/.build_cache
|
||||||
~/.platformio/.cachedir
|
~/.platformio/.cachedir
|
||||||
key: ${{ runner.os }}-pio
|
key: ${{ runner.os }}-pio-6.1.18-${{ hashFiles('platformio.ini', 'extra_script.py') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pio-6.1.18-
|
||||||
|
${{ runner.os }}-pio-
|
||||||
- name: Set up python
|
- name: Set up python
|
||||||
uses: actions/setup-python@v5
|
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
||||||
with:
|
with:
|
||||||
python-version: "3.14.0"
|
python-version: "3.14.0"
|
||||||
architecture: "x64"
|
architecture: "x64"
|
||||||
- name: Install PlatformIO
|
- name: Install PlatformIO
|
||||||
run: python3 -m pip install platformio==6.1.18
|
run: python3 -m pip install platformio==6.1.18
|
||||||
- name: Build firmwares
|
- name: Validate version and required files
|
||||||
run: FIRMWARE_VERSION=${{gitea.ref_name}} platformio run
|
env:
|
||||||
- name: Archive
|
TAG_NAME: ${{ gitea.ref_name }}
|
||||||
uses: christopherhx/gitea-upload-artifact@v4
|
run: |
|
||||||
|
VERSION="${TAG_NAME#v}"
|
||||||
|
grep -qE "^## (v)?${VERSION} " CHANGELOG.md
|
||||||
|
test -s LICENSE
|
||||||
|
test -s THIRD_PARTY_NOTICES.md
|
||||||
|
- name: Static analysis
|
||||||
|
run: python3 -m platformio check --environment "${{ matrix.environment }}"
|
||||||
|
- name: Build firmware
|
||||||
|
env:
|
||||||
|
FIRMWARE_VERSION: ${{ gitea.ref_name }}
|
||||||
|
run: python3 -m platformio run --environment "${{ matrix.environment }}"
|
||||||
|
- name: Verify firmware and create checksum
|
||||||
|
run: |
|
||||||
|
test -n "$(find ".pio/build/${{ matrix.environment }}" -maxdepth 1 -type f -name 'firmware_*.bin' -print -quit)
|
||||||
|
sha256sum ".pio/build/${{ matrix.environment }}"/firmware_*.bin > "firmware-${{ matrix.environment }}.sha256"
|
||||||
|
- name: Archive firmware
|
||||||
|
uses: christopherhx/gitea-upload-artifact@62ac910c5d3dfa85c7cb2df15afe2e342b2407c2 # v4
|
||||||
with:
|
with:
|
||||||
name: firmware
|
name: firmware-${{ matrix.environment }}
|
||||||
path: .pio/build/*/firmware_*.bin
|
path: |
|
||||||
|
.pio/build/${{ matrix.environment }}/firmware_*.bin
|
||||||
|
firmware-${{ matrix.environment }}.sha256
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
# if: startsWith(github.event.ref, 'refs/tags/v')
|
if: startsWith(gitea.ref, 'refs/tags/v')
|
||||||
needs: build
|
needs: build
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
@@ -48,17 +80,29 @@ jobs:
|
|||||||
container: catthehacker/ubuntu:act-latest
|
container: catthehacker/ubuntu:act-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo for CHANGELOG
|
- name: Checkout repo for CHANGELOG
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Download artifacts
|
- name: Download Sailplane artifact
|
||||||
uses: christopherhx/gitea-download-artifact@v4
|
uses: christopherhx/gitea-download-artifact@75635f32b4c1c41c4b3d64e8f85210112ed4c9c7 # v4
|
||||||
with:
|
with:
|
||||||
name: firmware
|
name: firmware-heltec_wifi_lora_32_V3_sailplane
|
||||||
path: firmware
|
path: firmware/sailplane
|
||||||
# - name: Display structure of downloaded files
|
- name: Download Winde artifact
|
||||||
# run: ls -R
|
uses: christopherhx/gitea-download-artifact@75635f32b4c1c41c4b3d64e8f85210112ed4c9c7 # v4
|
||||||
- name: release
|
with:
|
||||||
uses: akkuman/gitea-release-action@v1
|
name: firmware-heltec_wifi_lora_32_V3_winde
|
||||||
|
path: firmware/winde
|
||||||
|
- name: Verify release assets
|
||||||
|
run: |
|
||||||
|
test -n "$(find firmware -type f -name 'firmware_*.bin' -print -quit)"
|
||||||
|
test -n "$(find firmware -type f -name '*.sha256' -print -quit)"
|
||||||
|
test -s LICENSE
|
||||||
|
test -s THIRD_PARTY_NOTICES.md
|
||||||
|
- name: Create release
|
||||||
|
uses: akkuman/gitea-release-action@5a83c90484ef4355121df5eb60558c8ce66e81ac # v1
|
||||||
with:
|
with:
|
||||||
files: |-
|
files: |-
|
||||||
**/firmware_*.bin
|
firmware/**/*.bin
|
||||||
|
firmware/**/*.sha256
|
||||||
|
LICENSE
|
||||||
|
THIRD_PARTY_NOTICES.md
|
||||||
body_path: "CHANGELOG.md"
|
body_path: "CHANGELOG.md"
|
||||||
@@ -1,5 +1,23 @@
|
|||||||
CHANGELOG
|
CHANGELOG
|
||||||
|
|
||||||
|
## 0.0.7 (28.08.2026)
|
||||||
|
+ Webinterface über eigenen WLAN-Access-Point ergänzt
|
||||||
|
+ Persistente Konfiguration für WLAN-Name, WLAN-Passwort und Callsign
|
||||||
|
+ Lizenzinformationen für Projektcode und Drittanbieterbibliotheken ergänzt
|
||||||
|
+ Firmware-Upload über das Webinterface für beide Firmwarevarianten ergänzt
|
||||||
|
|
||||||
|
### Segeflug Modul
|
||||||
|
+ Einstellbare minimale und maximale Schleppgeschwindigkeit
|
||||||
|
+ Einstellbare maximale Übertragungszeit, Standardwert 90 Sekunden
|
||||||
|
+ Geladene Einstellungen beim Programmstart verwendet
|
||||||
|
+ Sensorinitialisierung und Messwertverarbeitung robustifiziert
|
||||||
|
|
||||||
|
### Winden Modul
|
||||||
|
+ Einstellbare WLAN-Konfiguration über das Webinterface
|
||||||
|
+ Standard-WLAN-Name `Winde-Telemetry`
|
||||||
|
+ Initialisierung von Servo und LED-Ring korrigiert
|
||||||
|
+ NMEA-Nachrichtenprüfung und Fehlerbehandlung beim Empfang verbessert
|
||||||
|
|
||||||
## 0.0.6 (18.01.2025)
|
## 0.0.6 (18.01.2025)
|
||||||
+ Anpassung Programmablaufplan
|
+ Anpassung Programmablaufplan
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Winden-Telemetry contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -4,6 +4,12 @@
|
|||||||
|
|
||||||
# Winden-Telemetry
|
# Winden-Telemetry
|
||||||
|
|
||||||
|
Der eigene Projektcode steht unter der MIT-Lizenz. Die verwendeten
|
||||||
|
Drittanbieterbibliotheken bleiben unter ihren jeweiligen Original-Lizenzen.
|
||||||
|
Eine Übersicht der Komponenten, Versionen und Lizenzbedingungen steht in
|
||||||
|
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md); der vollständige Lizenztext
|
||||||
|
für den Projektcode steht in [LICENSE](LICENSE).
|
||||||
|
|
||||||
|
|
||||||
Übertragung der IAS des Segelflugzeuges an die Winde
|
Übertragung der IAS des Segelflugzeuges an die Winde
|
||||||
|
|
||||||
@@ -19,16 +25,37 @@
|
|||||||
### Features:
|
### Features:
|
||||||
- [x] LORA zum Übertragen
|
- [x] LORA zum Übertragen
|
||||||
- [x] Airspeed via differenz Drucksensor
|
- [x] Airspeed via differenz Drucksensor
|
||||||
- [ ] Webinterface
|
- [x] Webinterface über eigenen Access Point
|
||||||
- [ ] min/max speed einstellbar
|
- [x] min/max speed per Webinterface einstellbar
|
||||||
- [ ] Kennzeichen einstellbar
|
- [x] Kennzeichen per Webinterface einstellbar
|
||||||
|
- [x] maximale Übertragungszeit per Webinterface einstellbar (Standard: 90 Sekunden)
|
||||||
|
- [x] Firmware-Upload per Webinterface für beide Firmwarevarianten
|
||||||
- [x] Analoge Anzeige in der Winde
|
- [x] Analoge Anzeige in der Winde
|
||||||
- [x] Farbige LEDs für Limits
|
- [x] Farbige LEDs für Limits
|
||||||
- [x] Übertragungszeit Begrenzen
|
- [x] Übertragungszeit Begrenzen
|
||||||
- [ ] Übertragungszeit einstellbar
|
|
||||||
- [ ] Übertragung Rundumleuchten Signal an Start
|
- [ ] Übertragung Rundumleuchten Signal an Start
|
||||||
- [x] Luftdrucksensor für Höhe und Vario
|
- [x] Luftdrucksensor für Höhe und Vario
|
||||||
|
|
||||||
|
### Webinterface und Firmware-Update
|
||||||
|
|
||||||
|
Beide Firmwarevarianten starten einen eigenen WLAN-Access-Point. Der
|
||||||
|
voreingestellte WLAN-Name ist bei Sailplane `Sailplane-D1234` und bei der
|
||||||
|
Winde `Winde-Telemetry`.
|
||||||
|
|
||||||
|
- Passwort: `telemetry`
|
||||||
|
- Webadresse: `http://192.168.4.1/`
|
||||||
|
|
||||||
|
Im Webinterface können WLAN-Name und WLAN-Passwort sowie Callsign, minimale und maximale Geschwindigkeit
|
||||||
|
gespeichert werden. Die Werte bleiben nach einem Neustart erhalten. Die
|
||||||
|
Sailplane-Firmware lädt sie beim Start und verwendet sie für die Telemetrie,
|
||||||
|
die Schlepp-Erkennung und die maximale Übertragungszeit. Die Winden-Firmware verwendet die gespeicherten
|
||||||
|
Grenzen für die Anzeige beim Start; empfangene Telemetriegrenzen werden danach
|
||||||
|
weiterhin aus dem LoRa-Paket übernommen.
|
||||||
|
|
||||||
|
Für ein Firmware-Update die zur jeweiligen Hardware passende `.bin`-Datei aus
|
||||||
|
`.pio/build/<environment>/` auswählen. Nach erfolgreichem Upload startet das
|
||||||
|
Gerät automatisch neu.
|
||||||
|
|
||||||
## Aufbau
|
## Aufbau
|
||||||
|
|
||||||
Pin Layout Heltec WiFi LoRa (v3)
|
Pin Layout Heltec WiFi LoRa (v3)
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Third-party notices
|
||||||
|
|
||||||
|
This project contains or links to the following third-party software. The
|
||||||
|
listed versions are the versions resolved by PlatformIO on 2026-08-28.
|
||||||
|
Original license texts and copyright notices must be retained when the
|
||||||
|
corresponding software is redistributed.
|
||||||
|
|
||||||
|
## Direct and transitive library dependencies
|
||||||
|
|
||||||
|
| Component | Version | Used by | License | Source |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| U8g2 | 2.36.18 | Sailplane, Winde | BSD-2-Clause; bundled fonts may have additional licenses | https://github.com/olikraus/u8g2 |
|
||||||
|
| RadioLib | 7.6.0 | Sailplane, Winde | MIT | https://github.com/jgromes/RadioLib |
|
||||||
|
| ArduinoJson | 7.4.3 | Sailplane, Winde | MIT | https://github.com/bblanchon/ArduinoJson |
|
||||||
|
| Bolder Flight Systems Airdata Calculations | 4.0.0 | Sailplane | MIT | https://github.com/bolderflight/airdata_calculations |
|
||||||
|
| Bolder Flight Systems MS4525 | 1.1.3 | Sailplane | MIT | https://github.com/bolderflight/ms4525 |
|
||||||
|
| Bolder Flight Systems Unit Conversions | 5.0.0 | Sailplane | MIT | https://github.com/bolderflight/units |
|
||||||
|
| Adafruit BMP085 Library | 1.2.4 | Sailplane | BSD | https://github.com/adafruit/Adafruit-BMP085-Library |
|
||||||
|
| Adafruit BusIO | 1.17.4 | Sailplane, transitive | MIT | https://github.com/adafruit/Adafruit_BusIO |
|
||||||
|
| Adafruit Unified Sensor | 1.1.15 | Sailplane, transitive | Apache-2.0 | https://github.com/adafruit/Adafruit_Sensor |
|
||||||
|
| Adafruit NeoPixel | 1.15.4 | Winde | LGPL-3.0-or-later | https://github.com/adafruit/Adafruit_NeoPixel |
|
||||||
|
| ESP32Servo | 3.1.3 | Winde | LGPL-2.1-or-later | https://github.com/madhephaestos/ESP32Servo |
|
||||||
|
|
||||||
|
## Build framework
|
||||||
|
|
||||||
|
| Component | Version | License | Source |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| Arduino core for ESP32 | 3.20017.241212+sha.dcc1105b | LGPL-2.1-or-later | https://github.com/espressif/arduino-esp32 |
|
||||||
|
|
||||||
|
The PlatformIO platform and build tools are development dependencies. Their
|
||||||
|
licenses are distributed with their respective PlatformIO packages and are
|
||||||
|
not relicensed by this project.
|
||||||
|
|
||||||
|
## License compatibility
|
||||||
|
|
||||||
|
The source code in this repository is licensed under the MIT License in
|
||||||
|
`LICENSE`. MIT is compatible with the MIT, BSD, Apache-2.0 and LGPL components
|
||||||
|
listed above. The LGPL components remain under their original licenses; this
|
||||||
|
project does not change or relicense them.
|
||||||
|
|
||||||
|
For a release containing compiled firmware, distribute this file together
|
||||||
|
with `LICENSE` and retain the copyright and license notices supplied by the
|
||||||
|
third-party components. U8g2 fonts must be checked separately when changing
|
||||||
|
fonts, because their licensing terms can differ from the U8g2 library code.
|
||||||
@@ -6,3 +6,9 @@ build_tag = env['PIOENV']
|
|||||||
version_tag = os.getenv("FIRMWARE_VERSION")
|
version_tag = os.getenv("FIRMWARE_VERSION")
|
||||||
|
|
||||||
env.Replace(PROGNAME="firmware_%s_%s" % (build_tag, version_tag))
|
env.Replace(PROGNAME="firmware_%s_%s" % (build_tag, version_tag))
|
||||||
|
|
||||||
|
# include toolchain paths
|
||||||
|
env.Replace(COMPILATIONDB_INCLUDE_TOOLCHAIN=True)
|
||||||
|
|
||||||
|
# override compilation DB path
|
||||||
|
env.Replace(COMPILATIONDB_PATH=os.path.join("$BUILD_DIR", "compile_commands.json"))
|
||||||
+40
-15
@@ -11,12 +11,19 @@ bfs::Ms4525do pres;
|
|||||||
Adafruit_BMP085 bmp;
|
Adafruit_BMP085 bmp;
|
||||||
|
|
||||||
float pressure_avg[10];
|
float pressure_avg[10];
|
||||||
float basicaltitude;
|
float basicaltitude = 0.0f;
|
||||||
void init_2ndi2c(){
|
bool pressure_sensor_ready = false;
|
||||||
Wire1.begin(dp_sda, dp_scl);
|
|
||||||
Wire1.setClock(400000);
|
bool init_2ndi2c(){
|
||||||
|
if (!Wire1.begin(dp_sda, dp_scl))
|
||||||
|
{
|
||||||
|
Serial.println("Error starting I2C");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
void init_airspeed_sensor(void)
|
Wire1.setClock(400000);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool init_airspeed_sensor(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -27,10 +34,9 @@ void init_airspeed_sensor(void)
|
|||||||
if (!pres.Begin())
|
if (!pres.Begin())
|
||||||
{
|
{
|
||||||
Serial.println("Error communicating with sensor");
|
Serial.println("Error communicating with sensor");
|
||||||
while (1)
|
return false;
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_airspeed_kmh(void)
|
int get_airspeed_kmh(void)
|
||||||
@@ -51,10 +57,22 @@ float get_airspeed(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void init_pressure_sensor(void)
|
bool init_pressure_sensor(void)
|
||||||
{
|
{
|
||||||
bmp.begin(BMP085_ULTRAHIGHRES, &Wire1);
|
if (!bmp.begin(BMP085_ULTRAHIGHRES, &Wire1))
|
||||||
|
{
|
||||||
|
Serial.println("Error communicating with pressure sensor");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
basicaltitude=bmp.readPressure();
|
basicaltitude=bmp.readPressure();
|
||||||
|
if (basicaltitude <= 0.0f)
|
||||||
|
{
|
||||||
|
Serial.println("Invalid initial pressure");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (float &sample : pressure_avg)
|
||||||
|
sample = basicaltitude;
|
||||||
|
pressure_sensor_ready = true;
|
||||||
Serial.print("Pressure = ");
|
Serial.print("Pressure = ");
|
||||||
Serial.print(basicaltitude);
|
Serial.print(basicaltitude);
|
||||||
Serial.println(" Pa");
|
Serial.println(" Pa");
|
||||||
@@ -64,21 +82,28 @@ void init_pressure_sensor(void)
|
|||||||
Serial.print("Altitude = ");
|
Serial.print("Altitude = ");
|
||||||
Serial.print(get_altitude(basicaltitude));
|
Serial.print(get_altitude(basicaltitude));
|
||||||
Serial.println(" meters");
|
Serial.println(" meters");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
float get_pressure()
|
float get_pressure()
|
||||||
{
|
{
|
||||||
|
if (!pressure_sensor_ready)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
float pressure;
|
float pressure;
|
||||||
pressure = bmp.readPressure();
|
pressure = bmp.readPressure();
|
||||||
memcpy(pressure_avg, &pressure_avg[1], sizeof(pressure_avg) - sizeof(int));
|
if (pressure <= 0.0f)
|
||||||
|
return pressure_avg[9];
|
||||||
|
|
||||||
|
memmove(pressure_avg, &pressure_avg[1], sizeof(pressure_avg) - sizeof(pressure_avg[0]));
|
||||||
pressure_avg[9] = pressure;
|
pressure_avg[9] = pressure;
|
||||||
return pressure;
|
return pressure;
|
||||||
}
|
}
|
||||||
|
|
||||||
float get_pressure_avg(void)
|
float get_pressure_avg(void)
|
||||||
{
|
{
|
||||||
|
float total = 0.0f;
|
||||||
int i;
|
int i;
|
||||||
float total;
|
|
||||||
for (i = 0; i <10; i++)
|
for (i = 0; i <10; i++)
|
||||||
{
|
{
|
||||||
total = total + pressure_avg[i];
|
total = total + pressure_avg[i];
|
||||||
@@ -97,14 +122,14 @@ float get_vario_avg(void)
|
|||||||
float vario;
|
float vario;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
float total;
|
float total = 0.0f;
|
||||||
for (i = 0; i <9; i++)
|
for (i = 0; i <9; i++)
|
||||||
{
|
{
|
||||||
int n=i+1;
|
int n=i+1;
|
||||||
vario = get_altitude(pressure_avg[n]) - get_altitude(pressure_avg[i]);
|
vario = get_altitude(pressure_avg[n]) - get_altitude(pressure_avg[i]);
|
||||||
total = total + vario;
|
total = total + vario;
|
||||||
}
|
}
|
||||||
return (total / 10);
|
return (total / 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
float get_altitude(float pressure)
|
float get_altitude(float pressure)
|
||||||
@@ -115,5 +140,5 @@ float get_altitude(float pressure)
|
|||||||
}
|
}
|
||||||
|
|
||||||
float get_altitude_diff(void){
|
float get_altitude_diff(void){
|
||||||
return bmp.readPressure() - basicaltitude;
|
return get_altitude(pressure_avg[9]) - get_altitude(basicaltitude);
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
#ifndef WINDENTELEMETRY_AIRSPEED_H
|
#ifndef WINDENTELEMETRY_AIRSPEED_H
|
||||||
#define WINDENTELEMETRY_AIRSPEED_H
|
#define WINDENTELEMETRY_AIRSPEED_H
|
||||||
|
|
||||||
void init_2ndi2c(void);
|
bool init_2ndi2c(void);
|
||||||
void init_airspeed_sensor(void);
|
bool init_airspeed_sensor(void);
|
||||||
|
|
||||||
int get_airspeed_kmh(void);
|
int get_airspeed_kmh(void);
|
||||||
/*!
|
/*!
|
||||||
@@ -10,7 +10,7 @@ int get_airspeed_kmh(void);
|
|||||||
*/
|
*/
|
||||||
float get_airspeed(void);
|
float get_airspeed(void);
|
||||||
|
|
||||||
void init_pressure_sensor(void);
|
bool init_pressure_sensor(void);
|
||||||
float get_pressure(void);
|
float get_pressure(void);
|
||||||
float get_pressure_adv(void);
|
float get_pressure_adv(void);
|
||||||
float get_altitude(float pressure);
|
float get_altitude(float pressure);
|
||||||
|
|||||||
@@ -0,0 +1,242 @@
|
|||||||
|
#include "webinterface.h"
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <Preferences.h>
|
||||||
|
#include <Update.h>
|
||||||
|
#include <WebServer.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr char default_access_point_password[] = "telemetry";
|
||||||
|
constexpr char settings_namespace[] = "telemetry";
|
||||||
|
constexpr char default_callsign[] = "D1234";
|
||||||
|
constexpr int default_min_speed = 80;
|
||||||
|
constexpr int default_max_speed = 150;
|
||||||
|
constexpr unsigned int default_active_time_seconds = 90;
|
||||||
|
|
||||||
|
String default_access_point_name()
|
||||||
|
{
|
||||||
|
#ifdef DEVICE_SAILPLANE
|
||||||
|
return String("Sailplane-") + default_callsign;
|
||||||
|
#else
|
||||||
|
return "Winde-Telemetry";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
WebServer server(80);
|
||||||
|
Preferences preferences;
|
||||||
|
TelemetrySettings *active_settings = nullptr;
|
||||||
|
bool restart_after_update = false;
|
||||||
|
bool update_failed = false;
|
||||||
|
bool access_point_restart_pending = false;
|
||||||
|
|
||||||
|
String html_escape(const String &value)
|
||||||
|
{
|
||||||
|
String escaped = value;
|
||||||
|
escaped.replace("&", "&");
|
||||||
|
escaped.replace("<", "<");
|
||||||
|
escaped.replace(">", ">");
|
||||||
|
escaped.replace("\"", """);
|
||||||
|
escaped.replace("'", "'");
|
||||||
|
return escaped;
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_page(const String &message = String())
|
||||||
|
{
|
||||||
|
String page;
|
||||||
|
page.reserve(2600);
|
||||||
|
page += F("<!doctype html><html lang='de'><head><meta charset='utf-8'>"
|
||||||
|
"<meta name='viewport' content='width=device-width,initial-scale=1'>"
|
||||||
|
"<title>Winden-Telemetry</title><style>"
|
||||||
|
"body{font-family:sans-serif;max-width:38rem;margin:2rem auto;padding:0 1rem}"
|
||||||
|
"label{display:block;margin-top:1rem}input{box-sizing:border-box;width:100%;padding:.6rem;font-size:1rem}"
|
||||||
|
"button{margin-top:1rem;padding:.65rem 1rem;font-size:1rem}"
|
||||||
|
".msg{padding:.6rem;background:#e5f4e8}small{color:#555}"
|
||||||
|
"</style></head><body><h1>Winden-Telemetry</h1>");
|
||||||
|
if (message.length() > 0)
|
||||||
|
{
|
||||||
|
page += F("<p class='msg'>");
|
||||||
|
page += html_escape(message);
|
||||||
|
page += F("</p>");
|
||||||
|
}
|
||||||
|
page += F("<form method='post' action='/settings'>"
|
||||||
|
"<label>WLAN-Name<input name='ap_name' maxlength='32' required value='");
|
||||||
|
page += html_escape(active_settings->access_point_name);
|
||||||
|
page += F("'></label><label>WLAN-Passwort<input name='ap_password' type='password' minlength='8' maxlength='63' required value='");
|
||||||
|
page += html_escape(active_settings->access_point_password);
|
||||||
|
page += F("'></label><label>Callsign<input name='callsign' maxlength='16' required value='");
|
||||||
|
page += html_escape(active_settings->callsign);
|
||||||
|
page += F("'></label><label>Min Speed (km/h)<input name='min' type='number' min='0' max='300' required value='");
|
||||||
|
page += String(active_settings->min_speed);
|
||||||
|
page += F("'></label><label>Max Speed (km/h)<input name='max' type='number' min='1' max='300' required value='");
|
||||||
|
page += String(active_settings->max_speed);
|
||||||
|
page += F("'></label><label>Uebertragungszeit (Sekunden)<input name='active_time' type='number' min='1' max='600' required value='");
|
||||||
|
page += String(active_settings->active_time_seconds);
|
||||||
|
page += F("'></label><button type='submit'>Speichern</button></form>"
|
||||||
|
"<h2>Firmware aktualisieren</h2><form method='post' action='/update' enctype='multipart/form-data'>"
|
||||||
|
"<input name='firmware' type='file' accept='.bin' required><button type='submit'>Upload starten</button>"
|
||||||
|
"</form><p><small>Access Point: ");
|
||||||
|
page += html_escape(active_settings->access_point_name);
|
||||||
|
page += F("</small></p></body></html>");
|
||||||
|
server.send(200, "text/html; charset=utf-8", page);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool parse_settings(TelemetrySettings &settings)
|
||||||
|
{
|
||||||
|
String callsign = server.arg("callsign");
|
||||||
|
String access_point_name = server.arg("ap_name");
|
||||||
|
String access_point_password = server.arg("ap_password");
|
||||||
|
int min_speed = server.arg("min").toInt();
|
||||||
|
int max_speed = server.arg("max").toInt();
|
||||||
|
int active_time_seconds = server.arg("active_time").toInt();
|
||||||
|
callsign.trim();
|
||||||
|
access_point_name.trim();
|
||||||
|
access_point_password.trim();
|
||||||
|
if (access_point_name.length() == 0 || access_point_name.length() > 32 || access_point_password.length() < 8 || access_point_password.length() > 63 || callsign.length() == 0 || callsign.length() > 16 || min_speed < 0 || max_speed > 300 ||
|
||||||
|
min_speed >= max_speed || active_time_seconds < 1 || active_time_seconds > 600)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
settings.callsign = callsign;
|
||||||
|
settings.access_point_name = access_point_name;
|
||||||
|
settings.access_point_password = access_point_password;
|
||||||
|
settings.min_speed = min_speed;
|
||||||
|
settings.max_speed = max_speed;
|
||||||
|
settings.active_time_seconds = active_time_seconds;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_root()
|
||||||
|
{
|
||||||
|
send_page();
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_settings()
|
||||||
|
{
|
||||||
|
TelemetrySettings updated = *active_settings;
|
||||||
|
if (!parse_settings(updated))
|
||||||
|
{
|
||||||
|
server.send(400, "text/plain; charset=utf-8", "Ungueltige Einstellungen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
active_settings->callsign = updated.callsign;
|
||||||
|
active_settings->access_point_name = updated.access_point_name;
|
||||||
|
active_settings->access_point_password = updated.access_point_password;
|
||||||
|
active_settings->min_speed = updated.min_speed;
|
||||||
|
active_settings->max_speed = updated.max_speed;
|
||||||
|
active_settings->active_time_seconds = updated.active_time_seconds;
|
||||||
|
preferences.putString("callsign", active_settings->callsign);
|
||||||
|
preferences.putString("ap_name", active_settings->access_point_name);
|
||||||
|
preferences.putString("ap_password", active_settings->access_point_password);
|
||||||
|
preferences.putInt("min", active_settings->min_speed);
|
||||||
|
preferences.putInt("max", active_settings->max_speed);
|
||||||
|
preferences.putUInt("active_time", active_settings->active_time_seconds);
|
||||||
|
send_page("Einstellungen gespeichert.");
|
||||||
|
access_point_restart_pending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_update_upload()
|
||||||
|
{
|
||||||
|
HTTPUpload &upload = server.upload();
|
||||||
|
if (upload.status == UPLOAD_FILE_START)
|
||||||
|
{
|
||||||
|
restart_after_update = false;
|
||||||
|
update_failed = false;
|
||||||
|
Serial.printf("Firmware-Upload: %s\n", upload.filename.c_str());
|
||||||
|
if (!Update.begin(UPDATE_SIZE_UNKNOWN))
|
||||||
|
{
|
||||||
|
update_failed = true;
|
||||||
|
Update.printError(Serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (upload.status == UPLOAD_FILE_WRITE)
|
||||||
|
{
|
||||||
|
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize)
|
||||||
|
{
|
||||||
|
update_failed = true;
|
||||||
|
Update.printError(Serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (upload.status == UPLOAD_FILE_END)
|
||||||
|
{
|
||||||
|
if (Update.end(true))
|
||||||
|
{
|
||||||
|
restart_after_update = true;
|
||||||
|
Serial.printf("Firmware-Upload abgeschlossen: %u Bytes\n", upload.totalSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
update_failed = true;
|
||||||
|
Update.printError(Serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_update_result()
|
||||||
|
{
|
||||||
|
if (!update_failed && restart_after_update)
|
||||||
|
{
|
||||||
|
server.send(200, "text/plain; charset=utf-8", "Upload erfolgreich. Neustart...");
|
||||||
|
if (restart_after_update)
|
||||||
|
{
|
||||||
|
delay(500);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
server.send(500, "text/plain; charset=utf-8", "Firmware-Upload fehlgeschlagen");
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool webinterface_begin(TelemetrySettings &settings)
|
||||||
|
{
|
||||||
|
active_settings = &settings;
|
||||||
|
preferences.begin(settings_namespace, false);
|
||||||
|
settings.callsign = preferences.getString("callsign", default_callsign);
|
||||||
|
settings.access_point_name = preferences.getString("ap_name", default_access_point_name());
|
||||||
|
settings.access_point_password = preferences.getString("ap_password", default_access_point_password);
|
||||||
|
settings.min_speed = preferences.getInt("min", default_min_speed);
|
||||||
|
settings.max_speed = preferences.getInt("max", default_max_speed);
|
||||||
|
settings.active_time_seconds = preferences.getUInt("active_time", default_active_time_seconds);
|
||||||
|
if (settings.access_point_name.length() == 0 || settings.access_point_name.length() > 32 || settings.access_point_password.length() < 8 || settings.access_point_password.length() > 63 || settings.callsign.length() == 0 || settings.min_speed < 0 || settings.min_speed >= settings.max_speed ||
|
||||||
|
settings.max_speed > 300 || settings.active_time_seconds < 1 || settings.active_time_seconds > 600)
|
||||||
|
{
|
||||||
|
settings.callsign = default_callsign;
|
||||||
|
settings.access_point_name = default_access_point_name();
|
||||||
|
settings.access_point_password = default_access_point_password;
|
||||||
|
settings.min_speed = default_min_speed;
|
||||||
|
settings.max_speed = default_max_speed;
|
||||||
|
settings.active_time_seconds = default_active_time_seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFi.mode(WIFI_AP);
|
||||||
|
bool ap_started = WiFi.softAP(settings.access_point_name, settings.access_point_password);
|
||||||
|
if (!ap_started)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
server.on("/", HTTP_GET, handle_root);
|
||||||
|
server.on("/settings", HTTP_POST, handle_settings);
|
||||||
|
server.on("/update", HTTP_POST, handle_update_result, handle_update_upload);
|
||||||
|
server.begin();
|
||||||
|
Serial.print("Webinterface: http://");
|
||||||
|
Serial.println(WiFi.softAPIP());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void webinterface_handle(void)
|
||||||
|
{
|
||||||
|
server.handleClient();
|
||||||
|
if (access_point_restart_pending)
|
||||||
|
{
|
||||||
|
access_point_restart_pending = false;
|
||||||
|
WiFi.softAPdisconnect(true);
|
||||||
|
delay(100);
|
||||||
|
if (!WiFi.softAP(active_settings->access_point_name, active_settings->access_point_password))
|
||||||
|
Serial.println("Access Point konnte nicht neu gestartet werden");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const TelemetrySettings &webinterface_settings(void)
|
||||||
|
{
|
||||||
|
return *active_settings;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef WINDENTELEMETRY_WEBINTERFACE_H
|
||||||
|
#define WINDENTELEMETRY_WEBINTERFACE_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
struct TelemetrySettings
|
||||||
|
{
|
||||||
|
String callsign;
|
||||||
|
String access_point_name;
|
||||||
|
String access_point_password;
|
||||||
|
int min_speed;
|
||||||
|
int max_speed;
|
||||||
|
unsigned int active_time_seconds;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool webinterface_begin(TelemetrySettings &settings);
|
||||||
|
void webinterface_handle(void);
|
||||||
|
const TelemetrySettings &webinterface_settings(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
+2
-9
@@ -8,14 +8,13 @@ void init_servo(void)
|
|||||||
{
|
{
|
||||||
myservo.setPeriodHertz(50);
|
myservo.setPeriodHertz(50);
|
||||||
myservo.attach(servoPin);
|
myservo.attach(servoPin);
|
||||||
set_tacho(0, 70, 150);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_tacho(int speed, int speed_min, int speed_max)
|
void set_tacho(int speed, int speed_min, int speed_max)
|
||||||
{
|
{
|
||||||
int val = map(speed, -25, 220, 0, 155);
|
int val = map(speed, -25, 220, 0, 155);
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
Serial.print("Tacho Mapping: ")
|
Serial.print("Tacho Mapping: ");
|
||||||
Serial.println(val);
|
Serial.println(val);
|
||||||
#endif
|
#endif
|
||||||
myservo.write(val);
|
myservo.write(val);
|
||||||
@@ -72,11 +71,5 @@ void init_pixel(void)
|
|||||||
|
|
||||||
int setoffsetpixel(int pixel)
|
int setoffsetpixel(int pixel)
|
||||||
{
|
{
|
||||||
int newpixel;
|
return (pixel + pixeloffset + NUMPIXELS) % NUMPIXELS;
|
||||||
newpixel = pixel + pixeloffset;
|
|
||||||
if (newpixel >= NUMPIXELS)
|
|
||||||
{
|
|
||||||
newpixel = newpixel - NUMPIXELS;
|
|
||||||
}
|
|
||||||
return newpixel;
|
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,12 @@
|
|||||||
#define WINDENTELEMETRY_CONFIG_H
|
#define WINDENTELEMETRY_CONFIG_H
|
||||||
|
|
||||||
#define LORA_FREQ 868.0
|
#define LORA_FREQ 868.0
|
||||||
|
#define TELEMETRY_CALLSIGN "D1234"
|
||||||
|
#define TELEMETRY_SEND_INTERVAL_MS 1000UL
|
||||||
|
#define TELEMETRY_ACTIVE_TIME_MS 90000UL
|
||||||
|
#define TELEMETRY_LOW_SPEED_KMH 30
|
||||||
|
#define default_min_tow_speed 80
|
||||||
|
#define default_max_tow_speed 150
|
||||||
#ifdef HELTEC_WIFI_LORA_32_V3
|
#ifdef HELTEC_WIFI_LORA_32_V3
|
||||||
// SX1262 on HELTEC_WIFI_LORA_32_V3 has the following connections:
|
// SX1262 on HELTEC_WIFI_LORA_32_V3 has the following connections:
|
||||||
// NSS pin: 8
|
// NSS pin: 8
|
||||||
@@ -27,8 +33,6 @@
|
|||||||
/**difference pressure**/
|
/**difference pressure**/
|
||||||
#define dp_scl 20
|
#define dp_scl 20
|
||||||
#define dp_sda 19
|
#define dp_sda 19
|
||||||
#define default_min_tow_speed 80
|
|
||||||
#define default_max_tow_speed 150
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef DEVICE_WINDE
|
#ifdef DEVICE_WINDE
|
||||||
|
|||||||
+11
-8
@@ -9,8 +9,8 @@
|
|||||||
; https://docs.platformio.org/page/projectconf.html
|
; https://docs.platformio.org/page/projectconf.html
|
||||||
|
|
||||||
[platformio]
|
[platformio]
|
||||||
build_cache_dir = ./.pio/.build_cache
|
build_cache_dir = ~/.pio/.build_cache
|
||||||
cache_dir = ./.pio/.cache_dir
|
cache_dir = ~/.pio/.cache_dir
|
||||||
|
|
||||||
[common]
|
[common]
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
@@ -25,6 +25,8 @@ build_flags =
|
|||||||
-D CORE_DEBUG_LEVEL=5
|
-D CORE_DEBUG_LEVEL=5
|
||||||
-D SLOW_CLK_TPYE=0
|
-D SLOW_CLK_TPYE=0
|
||||||
-D REGION_EU868
|
-D REGION_EU868
|
||||||
|
-Ilib
|
||||||
|
-Isrc
|
||||||
lib_deps =
|
lib_deps =
|
||||||
olikraus/U8g2@^2.36.15
|
olikraus/U8g2@^2.36.15
|
||||||
jgromes/RadioLib@^7.4.0
|
jgromes/RadioLib@^7.4.0
|
||||||
@@ -41,12 +43,13 @@ lib_deps =
|
|||||||
bolderflight/Bolder Flight Systems Unit Conversions@^5.0.0
|
bolderflight/Bolder Flight Systems Unit Conversions@^5.0.0
|
||||||
bolderflight/Bolder Flight Systems Airdata Calculations@^4.0.0
|
bolderflight/Bolder Flight Systems Airdata Calculations@^4.0.0
|
||||||
adafruit/Adafruit BMP085 Library @ ^1.2.4
|
adafruit/Adafruit BMP085 Library @ ^1.2.4
|
||||||
lib_ignore =
|
lib_ignore = winde
|
||||||
winde
|
build_flags =
|
||||||
build_flags = ${common.build_flags}
|
${common.build_flags}
|
||||||
-D DEVICE_SAILPLANE
|
-D DEVICE_SAILPLANE
|
||||||
upload_port = COM8
|
upload_port = COM8
|
||||||
monitor_port = COM8
|
monitor_port = COM8
|
||||||
|
|
||||||
[env:heltec_wifi_lora_32_V3_winde]
|
[env:heltec_wifi_lora_32_V3_winde]
|
||||||
extends = common
|
extends = common
|
||||||
board = heltec_wifi_lora_32_V3
|
board = heltec_wifi_lora_32_V3
|
||||||
@@ -54,9 +57,9 @@ lib_deps =
|
|||||||
${common.lib_deps}
|
${common.lib_deps}
|
||||||
adafruit/Adafruit NeoPixel@^1.15.2
|
adafruit/Adafruit NeoPixel@^1.15.2
|
||||||
madhephaestus/ESP32Servo@^3.0.9
|
madhephaestus/ESP32Servo@^3.0.9
|
||||||
lib_ignore =
|
lib_ignore = sailplane
|
||||||
sailplane
|
build_flags =
|
||||||
build_flags = ${common.build_flags}
|
${common.build_flags}
|
||||||
-D DEVICE_WINDE
|
-D DEVICE_WINDE
|
||||||
upload_port = COM9
|
upload_port = COM9
|
||||||
monitor_port = COM9
|
monitor_port = COM9
|
||||||
+76
-33
@@ -3,23 +3,25 @@
|
|||||||
#include <U8g2lib.h>
|
#include <U8g2lib.h>
|
||||||
#include <RadioLib.h>
|
#include <RadioLib.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
|
#include <webinterface.h>
|
||||||
#ifdef DEVICE_WINDE
|
#ifdef DEVICE_WINDE
|
||||||
#include <tacho.h>
|
#include <tacho.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TelemetrySettings telemetry_settings;
|
||||||
|
|
||||||
#ifdef DEVICE_SAILPLANE
|
#ifdef DEVICE_SAILPLANE
|
||||||
#include <airspeed.h>
|
#include <airspeed.h>
|
||||||
unsigned long previousMillisSend = 0;
|
unsigned long previousMillisSend = 0;
|
||||||
const long send_interval = 1000;
|
|
||||||
unsigned long previousMillissendtimer = 0;
|
unsigned long previousMillissendtimer = 0;
|
||||||
const long sendtimer_max = 90000;
|
|
||||||
bool send_data = false;
|
bool send_data = false;
|
||||||
bool is_airborn = false;
|
bool is_airborn = false;
|
||||||
int lowspeedtimer = 0;
|
unsigned long lowspeedtimer = 0;
|
||||||
int lowspeedtimermax = 90000;
|
bool sensors_ready = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SX1262 radio = new Module(LORA_NSS, LORA_DIO1, LORA_NRST, LORA_BUSY);
|
SX1262 radio = new Module(LORA_NSS, LORA_DIO1, LORA_NRST, LORA_BUSY);
|
||||||
|
bool radio_ready = false;
|
||||||
#ifdef DEVICE_WINDE
|
#ifdef DEVICE_WINDE
|
||||||
volatile bool receivedFlag = false;
|
volatile bool receivedFlag = false;
|
||||||
#if defined(ESP8266) || defined(ESP32)
|
#if defined(ESP8266) || defined(ESP32)
|
||||||
@@ -50,38 +52,43 @@ void setup()
|
|||||||
/* Serial to display data */
|
/* Serial to display data */
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
Serial.println("start");
|
Serial.println("start");
|
||||||
|
if (!webinterface_begin(telemetry_settings))
|
||||||
|
Serial.println("Webinterface konnte nicht gestartet werden");
|
||||||
int state = radio.begin(LORA_FREQ);
|
int state = radio.begin(LORA_FREQ);
|
||||||
if (state == RADIOLIB_ERR_NONE)
|
if (state == RADIOLIB_ERR_NONE)
|
||||||
{
|
{
|
||||||
|
radio_ready = true;
|
||||||
Serial.println(F("success!"));
|
Serial.println(F("success!"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Serial.print(F("failed, code "));
|
Serial.print(F("failed, code "));
|
||||||
Serial.println(state);
|
Serial.println(state);
|
||||||
while (true)
|
Serial.println(F("Webinterface bleibt verfuegbar"));
|
||||||
{
|
|
||||||
delay(10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
u8g2.begin();
|
u8g2.begin();
|
||||||
u8g2.clearBuffer();
|
u8g2.clearBuffer();
|
||||||
u8g2.setFont(u8g2_font_ncenB14_tr);
|
u8g2.setFont(u8g2_font_ncenB14_tr);
|
||||||
#ifdef DEVICE_SAILPLANE
|
#ifdef DEVICE_SAILPLANE
|
||||||
u8g2.drawStr(0, 20, "Start Plane");
|
u8g2.drawStr(0, 20, "Start Plane");
|
||||||
init_2ndi2c();
|
sensors_ready = init_2ndi2c() && init_airspeed_sensor() && init_pressure_sensor();
|
||||||
init_airspeed_sensor();
|
if (!sensors_ready)
|
||||||
init_pressure_sensor();
|
{
|
||||||
|
u8g2.drawStr(0, 40, "Sensor error");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef DEVICE_WINDE
|
#ifdef DEVICE_WINDE
|
||||||
u8g2.drawStr(0, 20, "Start Winde");
|
u8g2.drawStr(0, 20, "Start Winde");
|
||||||
init_servo();
|
|
||||||
init_pixel();
|
init_pixel();
|
||||||
|
init_servo();
|
||||||
|
set_tacho(0, telemetry_settings.min_speed, telemetry_settings.max_speed);
|
||||||
|
|
||||||
radio.setPacketReceivedAction(setFlag);
|
radio.setPacketReceivedAction(setFlag);
|
||||||
|
|
||||||
// start listening for LoRa packets
|
// start listening for LoRa packets
|
||||||
|
|
||||||
|
if (radio_ready)
|
||||||
|
{
|
||||||
state = radio.startReceive();
|
state = radio.startReceive();
|
||||||
if (state == RADIOLIB_ERR_NONE)
|
if (state == RADIOLIB_ERR_NONE)
|
||||||
{
|
{
|
||||||
@@ -91,9 +98,7 @@ void setup()
|
|||||||
{
|
{
|
||||||
Serial.print(F("failed, code "));
|
Serial.print(F("failed, code "));
|
||||||
Serial.println(state);
|
Serial.println(state);
|
||||||
while (true)
|
radio_ready = false;
|
||||||
{
|
|
||||||
delay(10);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -105,11 +110,10 @@ String nmea_checksum(String str)
|
|||||||
byte cs = 0;
|
byte cs = 0;
|
||||||
for (unsigned int n = 1; n < str.length(); n++)
|
for (unsigned int n = 1; n < str.length(); n++)
|
||||||
{
|
{
|
||||||
if (str[n] != '$' || str[n] != '!' || str[n] != '*')
|
if (str[n] == '*')
|
||||||
{
|
break;
|
||||||
cs ^= str[n];
|
cs ^= str[n];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (cs < 0x10)
|
if (cs < 0x10)
|
||||||
return "*0" + String(cs, HEX);
|
return "*0" + String(cs, HEX);
|
||||||
@@ -150,6 +154,9 @@ void draw_rssi(int Rssi){
|
|||||||
|
|
||||||
void send_lora(String data)
|
void send_lora(String data)
|
||||||
{
|
{
|
||||||
|
if (!radio_ready)
|
||||||
|
return;
|
||||||
|
|
||||||
int state = radio.transmit(data);
|
int state = radio.transmit(data);
|
||||||
if (state == RADIOLIB_ERR_NONE)
|
if (state == RADIOLIB_ERR_NONE)
|
||||||
{
|
{
|
||||||
@@ -158,7 +165,7 @@ void send_lora(String data)
|
|||||||
|
|
||||||
// print measured data rate
|
// print measured data rate
|
||||||
Serial.print(F("[SX1262] Datarate:\t"));
|
Serial.print(F("[SX1262] Datarate:\t"));
|
||||||
Serial.print(radio.getDataRate());
|
//Serial.print(radio.getDataRate());
|
||||||
Serial.println(F(" bps"));
|
Serial.println(F(" bps"));
|
||||||
}
|
}
|
||||||
else if (state == RADIOLIB_ERR_PACKET_TOO_LONG)
|
else if (state == RADIOLIB_ERR_PACKET_TOO_LONG)
|
||||||
@@ -184,7 +191,7 @@ void send_speed(int vel_kmh)
|
|||||||
String data;
|
String data;
|
||||||
// serializeJson(sailplane_data, data);
|
// serializeJson(sailplane_data, data);
|
||||||
// sprintf(data,"$PWTLS,%s,%u,%u,%u","D-1234",vel_kmh,70,140);
|
// sprintf(data,"$PWTLS,%s,%u,%u,%u","D-1234",vel_kmh,70,140);
|
||||||
data = "$PWTLS,D1234," + String(vel_kmh) + ",70,140";
|
data = "$PWTLS," + telemetry_settings.callsign + "," + String(vel_kmh) + "," + String(telemetry_settings.min_speed) + "," + String(telemetry_settings.max_speed);
|
||||||
data += nmea_checksum(data);
|
data += nmea_checksum(data);
|
||||||
Serial.println(data);
|
Serial.println(data);
|
||||||
send_lora(data);
|
send_lora(data);
|
||||||
@@ -194,7 +201,7 @@ void send_airborn()
|
|||||||
{
|
{
|
||||||
String data;
|
String data;
|
||||||
// serializeJson(sailplane_data, data);
|
// serializeJson(sailplane_data, data);
|
||||||
data = "$PWTLA,D1234,1";
|
data = "$PWTLA," + telemetry_settings.callsign + ",1";
|
||||||
data += nmea_checksum(data);
|
data += nmea_checksum(data);
|
||||||
Serial.println(data);
|
Serial.println(data);
|
||||||
send_lora(data);
|
send_lora(data);
|
||||||
@@ -215,6 +222,8 @@ String getSplitValue(String data, char separator, int index)
|
|||||||
}
|
}
|
||||||
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
|
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
|
||||||
}
|
}
|
||||||
|
#ifdef DEVICE_WINDE
|
||||||
|
|
||||||
void decode_start(String data)
|
void decode_start(String data)
|
||||||
{
|
{
|
||||||
data_from = getSplitValue(data, ',', 1);
|
data_from = getSplitValue(data, ',', 1);
|
||||||
@@ -229,28 +238,59 @@ void decode_airborn(String data)
|
|||||||
data_min = 0;
|
data_min = 0;
|
||||||
data_max = 0;
|
data_max = 0;
|
||||||
}
|
}
|
||||||
void decode_msg(String data)
|
|
||||||
|
bool valid_nmea(String data)
|
||||||
|
{
|
||||||
|
int checksum_start = data.indexOf('*');
|
||||||
|
if (checksum_start <= 1 || checksum_start + 2 >= data.length())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
byte checksum = 0;
|
||||||
|
for (int i = 1; i < checksum_start; ++i)
|
||||||
|
checksum ^= data[i];
|
||||||
|
|
||||||
|
String received_checksum = data.substring(checksum_start + 1, checksum_start + 3);
|
||||||
|
received_checksum.toUpperCase();
|
||||||
|
char expected_checksum[3];
|
||||||
|
snprintf(expected_checksum, sizeof(expected_checksum), "%02X", checksum);
|
||||||
|
return received_checksum == expected_checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool decode_msg(String data)
|
||||||
{
|
{
|
||||||
String pos1 = getSplitValue(data, ',', 0);
|
String pos1 = getSplitValue(data, ',', 0);
|
||||||
if (pos1 == "$PWTLS")
|
if (pos1 == "$PWTLS")
|
||||||
{
|
{
|
||||||
|
if (getSplitValue(data, ',', 4).length() == 0)
|
||||||
|
return false;
|
||||||
decode_start(data);
|
decode_start(data);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else if (pos1 == "$PWTLA")
|
else if (pos1 == "$PWTLA")
|
||||||
{
|
{
|
||||||
decode_airborn(data);
|
decode_airborn(data);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Serial.println("Nachricht nicht erkannt");
|
Serial.println("Nachricht nicht erkannt");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
|
webinterface_handle();
|
||||||
#ifdef DEVICE_SAILPLANE
|
#ifdef DEVICE_SAILPLANE
|
||||||
|
if (!sensors_ready)
|
||||||
|
{
|
||||||
|
delay(1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long currentMillis = millis();
|
unsigned long currentMillis = millis();
|
||||||
if (currentMillis - previousMillisSend >= send_interval)
|
unsigned long active_time_ms = telemetry_settings.active_time_seconds * 1000UL;
|
||||||
|
if (currentMillis - previousMillisSend >= TELEMETRY_SEND_INTERVAL_MS)
|
||||||
{
|
{
|
||||||
previousMillisSend = currentMillis;
|
previousMillisSend = currentMillis;
|
||||||
/* Read the sensor */
|
/* Read the sensor */
|
||||||
@@ -264,13 +304,13 @@ void loop()
|
|||||||
|
|
||||||
if (send_data == false)
|
if (send_data == false)
|
||||||
{
|
{
|
||||||
if (vel_kmh < 30)
|
if (vel_kmh < telemetry_settings.min_speed)
|
||||||
{
|
{
|
||||||
lowspeedtimer++;
|
lowspeedtimer += TELEMETRY_SEND_INTERVAL_MS;
|
||||||
if (lowspeedtimer >= lowspeedtimermax)
|
if (lowspeedtimer >= active_time_ms)
|
||||||
{
|
{
|
||||||
is_airborn = false;
|
is_airborn = false;
|
||||||
lowspeedtimer = lowspeedtimermax;
|
lowspeedtimer = active_time_ms;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -289,7 +329,7 @@ void loop()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (currentMillis - previousMillissendtimer < sendtimer_max)
|
if (currentMillis - previousMillissendtimer < active_time_ms)
|
||||||
{
|
{
|
||||||
send_speed(vel_kmh);
|
send_speed(vel_kmh);
|
||||||
}
|
}
|
||||||
@@ -308,7 +348,7 @@ void loop()
|
|||||||
Serial.println(vel_kmh);
|
Serial.println(vel_kmh);
|
||||||
Serial.print(pres.pres_pa(), 6);
|
Serial.print(pres.pres_pa(), 6);
|
||||||
Serial.print("IAS (m/s): ");
|
Serial.print("IAS (m/s): ");
|
||||||
Serial.println(ias);
|
Serial.println(get_airspeed());
|
||||||
Serial.println(vel_kmh);
|
Serial.println(vel_kmh);
|
||||||
Serial.print("\t");
|
Serial.print("\t");
|
||||||
Serial.print(pres.die_temp_c(), 6);
|
Serial.print(pres.die_temp_c(), 6);
|
||||||
@@ -318,7 +358,7 @@ void loop()
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef DEVICE_WINDE
|
#ifdef DEVICE_WINDE
|
||||||
if (receivedFlag)
|
if (radio_ready && receivedFlag)
|
||||||
{
|
{
|
||||||
// reset flag
|
// reset flag
|
||||||
receivedFlag = false;
|
receivedFlag = false;
|
||||||
@@ -329,7 +369,11 @@ void loop()
|
|||||||
|
|
||||||
if (state == RADIOLIB_ERR_NONE)
|
if (state == RADIOLIB_ERR_NONE)
|
||||||
{
|
{
|
||||||
decode_msg(str);
|
if (!valid_nmea(str) || !decode_msg(str))
|
||||||
|
{
|
||||||
|
Serial.println("Ungueltige Telemetrie-Nachricht");
|
||||||
|
return;
|
||||||
|
}
|
||||||
// packet was successfully received
|
// packet was successfully received
|
||||||
u8g2.clearBuffer();
|
u8g2.clearBuffer();
|
||||||
u8g2.setFont(u8g2_font_ncenB10_tr);
|
u8g2.setFont(u8g2_font_ncenB10_tr);
|
||||||
@@ -345,7 +389,6 @@ void loop()
|
|||||||
draw_rssi(radio.getRSSI());
|
draw_rssi(radio.getRSSI());
|
||||||
u8g2.sendBuffer();
|
u8g2.sendBuffer();
|
||||||
Serial.println(str);
|
Serial.println(str);
|
||||||
int speed = str.toInt();
|
|
||||||
set_tacho(data_speed, data_min, data_max);
|
set_tacho(data_speed, data_min, data_max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user