Beide Wallboxen werden gleich bedient
carEG.php und carOG.php waren fast identisch und unterschieden sich nur im Transportweg: der go-e bekam seine Kommandos per HTTP, die Wattpilot ueber einen eigenen Python-Prozess je Klick, der sich einen Websocket aufbaute, anmeldete, ein Feld setzte und wieder starb. Beide haengen laengst am selben MQTT-Broker - der go-e mit eigenem Client (mce=true, mcr=false), die Wattpilot ueber wattpilot_bruecke.py. Beide nehmen Kommandos auf <praefix><schluessel>/set entgegen. Die Steuerung steht deshalb jetzt einmal in carSteuerung.php; was die Wallboxen wirklich trennt - Topic-Praefix, die Namen ate/att gegen ftt/fte und die Wattstunden je Prozent - steht als Tabelle in restricted/wallboxen.php. Nebenbei faellt damit /volume1/homes/wagner/wattpilot.py weg, das das Passwort der Wallbox im Klartext enthaelt und ausserhalb jedes Repos liegt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
/**
|
||||
* Beide Wallboxen ueber denselben Weg ansteuern: MQTT.
|
||||
*
|
||||
* Bis September 2026 liefen die beiden voellig verschieden. Der go-e bekam
|
||||
* seine Kommandos per HTTP (`api/set?frc=2`), die Wattpilot ueber einen
|
||||
* eigenen Python-Prozess je Klick, der sich einen Websocket aufbaute,
|
||||
* anmeldete, ein Feld setzte und wieder starb - inklusive Passwort im
|
||||
* Klartext in `/volume1/homes/wagner/wattpilot.py`.
|
||||
*
|
||||
* Warum MQTT und nicht HTTP fuer beide: die Wattpilot hat keine lokale
|
||||
* REST-API. Sie beantwortet auf Port 80 jeden Pfad mit 404 und spricht nur
|
||||
* ueber ihren Websocket. Fronius liefert die go-e-Firmware ohne die
|
||||
* HTTP-Schnittstelle aus.
|
||||
*
|
||||
* Warum es umgekehrt geht: der go-e hat einen eigenen MQTT-Client (`mce`),
|
||||
* haengt an unserem Broker (`mcu`) und laesst Schreibzugriffe zu
|
||||
* (`mcr = false`). Die Wattpilot erreicht denselben Broker ueber
|
||||
* `wattpilot_bruecke.py` im SolarManager. Beide nehmen Kommandos auf
|
||||
* `<praefix><schluessel>/set` entgegen und antworten auf
|
||||
* `<praefix><schluessel>/result` mit `success` oder einer Fehlermeldung.
|
||||
*
|
||||
* Der Lesestand liegt ohnehin schon auf demselben Broker - der Browser
|
||||
* abonniert `go-eCharger/270003/...` und `wattpilot/properties/.../state`
|
||||
* nebeneinander (js/solar/solarMQTT.js).
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . "/../ajax/phpMQTT.php");
|
||||
|
||||
// Der Broker laeuft auf demselben Rechner wie der Webserver. Steht hier und
|
||||
// nicht in commands.php, damit diese Datei nicht die halbe Raumsteuerung
|
||||
// mitzieht, nur um zwei Konstanten zu erben.
|
||||
const WALLBOX_BROKER = "localhost";
|
||||
const WALLBOX_PORT = 1883;
|
||||
|
||||
/**
|
||||
* Die beiden Wallboxen und worin sie sich noch unterscheiden.
|
||||
*
|
||||
* Die Schluessel `frc`, `lmo`, `amp` und `fup` heissen auf beiden gleich -
|
||||
* es ist beides go-e-Firmware. Uebrig bleiben drei echte Unterschiede, und
|
||||
* die stehen hier statt in zwei getrennten Codepfaden.
|
||||
*/
|
||||
function wallboxen()
|
||||
{
|
||||
return [
|
||||
"eg" => [
|
||||
"titel" => "Wattpilot (EG)",
|
||||
"praefix" => "wattpilot/properties/",
|
||||
// Die Bruecke haengt "/set" an den Eigenschaftsnamen an.
|
||||
"namen" => [],
|
||||
// Wattstunden je Prozent des Schiebereglers - Akku des Autos,
|
||||
// das hier haengt.
|
||||
"whProProzent" => 140,
|
||||
// Zeichenketten gehen roh hinaus; die Bruecke gibt sie
|
||||
// unveraendert an die Wallbox weiter.
|
||||
"textInJson" => false,
|
||||
// Die Ladeplanung rechnet mit der Uhr der Wallbox. Beim alten
|
||||
// Python-Aufruf wurde sie vor jedem Moduswechsel gestellt
|
||||
// (-setTime); das bleibt so, damit die Funktion nicht verloren
|
||||
// geht. Der go-e hat das nie gebraucht.
|
||||
"uhrStellen" => true,
|
||||
],
|
||||
"og" => [
|
||||
"titel" => "go-e (OG)",
|
||||
"praefix" => "go-eCharger/270003/",
|
||||
// Zielzeit und Zielenergie heissen hier anders. Die Wattpilot
|
||||
// kennt "ate"/"att" gar nicht, der go-e umgekehrt "fte"/"ftt".
|
||||
"namen" => ["fte" => "ate", "ftt" => "att"],
|
||||
"whProProzent" => 90,
|
||||
// Der go-e liest jeden Wert als JSON. Zeichenketten muessen
|
||||
// deshalb in Anfuehrungszeichen stehen, sonst antwortet er mit
|
||||
// "tried to set api key with invalid json".
|
||||
"textInJson" => true,
|
||||
"uhrStellen" => false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Einen Wert so schreiben, wie die jeweilige Wallbox ihn erwartet.
|
||||
*/
|
||||
function wallboxNutzlast($wert, array $konf)
|
||||
{
|
||||
if (is_bool($wert)) {
|
||||
return $wert ? "true" : "false";
|
||||
}
|
||||
if (is_string($wert) && $konf["textInJson"]) {
|
||||
return json_encode($wert);
|
||||
}
|
||||
return (string) $wert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mehrere Eigenschaften einer Wallbox setzen.
|
||||
*
|
||||
* Die Reihenfolge von $werte bleibt erhalten - sie ist nicht beliebig: der
|
||||
* Modus (`lmo`) kommt zuletzt, damit Zielzeit und Zielenergie schon stehen,
|
||||
* wenn er greift.
|
||||
*
|
||||
* Liefert true, wenn alles beim Broker war. Ob die Wallbox die Werte
|
||||
* genommen hat, steht anschliessend auf den `/result`-Topics; darauf wird
|
||||
* hier nicht gewartet, damit ein Klick nicht an einer stummen Wallbox
|
||||
* haengenbleibt.
|
||||
*/
|
||||
function wallboxSetzen(string $box, array $werte): bool
|
||||
{
|
||||
$alle = wallboxen();
|
||||
if (!isset($alle[$box])) {
|
||||
throw new InvalidArgumentException("Unbekannte Wallbox: " . $box);
|
||||
}
|
||||
$konf = $alle[$box];
|
||||
|
||||
$mqtt = new Bluerhinos\phpMQTT(WALLBOX_BROKER, WALLBOX_PORT,
|
||||
"WallboxWeb-" . bin2hex(random_bytes(4)));
|
||||
if (!$mqtt->connect(true, null, "", "")) {
|
||||
error_log("wallboxSetzen: kein Kontakt zum MQTT-Broker");
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($werte as $schluessel => $wert) {
|
||||
$name = $konf["namen"][$schluessel] ?? $schluessel;
|
||||
$mqtt->publish($konf["praefix"] . $name . "/set",
|
||||
wallboxNutzlast($wert, $konf), 0, false);
|
||||
}
|
||||
|
||||
$mqtt->close();
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user