forked from fritob/Camper-Monitor
Firmware des Neigungsmessers ins Projekt übernehmen
Die ESPHome-Firmware lag bisher im eigenständigen Projekt VanAllign-Pro. Da die App der einzige Client ist, gehören Firmware und App zusammen: ändert sich die Bluetooth-Schnittstelle, muss beides gemeinsam angefasst werden. Übernommen sind die Firmware selbst und die beiden Experimente zu WLAN/BLE-Umschaltung und ESP-NOW, letztere nach experimente/ einsortiert und als nicht betriebsnotwendig gekennzeichnet. Die WebBLE-Oberfläche bleibt im Ursprungsprojekt - sie ist durch die App abgelöst und bringt 2 MB Bilder mit, die in einem iOS-Projekt nichts zu suchen haben. Die .gitignore schliesst jetzt die ESPHome-Build-Verzeichnisse aus; im Ursprungsprojekt fehlte das, dort liegen inzwischen 233 MB Bauartefakte neben den Quellen. Am neuen Ort mit esphome config gegengeprüft. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
# Custom folder icons
|
# Custom folder icons
|
||||||
Icon
|
Icon
|
||||||
|
|
||||||
|
|
||||||
# Volume root files
|
# Volume root files
|
||||||
.DocumentRevisions-V100
|
.DocumentRevisions-V100
|
||||||
.fseventsd
|
.fseventsd
|
||||||
@@ -63,3 +64,8 @@ playground.xcworkspace
|
|||||||
|
|
||||||
# Swift Package Manager
|
# Swift Package Manager
|
||||||
# Package.resolved
|
# Package.resolved
|
||||||
|
### ESPHome
|
||||||
|
# Build-Verzeichnis und Zustandsdaten; das Abbild wird aus der YAML erzeugt.
|
||||||
|
.esphome/
|
||||||
|
firmware/**/.esphome/
|
||||||
|
firmware/**/.pioenvs/
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ iOS-App, die per Bluetooth LE die Energieanlage im Wohnmobil ausliest:
|
|||||||
|
|
||||||
Ein Victron SmartShunt/BMV wird ebenfalls unterstützt, falls später einer dazukommt.
|
Ein Victron SmartShunt/BMV wird ebenfalls unterstützt, falls später einer dazukommt.
|
||||||
|
|
||||||
|
Die Firmware des Neigungsmessers liegt mit im Projekt, siehe
|
||||||
|
[firmware/vanalign](firmware/vanalign/README.md).
|
||||||
|
|
||||||
## Bauen und installieren
|
## Bauen und installieren
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -170,6 +173,10 @@ und die Prüfsummen beider Daly-Dialekte.
|
|||||||
## Aufbau
|
## Aufbau
|
||||||
|
|
||||||
```
|
```
|
||||||
|
firmware/vanalign/ Firmware des Neigungsmessers (ESPHome)
|
||||||
|
├── esp32_ble.yaml Neigungsmessung und Bluetooth-Schnittstelle
|
||||||
|
└── experimente/ Nicht für den Betrieb nötig
|
||||||
|
|
||||||
CamperMonitor/
|
CamperMonitor/
|
||||||
├── Models/
|
├── Models/
|
||||||
│ ├── Profile.swift Fahrzeug
|
│ ├── Profile.swift Fahrzeug
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
# VanAlign Pro – Neigungsmessung für den Camper
|
||||||
|
|
||||||
|
ESP32-S3 mit MPU6050, der Längs- und Querneigung des Fahrzeugs misst und über
|
||||||
|
Bluetooth bereitstellt. Zum Ausrichten beim Parken: die Anzeige zeigt, welche
|
||||||
|
Seite höher steht und wie weit es noch ist.
|
||||||
|
|
||||||
|
> Teile dieses Projekts wurden mit KI-Unterstützung erstellt.
|
||||||
|
|
||||||
|
## Firmware
|
||||||
|
|
||||||
|
`esp32_ble.yaml` – die einzige Datei, die für den Betrieb gebraucht wird.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd firmware/vanalign
|
||||||
|
esphome run esp32_ble.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bluetooth-Schnittstelle
|
||||||
|
|
||||||
|
Dienst `2a24b789-7aab-4535-af3e-ee76a35cc42d` (wird beworben, das Gerät ist
|
||||||
|
darüber auffindbar).
|
||||||
|
|
||||||
|
| Charakteristik | UUID (Ende) | Zugriff | Inhalt |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Pitch | `…3424` | lesen, benachrichtigen | Längsneigung, Float32 little-endian, Grad |
|
||||||
|
| Roll | `…3425` | lesen, benachrichtigen | Querneigung, Float32 little-endian, Grad |
|
||||||
|
| Offsets | `…3426` | lesen, benachrichtigen | zwei Float32: die gespeicherten Kalibrierwerte |
|
||||||
|
| Kalibrieren | `…3427` | schreiben | ein Byte: `0` setzt zurück, alles andere kalibriert |
|
||||||
|
|
||||||
|
Positiver Pitch heißt: das Heck steht höher. Positiver Roll: die rechte Seite
|
||||||
|
steht höher.
|
||||||
|
|
||||||
|
### Kalibrierung
|
||||||
|
|
||||||
|
Fahrzeug eben stellen, dann ein beliebiges Byte ungleich `0` auf `…3427`
|
||||||
|
schreiben – oder in Camper Monitor auf *Auf aktuelle Lage kalibrieren* tippen.
|
||||||
|
Die Offsets werden dauerhaft gespeichert und überstehen einen Neustart.
|
||||||
|
|
||||||
|
## Was sich gegenüber 1.0 geändert hat
|
||||||
|
|
||||||
|
* **Kalibrierung funktioniert jetzt überhaupt.** Die Charakteristik `…3427` war
|
||||||
|
zwar beschreibbar, hatte aber keine Aktion hinterlegt und tat nichts. Der
|
||||||
|
Kalibrier-Knopf war nur über den Webserver erreichbar, der auskommentiert
|
||||||
|
ist – kalibrieren war damit auf keinem Weg möglich.
|
||||||
|
* **Die Werte werden gesendet, statt abgefragt.** Pitch und Roll haben jetzt
|
||||||
|
`notify`. Vorher musste der Client im Sekundentakt lesen, was für eine
|
||||||
|
Wasserwaage zu träge ist.
|
||||||
|
* **Die gespeicherten Offsets sind auslesbar**, sodass ein Client zeigen kann,
|
||||||
|
ob überhaupt schon kalibriert wurde.
|
||||||
|
* **Der ESP-NOW-Rest ist entfernt.** Er schickte bei jedem einzelnen Messwert
|
||||||
|
ein `"hallo"` an eine fest eingetragene MAC-Adresse.
|
||||||
|
|
||||||
|
Die UUIDs sind unverändert, die vorhandene WebApp läuft weiter.
|
||||||
|
|
||||||
|
## Clients
|
||||||
|
|
||||||
|
* **Camper Monitor** (iOS) – die App in diesem Projekt. Geräteart
|
||||||
|
*Nivellierung*: grafische Libelle, Kalibrierung aus der App, zusammen mit
|
||||||
|
den übrigen Geräten im Fahrzeug.
|
||||||
|
* Die ursprüngliche WebBLE-Oberfläche liegt weiterhin im Projekt
|
||||||
|
`VanAllign-Pro` unter `WebAPP/`.
|
||||||
|
|
||||||
|
## Weitere Dateien
|
||||||
|
|
||||||
|
Unter `experimente/` liegen `esp32_switch.yaml` (Umschalten zwischen WLAN und
|
||||||
|
BLE) und `esp32_EspNow-rec.yaml` (ESP-NOW-Empfänger). Beide gehören nicht zum
|
||||||
|
Neigungsmesser und werden für den Betrieb nicht gebraucht – sie sind nur
|
||||||
|
aufgehoben, weil sie Ideen aus der Entstehungszeit festhalten.
|
||||||
|
|
||||||
|
## Herkunft
|
||||||
|
|
||||||
|
Übernommen aus dem eigenständigen Projekt `VanAllign-Pro`. Dort liegen
|
||||||
|
weiterhin die WebBLE-Oberfläche (`WebAPP/`, durch die iOS-App abgelöst) und
|
||||||
|
unter `bin/` die gebauten Binärdateien der Version 1.0.
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
* ESP32-S3, MPU6050 an I²C (SDA GPIO8, SCL GPIO9)
|
||||||
|
* ESPHome (geprüft mit 2026.6.5)
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
# VanAlign Pro – Neigungsmessung über BLE
|
||||||
|
#
|
||||||
|
# ESP32-S3 mit MPU6050. Liefert Pitch und Roll als 32-Bit-Float
|
||||||
|
# (little-endian) und lässt sich über Bluetooth auf die aktuelle Lage
|
||||||
|
# kalibrieren.
|
||||||
|
#
|
||||||
|
# Die UUIDs sind gegenüber Version 1.0 unverändert, damit die vorhandene
|
||||||
|
# WebApp weiterläuft. Neu sind:
|
||||||
|
# * notify auf Pitch und Roll – die Werte werden gesendet, sobald sie sich
|
||||||
|
# ändern, statt vom Client im Sekundentakt abgefragt zu werden.
|
||||||
|
# * eine funktionierende Kalibrierung über Bluetooth. Bisher war die
|
||||||
|
# Charakteristik zwar beschreibbar, hatte aber keine Aktion hinterlegt,
|
||||||
|
# und der Kalibrier-Knopf war nur über den Webserver erreichbar, der
|
||||||
|
# auskommentiert ist. Kalibrieren war damit gar nicht möglich.
|
||||||
|
# * die gespeicherten Offsets sind auslesbar, sodass ein Client zeigen
|
||||||
|
# kann, ob überhaupt schon kalibriert wurde.
|
||||||
|
|
||||||
|
esphome:
|
||||||
|
name: vanalign
|
||||||
|
friendly_name: "VanAlign Pro"
|
||||||
|
on_boot:
|
||||||
|
priority: -100
|
||||||
|
then:
|
||||||
|
- script.execute: publish_offsets
|
||||||
|
|
||||||
|
esp32:
|
||||||
|
board: esp32-s3-devkitc-1
|
||||||
|
framework:
|
||||||
|
type: esp-idf
|
||||||
|
|
||||||
|
logger:
|
||||||
|
level: WARN
|
||||||
|
|
||||||
|
i2c:
|
||||||
|
sda: GPIO8
|
||||||
|
scl: GPIO9
|
||||||
|
scan: true
|
||||||
|
|
||||||
|
globals:
|
||||||
|
- id: pitch_offset
|
||||||
|
type: float
|
||||||
|
restore_value: yes
|
||||||
|
initial_value: '0.0'
|
||||||
|
- id: roll_offset
|
||||||
|
type: float
|
||||||
|
restore_value: yes
|
||||||
|
initial_value: '0.0'
|
||||||
|
|
||||||
|
sensor:
|
||||||
|
- platform: mpu6050
|
||||||
|
#address: 0x69
|
||||||
|
accel_x:
|
||||||
|
id: accel_x
|
||||||
|
internal: true
|
||||||
|
accel_y:
|
||||||
|
id: accel_y
|
||||||
|
internal: true
|
||||||
|
accel_z:
|
||||||
|
id: accel_z
|
||||||
|
internal: true
|
||||||
|
gyro_x:
|
||||||
|
id: mpu_gyro_x
|
||||||
|
internal: true
|
||||||
|
gyro_y:
|
||||||
|
id: mpu_gyro_y
|
||||||
|
internal: true
|
||||||
|
gyro_z:
|
||||||
|
id: mpu_gyro_z
|
||||||
|
internal: true
|
||||||
|
update_interval: 0.1s
|
||||||
|
|
||||||
|
- platform: template
|
||||||
|
name: "Neigung Pitch"
|
||||||
|
id: pitch
|
||||||
|
icon: mdi:caravan
|
||||||
|
unit_of_measurement: "°"
|
||||||
|
accuracy_decimals: 1
|
||||||
|
update_interval: 0.1s
|
||||||
|
lambda: |-
|
||||||
|
if (isnan(id(accel_x).state) || isnan(id(accel_y).state) || isnan(id(accel_z).state)) {
|
||||||
|
return NAN;
|
||||||
|
}
|
||||||
|
float raw = atan2(id(accel_y).state,
|
||||||
|
sqrt(pow(id(accel_x).state, 2) + pow(id(accel_z).state, 2)))
|
||||||
|
* (180.0 / 3.14159265);
|
||||||
|
return raw - id(pitch_offset);
|
||||||
|
filters:
|
||||||
|
- sliding_window_moving_average:
|
||||||
|
window_size: 8
|
||||||
|
send_every: 1
|
||||||
|
- exponential_moving_average:
|
||||||
|
alpha: 0.2
|
||||||
|
on_value:
|
||||||
|
# Ohne dieses Senden müsste der Client die Werte abfragen; die Anzeige
|
||||||
|
# ruckelt dann im Takt der Abfrage statt der Messung.
|
||||||
|
- ble_server.characteristic.set_value:
|
||||||
|
id: pitch_ble
|
||||||
|
value: !lambda |-
|
||||||
|
std::vector<uint8_t> v(sizeof(float));
|
||||||
|
float val = x;
|
||||||
|
memcpy(v.data(), &val, sizeof(float));
|
||||||
|
return v;
|
||||||
|
|
||||||
|
- platform: template
|
||||||
|
name: "Neigung Roll"
|
||||||
|
id: roll
|
||||||
|
icon: mdi:axis-x-rotate-clockwise
|
||||||
|
unit_of_measurement: "°"
|
||||||
|
accuracy_decimals: 1
|
||||||
|
update_interval: 0.1s
|
||||||
|
lambda: |-
|
||||||
|
if (isnan(id(accel_x).state) || isnan(id(accel_z).state)) {
|
||||||
|
return NAN;
|
||||||
|
}
|
||||||
|
float raw = atan2(-id(accel_x).state, id(accel_z).state) * (180.0 / 3.14159265);
|
||||||
|
return raw - id(roll_offset);
|
||||||
|
filters:
|
||||||
|
- sliding_window_moving_average:
|
||||||
|
window_size: 8
|
||||||
|
send_every: 1
|
||||||
|
- exponential_moving_average:
|
||||||
|
alpha: 0.2
|
||||||
|
on_value:
|
||||||
|
- ble_server.characteristic.set_value:
|
||||||
|
id: roll_ble
|
||||||
|
value: !lambda |-
|
||||||
|
std::vector<uint8_t> v(sizeof(float));
|
||||||
|
float val = x;
|
||||||
|
memcpy(v.data(), &val, sizeof(float));
|
||||||
|
return v;
|
||||||
|
|
||||||
|
script:
|
||||||
|
# Die aktuelle Lage wird zur neuen Null. Beide Wege – Knopf und Bluetooth –
|
||||||
|
# laufen hier zusammen, damit sie nicht auseinanderdriften.
|
||||||
|
- id: calibrate_level
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
if (isnan(id(accel_x).state) || isnan(id(accel_y).state) || isnan(id(accel_z).state)) {
|
||||||
|
ESP_LOGW("vanalign", "Kalibrierung abgebrochen: keine Sensorwerte");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
id(pitch_offset) = atan2(id(accel_y).state,
|
||||||
|
sqrt(pow(id(accel_x).state, 2) + pow(id(accel_z).state, 2)))
|
||||||
|
* (180.0 / 3.14159265);
|
||||||
|
id(roll_offset) = atan2(-id(accel_x).state, id(accel_z).state) * (180.0 / 3.14159265);
|
||||||
|
ESP_LOGI("vanalign", "Kalibriert: pitch_offset=%.2f roll_offset=%.2f",
|
||||||
|
id(pitch_offset), id(roll_offset));
|
||||||
|
|
||||||
|
- script.execute: publish_offsets
|
||||||
|
|
||||||
|
- id: reset_calibration
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
id(pitch_offset) = 0.0f;
|
||||||
|
id(roll_offset) = 0.0f;
|
||||||
|
ESP_LOGI("vanalign", "Kalibrierung zurückgesetzt");
|
||||||
|
- script.execute: publish_offsets
|
||||||
|
|
||||||
|
# Die gespeicherten Offsets für lesende Clients bereitstellen.
|
||||||
|
- id: publish_offsets
|
||||||
|
then:
|
||||||
|
- ble_server.characteristic.set_value:
|
||||||
|
id: offsets_ble
|
||||||
|
value: !lambda |-
|
||||||
|
std::vector<uint8_t> v(2 * sizeof(float));
|
||||||
|
float values[2] = { id(pitch_offset), id(roll_offset) };
|
||||||
|
memcpy(v.data(), values, sizeof(values));
|
||||||
|
return v;
|
||||||
|
|
||||||
|
esp32_ble_server:
|
||||||
|
manufacturer: "VanAlign"
|
||||||
|
model: "Pro"
|
||||||
|
services:
|
||||||
|
- uuid: 2a24b789-7aab-4535-af3e-ee76a35cc42d
|
||||||
|
advertise: true
|
||||||
|
characteristics:
|
||||||
|
- id: pitch_ble
|
||||||
|
uuid: cad48e28-7fbe-41cf-bae9-d77a6c233424
|
||||||
|
description: "Pitch"
|
||||||
|
read: true
|
||||||
|
notify: true
|
||||||
|
|
||||||
|
- id: roll_ble
|
||||||
|
uuid: cad48e28-7fbe-41cf-bae9-d77a6c233425
|
||||||
|
description: "Roll"
|
||||||
|
read: true
|
||||||
|
notify: true
|
||||||
|
|
||||||
|
# Zwei Floats: die gespeicherten Offsets. Damit kann ein Client
|
||||||
|
# anzeigen, ob und worauf kalibriert wurde.
|
||||||
|
- id: offsets_ble
|
||||||
|
uuid: cad48e28-7fbe-41cf-bae9-d77a6c233426
|
||||||
|
description: "Kalibrier-Offsets"
|
||||||
|
read: true
|
||||||
|
notify: true
|
||||||
|
|
||||||
|
# Ein Byte: 0 setzt die Kalibrierung zurück, alles andere kalibriert
|
||||||
|
# auf die aktuelle Lage.
|
||||||
|
- id: calib_ble
|
||||||
|
uuid: cad48e28-7fbe-41cf-bae9-d77a6c233427
|
||||||
|
description: "Kalibriere Neigung"
|
||||||
|
write: true
|
||||||
|
on_write:
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
bool reset = !x.empty() && (x[0] == 0x00 || x[0] == '0');
|
||||||
|
if (reset) {
|
||||||
|
id(reset_calibration).execute();
|
||||||
|
} else {
|
||||||
|
id(calibrate_level).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
button:
|
||||||
|
- platform: template
|
||||||
|
name: "Kalibriere Neigung"
|
||||||
|
id: calib_button
|
||||||
|
on_press:
|
||||||
|
- script.execute: calibrate_level
|
||||||
|
|
||||||
|
- platform: template
|
||||||
|
name: "Kalibrierung zurücksetzen"
|
||||||
|
id: calib_reset_button
|
||||||
|
on_press:
|
||||||
|
- script.execute: reset_calibration
|
||||||
|
|
||||||
|
- platform: restart
|
||||||
|
name: "ESP Restart"
|
||||||
|
|
||||||
|
text_sensor:
|
||||||
|
- platform: template
|
||||||
|
name: "Firmware Version"
|
||||||
|
id: firmware_version
|
||||||
|
icon: mdi:tag
|
||||||
|
lambda: |-
|
||||||
|
return {"v1.1.0"};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
esphome:
|
||||||
|
name: vanalign
|
||||||
|
friendly_name: "VanAlign Pro"
|
||||||
|
|
||||||
|
|
||||||
|
esp32:
|
||||||
|
board: esp32-s3-devkitc-1
|
||||||
|
|
||||||
|
logger:
|
||||||
|
level: WARN
|
||||||
|
|
||||||
|
espnow:
|
||||||
|
channel: 1
|
||||||
|
on_broadcast:
|
||||||
|
- logger.log:
|
||||||
|
format: "Sent to %s from %s: %s RSSI: %ddBm"
|
||||||
|
args:
|
||||||
|
- format_mac_address_pretty(info.des_addr).c_str()
|
||||||
|
- format_mac_address_pretty(info.src_addr).c_str()
|
||||||
|
- format_hex_pretty(data, size).c_str()
|
||||||
|
- info.rx_ctrl->rssi
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
esphome:
|
||||||
|
name: dual-net-webble
|
||||||
|
|
||||||
|
esp32:
|
||||||
|
board: esp32-s3-devkitc-1
|
||||||
|
framework:
|
||||||
|
type: esp-idf
|
||||||
|
|
||||||
|
logger:
|
||||||
|
baud_rate: 0
|
||||||
|
level: WARN
|
||||||
|
|
||||||
|
wifi:
|
||||||
|
ssid: "DEIN_SSID"
|
||||||
|
password: "DEIN_PASSWORT"
|
||||||
|
enable_on_boot: false
|
||||||
|
|
||||||
|
api:
|
||||||
|
web_server:
|
||||||
|
port: 80
|
||||||
|
# ota: true <-- entfernen!
|
||||||
|
|
||||||
|
ota:
|
||||||
|
- platform: esphome # klassisches OTA (benötigt 'api:')
|
||||||
|
- platform: web_server # OTA im Web-Interface
|
||||||
|
|
||||||
|
|
||||||
|
# BLE-Stack nur für eigenen GATT-Server
|
||||||
|
esp32_ble:
|
||||||
|
enable_on_boot: false
|
||||||
|
|
||||||
|
esp32_ble_server:
|
||||||
|
manufacturer: "MyLab"
|
||||||
|
model: "WebBLE"
|
||||||
|
services:
|
||||||
|
- uuid: "12345678-1234-5678-1234-56789abcdef0"
|
||||||
|
characteristics:
|
||||||
|
# Write "1" -> WLAN-Fenster starten/verlängern
|
||||||
|
- uuid: "12345678-1234-5678-1234-56789abcdef1"
|
||||||
|
name: "StartMaintenance"
|
||||||
|
value: "0"
|
||||||
|
on_write:
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
if (x.get_value().find("1") != std::string::npos) {
|
||||||
|
id(start_wifi_window).execute();
|
||||||
|
}
|
||||||
|
# Status bei Bedarf lesbar (z. B. "WIFI,14" oder "BLE,0")
|
||||||
|
- uuid: "12345678-1234-5678-1234-56789abcdef2"
|
||||||
|
name: "Status"
|
||||||
|
value: "BLE,0"
|
||||||
|
on_read:
|
||||||
|
then:
|
||||||
|
- lambda: |-
|
||||||
|
char buf[16];
|
||||||
|
snprintf(buf, sizeof(buf), "%s,%d",
|
||||||
|
id(_netmode_is_wifi) ? "WIFI" : "BLE",
|
||||||
|
(int) id(_wifi_minutes_left));
|
||||||
|
x.set_value(std::string(buf));
|
||||||
|
|
||||||
|
number:
|
||||||
|
- platform: template
|
||||||
|
id: wifi_window_minu
|
||||||
Reference in New Issue
Block a user