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:
+69
-13
@@ -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) . ")";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user