forked from fritob/Camper-Monitor
Solar-Integration und dev_watch-Geräte zusammenführen
solar-integration (aus dem separaten VanAligneiOS-Repo) und dev_watch haben unabhängige Git-Historien, decken aber überlappende und sich ergänzende Funktionen ab. Übernommen aus solar-integration: Votronic- Solar-ESP-Anbindung samt Geräterolle, die Live-Activity/Widget-Extension fürs Sperrbildschirm/Dynamic-Island/CarPlay, das Querformat-Layout für Libelle/Fahrzeug-Ansicht und Ausrichtungs-Assistent, sowie die mehreren Fahrzeuggrafik-Stile (Vanster/California). Beibehalten aus dev_watch: alle zusätzlichen Geräteprotokolle (Daly-/JBD-BMS, Alpicool- Kühlbox, WattCycle, Victron), die dort zwischenzeitlich entstanden. Die Xcode-Projektdatei wurde von Hand um die neue Widget-Extension samt SharedActivity-Gruppe erweitert (Datei-synchronisierte Gruppen, kein App-Group-Entitlement nötig). Build für App, Watch und Widget-Extension geprüft (Debug und Release). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
812874baef
commit
e9b9c5bcd5
@@ -0,0 +1,332 @@
|
||||
# VanAlign Pro - Neigungsmessung über BLE (SIMULATION)
|
||||
#
|
||||
# Kopie von esp32_ble.yaml für den Fall, dass gerade kein MPU6050 zum
|
||||
# Anschliessen vorhanden ist. Der `platform: mpu6050`-Sensor sowie der
|
||||
# i2c-Bus wurden entfernt und durch Template-Sensoren ersetzt, die
|
||||
# plausible, sich langsam ändernde Beschleunigungswerte erzeugen (ein
|
||||
# gedachter Sensor, der gemütlich hin- und herschaukelt). Pitch/Roll,
|
||||
# Kalibrierung und die BLE-Charakteristiken funktionieren dadurch exakt wie
|
||||
# im Original - nur eben ohne angeschlossene Hardware.
|
||||
#
|
||||
# Name und Friendly Name sind bewusst auf "-sim" abgeändert, damit dieses
|
||||
# Gerät im Netzwerk/BLE nicht mit einem echten VanAlign-Gerät kollidiert.
|
||||
#
|
||||
# Sobald wieder ein echter MPU6050 verfügbar ist, einfach esp32_ble.yaml
|
||||
# weiterverwenden - diese Datei ist nur zum Testen der App/BLE-Anbindung.
|
||||
|
||||
esphome:
|
||||
name: vanalign-sim
|
||||
friendly_name: "VanAlign Pro (Sim)"
|
||||
|
||||
|
||||
esp32:
|
||||
board: esp32-s3-devkitc-1
|
||||
flash_size: 16MB
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
# N16R8: 16 MB Flash + 8 MB PSRAM, beim S3 als Octal-PSRAM angebunden.
|
||||
psram:
|
||||
mode: octal
|
||||
speed: 80MHz
|
||||
|
||||
|
||||
logger:
|
||||
level: WARN
|
||||
|
||||
espnow:
|
||||
channel: 1
|
||||
|
||||
sensor:
|
||||
# Simulierte Rohwerte anstelle des physischen MPU6050. Die Sensor-Lage
|
||||
# (Pitch/Roll) wandert langsam und stetig, wie es ein tatsächlich leicht
|
||||
# schaukelndes Fahrzeug/Werkstück tun würde (Perioden ~75s/~113s).
|
||||
- platform: template
|
||||
name: "MPU6050 Accel X (Sim)"
|
||||
id: accel_x
|
||||
internal: true
|
||||
update_interval: 0.1s
|
||||
lambda: |-
|
||||
float t = millis() / 1000.0f;
|
||||
float pitch_rad = (15.0f * sin(t / 12.0f)) * 3.14159265f / 180.0f;
|
||||
float roll_rad = (10.0f * sin(t / 18.0f + 1.0f)) * 3.14159265f / 180.0f;
|
||||
return -9.80665f * sin(roll_rad) * cos(pitch_rad);
|
||||
|
||||
- platform: template
|
||||
name: "MPU6050 Accel Y (Sim)"
|
||||
id: accel_y
|
||||
internal: true
|
||||
update_interval: 0.1s
|
||||
lambda: |-
|
||||
float t = millis() / 1000.0f;
|
||||
float pitch_rad = (15.0f * sin(t / 12.0f)) * 3.14159265f / 180.0f;
|
||||
return 9.80665f * sin(pitch_rad);
|
||||
|
||||
- platform: template
|
||||
name: "MPU6050 Accel Z (Sim)"
|
||||
id: accel_z
|
||||
internal: true
|
||||
update_interval: 0.1s
|
||||
lambda: |-
|
||||
float t = millis() / 1000.0f;
|
||||
float pitch_rad = (15.0f * sin(t / 12.0f)) * 3.14159265f / 180.0f;
|
||||
float roll_rad = (10.0f * sin(t / 18.0f + 1.0f)) * 3.14159265f / 180.0f;
|
||||
return 9.80665f * cos(roll_rad) * cos(pitch_rad);
|
||||
|
||||
# Gyro-Werte werden nur zur Anzeige simuliert (kleine Winkelgeschwindigkeit
|
||||
# passend zur Schaukelbewegung oben, kein realer Bezug nötig).
|
||||
- platform: template
|
||||
name: "MPU6050 Gyro X-Achse"
|
||||
id: mpu_gyro_x
|
||||
update_interval: 0.1s
|
||||
lambda: |-
|
||||
float t = millis() / 1000.0f;
|
||||
return (10.0f / 18.0f) * cos(t / 18.0f + 1.0f) * 3.14159265f / 180.0f;
|
||||
|
||||
- platform: template
|
||||
name: "MPU6050 Gyro Y-Achse"
|
||||
id: mpu_gyro_y
|
||||
update_interval: 0.1s
|
||||
lambda: |-
|
||||
float t = millis() / 1000.0f;
|
||||
return (15.0f / 12.0f) * cos(t / 12.0f) * 3.14159265f / 180.0f;
|
||||
|
||||
- platform: template
|
||||
name: "MPU6050 Gyro Z-Achse"
|
||||
id: mpu_gyro_z
|
||||
update_interval: 0.1s
|
||||
lambda: |-
|
||||
return 0.0f;
|
||||
|
||||
- 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); // Offset wird hier subtrahiert
|
||||
filters:
|
||||
- sliding_window_moving_average:
|
||||
window_size: 8
|
||||
send_every: 1
|
||||
- exponential_moving_average:
|
||||
alpha: 0.2
|
||||
|
||||
- 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); // Offset wird hier subtrahiert
|
||||
filters:
|
||||
- sliding_window_moving_average:
|
||||
window_size: 8
|
||||
send_every: 1
|
||||
- exponential_moving_average:
|
||||
alpha: 0.2
|
||||
|
||||
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'
|
||||
# Die Einbaulage liegt im Gerät, nicht in den Apps: Sie beschreibt, wie der
|
||||
# Sensor im Fahrzeug sitzt – eine Eigenschaft des Einbaus, nicht des Telefons.
|
||||
# Damit sehen iPhone, Uhr und Android dasselbe, ohne sie je einzeln zu
|
||||
# bestimmen. Angewandt wird sie weiterhin in den Apps; das Gerät verwahrt sie
|
||||
# nur, sonst rechneten ältere Clients die Korrektur ein zweites Mal.
|
||||
- id: orientation_version
|
||||
type: uint8_t
|
||||
restore_value: yes
|
||||
initial_value: '0'
|
||||
- id: orientation_source
|
||||
type: uint8_t
|
||||
restore_value: yes
|
||||
initial_value: '0'
|
||||
- id: orientation_invert_long
|
||||
type: bool
|
||||
restore_value: yes
|
||||
initial_value: 'false'
|
||||
- id: orientation_invert_lat
|
||||
type: bool
|
||||
restore_value: yes
|
||||
initial_value: 'false'
|
||||
- id: orientation_twist
|
||||
type: float
|
||||
restore_value: yes
|
||||
initial_value: '0.0'
|
||||
|
||||
- id: enable_captive
|
||||
type: bool
|
||||
restore_value: yes
|
||||
initial_value: 'false'
|
||||
|
||||
esp32_ble_server:
|
||||
services:
|
||||
- uuid: 2a24b789-7aab-4535-af3e-ee76a35cc42d
|
||||
advertise: true
|
||||
characteristics:
|
||||
- id: pitch_ble
|
||||
uuid: cad48e28-7fbe-41cf-bae9-d77a6c233424
|
||||
description: "Pitch"
|
||||
read: true
|
||||
value: !lambda |-
|
||||
std::vector<unsigned char> v(sizeof(float));
|
||||
float val = id(pitch).state;
|
||||
memcpy(v.data(), &val, sizeof(float));
|
||||
return v;
|
||||
- id: roll_ble
|
||||
uuid: cad48e28-7fbe-41cf-bae9-d77a6c233425
|
||||
description: "Roll"
|
||||
read: true
|
||||
value: !lambda |-
|
||||
std::vector<unsigned char> v(sizeof(float));
|
||||
float val = id(roll).state;
|
||||
memcpy(v.data(), &val, sizeof(float));
|
||||
return v;
|
||||
# Die gespeicherten Nullpunkte, zwei Floats. Daran erkennen die Apps,
|
||||
# ob überhaupt schon kalibriert wurde.
|
||||
- id: offsets_ble
|
||||
uuid: cad48e28-7fbe-41cf-bae9-d77a6c233426
|
||||
description: "Kalibrier-Offsets"
|
||||
read: true
|
||||
value: !lambda |-
|
||||
std::vector<unsigned char> v(2 * sizeof(float));
|
||||
float p = id(pitch_offset);
|
||||
float r = id(roll_offset);
|
||||
memcpy(v.data(), &p, sizeof(float));
|
||||
memcpy(v.data() + sizeof(float), &r, sizeof(float));
|
||||
return v;
|
||||
|
||||
# Die Einbaulage, acht Byte:
|
||||
#
|
||||
# 0 Version, 1 = gültig gesetzt, 0 = nie geschrieben
|
||||
# 1 Längsachse: 0 = Pitch des Sensors, 1 = Roll des Sensors
|
||||
# 2 längs umgekehrt (0/1)
|
||||
# 3 quer umgekehrt (0/1)
|
||||
# 4..7 Verdrehung um die Hochachse, float32, Grad
|
||||
- id: orientation_ble
|
||||
uuid: cad48e28-7fbe-41cf-bae9-d77a6c233428
|
||||
description: "Einbaulage"
|
||||
read: true
|
||||
write: true
|
||||
value: !lambda |-
|
||||
std::vector<unsigned char> v(8, 0);
|
||||
v[0] = id(orientation_version);
|
||||
v[1] = id(orientation_source);
|
||||
v[2] = id(orientation_invert_long) ? 1 : 0;
|
||||
v[3] = id(orientation_invert_lat) ? 1 : 0;
|
||||
float t = id(orientation_twist);
|
||||
memcpy(v.data() + 4, &t, sizeof(float));
|
||||
return v;
|
||||
on_write:
|
||||
then:
|
||||
- lambda: |-
|
||||
if (x.size() < 8 || x[0] != 1) {
|
||||
ESP_LOGW("vanalign", "Einbaulage verworfen: %d Byte, Version %d",
|
||||
(int) x.size(), x.empty() ? -1 : (int) x[0]);
|
||||
return;
|
||||
}
|
||||
float t;
|
||||
memcpy(&t, x.data() + 4, sizeof(float));
|
||||
if (!std::isfinite(t) || fabsf(t) > 180.0f) {
|
||||
ESP_LOGW("vanalign", "Einbaulage verworfen: Verdrehung %.1f", t);
|
||||
return;
|
||||
}
|
||||
id(orientation_version) = 1;
|
||||
id(orientation_source) = x[1];
|
||||
id(orientation_invert_long) = x[2] != 0;
|
||||
id(orientation_invert_lat) = x[3] != 0;
|
||||
id(orientation_twist) = t;
|
||||
ESP_LOGI("vanalign", "Einbaulage gespeichert: Quelle=%d laengs=%d quer=%d verdreht=%.1f",
|
||||
(int) x[1], (int) x[2], (int) x[3], t);
|
||||
|
||||
- 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();
|
||||
}
|
||||
|
||||
#web_server:
|
||||
# port: 80
|
||||
|
||||
|
||||
#ota:
|
||||
# platform: web_server
|
||||
|
||||
|
||||
#wifi:
|
||||
# ap:
|
||||
# ssid: "VanAlign-Setup"
|
||||
# password: "kalibrierung"
|
||||
|
||||
|
||||
|
||||
script:
|
||||
# Die aktuelle Lage wird zur neuen Null. 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));
|
||||
|
||||
- id: reset_calibration
|
||||
then:
|
||||
- lambda: |-
|
||||
id(pitch_offset) = 0.0f;
|
||||
id(roll_offset) = 0.0f;
|
||||
ESP_LOGI("vanalign", "Kalibrierung zurückgesetzt");
|
||||
|
||||
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.0.2-sim"};
|
||||
Reference in New Issue
Block a user