Zahlencodes als Klartext

Manche Geraete schicken eine Zahl und meinen einen Zustand - der
go-eCharger etwa 2 fuer "Charging". Welche Zahl welchen Namen hat, steht im
value_template der Home-Assistant-Discovery als Werttabelle:

    {{ ['Unknown','Idle','Charging','WaitCar','Complete','Error'][value_json|int] }}

Das ist kein Pfad in die Nutzlast, sondern eine Uebersetzung, und sie wurde
bisher verworfen. Jetzt landet sie in possible_values - in derselben
Schreibweise, die WLED fuer seine Effektliste schon benutzt, naemlich einer
Liste aus {Wert: Bezeichnung}. Damit versteht der Editor sie ohne
Zusatzarbeit und macht eine Auswahlliste daraus. Ein Versatz im Ausdruck
wandert in die Schluessel: aus [value_json|int-3] wird {"3":"Default"}.

Der Runner uebersetzt beim Lesen, eine Bedingung vergleicht also den
Klartext. Steht die Zahl nicht in der Tabelle, bleibt sie stehen - ein
erfundener Name waere schlimmer als ein roher Wert.

Dabei ist ein Folgefehler aufgefallen: Auswahlwerte in dieser Schreibweise
kamen im Editor als "[object Object]" an. Die alte addOptions kannte die
Form, der neue Modell-Aufbau nicht - aufgefallen ist es nie, weil WLED beim
Umbau abgeschaltet war. Der Katalog liefert Auswahlwerte jetzt einheitlich
als {value, label}, und zwar seitenrichtig:

    Messwert   angezeigt Charging, gespeichert Charging
               (der Runner hat schon uebersetzt)
    Parameter  angezeigt Blink,    gespeichert 1
               (das Geraet will die Zahl)

Die Uebersicht loest die Bezeichnung ebenfalls auf: "Effekt (Blink)" statt
"Effekt (1)".

Nachgemessen: alle fuenf Werttabellen auf dem Broker richtig erkannt,
einschliesslich des Versatzes, kein Fehltreffer unter den 35 uebrigen
Vorlagen. Live liefert der go-eCharger jetzt Idle, Neutral, Auto, Eco und
None statt 1, 0, 0, 4, 0. Ein weiterer Discovery-Lauf aendert keine Zeile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-31 15:44:39 +02:00
co-authored by Claude Opus 5
parent 56b2ab1648
commit 17678da824
7 changed files with 203 additions and 36 deletions
+69 -13
View File
@@ -100,6 +100,43 @@ function lockoutChoices()
];
}
/**
* Auswahlwerte aus possible_values in eine einheitliche Form bringen.
*
* In der Datenbank stehen zwei Schreibweisen. Eine schlichte Liste
* (["open","close"]) und eine Liste aus Ein-Schluessel-Objekten
* ([{"0":"Unknown"},{"1":"Idle"}]) - letztere ueberall dort, wo das Geraet
* eine Zahl schickt und einen Zustand meint.
*
* Was davon der gespeicherte Wert ist, haengt an der Seite:
*
* Messwert: der Runner uebersetzt die Zahl schon beim Lesen in den
* Klartext, eine Bedingung vergleicht also "Charging".
* Parameter: das Geraet will die Zahl - gespeichert wird der Schluessel,
* angezeigt der Klartext.
*/
function optionList($json, $klartextAlsWert)
{
$roh = json_decode($json, true);
if (!is_array($roh)) {
return [];
}
$liste = [];
foreach ($roh as $eintrag) {
if (is_array($eintrag)) {
foreach ($eintrag as $wert => $bezeichnung) {
$liste[] = [
"value" => $klartextAlsWert ? strval($bezeichnung) : strval($wert),
"label" => strval($bezeichnung),
];
}
} else {
$liste[] = ["value" => strval($eintrag), "label" => strval($eintrag)];
}
}
return $liste;
}
/** Wie das Wertfeld im Editor aussieht. */
function inputForType($type, $hasOptions)
{
@@ -187,10 +224,7 @@ function deviceCatalog()
if (!isset($devices[$id])) {
continue;
}
$options = json_decode($row["possible_values"], true);
if (!is_array($options)) {
$options = [];
}
$options = optionList($row["possible_values"], true);
$type = $row["type"] ?: "string";
$devices[$id]["states"][] = [
"id" => intval($row["id"]),
@@ -198,7 +232,7 @@ function deviceCatalog()
"type" => $type,
"input" => inputForType($type, count($options) > 0),
"operators" => operatorChoices($type),
"options" => array_values($options),
"options" => $options,
"unit" => $row["unit"],
"value" => $row["current_value"],
"url" => $row["url"],
@@ -232,10 +266,7 @@ function deviceCatalog()
if (!isset($commands[$cmdId])) {
continue;
}
$options = json_decode($row["possible_values"], true);
if (!is_array($options)) {
$options = [];
}
$options = optionList($row["possible_values"], false);
$type = $row["type"] ?: "string";
// Das passende Kommando im Geraet suchen. Wenige Kommandos je
// Geraet, deshalb reicht die lineare Suche.
@@ -246,7 +277,7 @@ function deviceCatalog()
"name" => $row["parameter_name"],
"type" => $type,
"input" => inputForType($type, count($options) > 0),
"options" => array_values($options),
"options" => $options,
"min" => $row["min_value"] === null ? null : floatval($row["min_value"]),
"max" => $row["max_value"] === null ? null : floatval($row["max_value"]),
"url" => $row["url"],
@@ -564,6 +595,7 @@ function listAutomations($floor)
$namesState = stateNames();
$namesCommand = commandNames();
$labelsParam = parameterLabels();
$list = [];
foreach ($ids as $id) {
@@ -572,7 +604,7 @@ function listAutomations($floor)
continue;
}
$auto["conditionText"] = describeConditions($auto["conditions"], $namesState);
$auto["actionText"] = describeActions($auto["actions"], $namesCommand);
$auto["actionText"] = describeActions($auto["actions"], $namesCommand, $labelsParam);
$list[] = $auto;
}
return $list;
@@ -597,6 +629,25 @@ function stateNames()
return $names;
}
/**
* id => [gespeicherter Wert => Bezeichnung] fuer alle Kommando-Parameter,
* die eine Auswahl haben. Gespeichert wird bei Parametern die Zahl, die das
* Geraet erwartet - in der Uebersicht soll aber "Blink" stehen und nicht "1".
*/
function parameterLabels()
{
$db = meshDb();
$res = $db->query("SELECT id, possible_values FROM command_parameters
WHERE possible_values <> '' AND possible_values <> '[]'");
$labels = [];
while ($row = $res->fetch_assoc()) {
foreach (optionList($row["possible_values"], false) as $option) {
$labels[intval($row["id"])][$option["value"]] = $option["label"];
}
}
return $labels;
}
/** id => "Geraet: Kommando" fuer alle Kommandos. */
function commandNames()
{
@@ -642,12 +693,17 @@ function describeConditions($conditions, $names)
return implode(" oder ", $parts);
}
function describeActions($actions, $names)
function describeActions($actions, $names, $labels = [])
{
$parts = [];
foreach ($actions as $a) {
$text = $names[$a["command_id"]] ?? ("Kommando " . $a["command_id"]);
$values = array_values($a["params"]);
$values = [];
foreach ($a["params"] as $parameterId => $wert) {
// Wo es eine Auswahl gibt, die Bezeichnung nennen: "Blink" sagt
// mehr als die 1, die das Geraet tatsaechlich bekommt.
$values[] = $labels[intval($parameterId)][$wert] ?? $wert;
}
if ($values) {
$text .= " (" . implode(", ", $values) . ")";
}