Files
Smart-Dashboard/restricted/home.php
T
adminandClaude Opus 5 eee3a89b4e AutoAction-Editor: Speichern, Laden und Loeschen
Der Editor las seine Geraete aus homeMesh, schrieb aber nach solarLog in
Tabellen, deren Fremdschluessel auf solarLog.actors/sensors zeigten. Jedes
INSERT lief damit gegen den Fremdschluessel - autoactionsSensors und
autoactionsActors sind deshalb leer geblieben, und die Aktor-Schleife war
ohnehin nie geschrieben worden.

Die Automatiken liegen jetzt in homeMesh neben dem Geraetemodell
(homeMesh_automations.sql). Eine Bedingung verweist mit einem einzigen
Fremdschluessel auf actor_states statt auf Geraet, State-URL und ein
unklares valID; Kommandoparameter stehen zeilenweise statt in vier festen
Spalten "Wert 1" bis "Wert 4". Verknuepft wird ueber group_no: gleiche
Nummer UND, verschiedene ODER, ausgewertet als any(all(gruppe)).

Im Editor ist eine Gruppe ein gerahmter Block mit eigenem "+ Bedingung",
dazwischen steht ODER - die Klammerung ist damit gezeichnet und nicht
vereinbart, und darunter steht derselbe Satz noch einmal in Worten. Die
Uebersicht zeigt ihn in der Spalte "Ausloeser" und ersetzt die bisher fest
verdrahtete Beispielzeile.

Nebenbei behoben: die Operator-Knoepfe schickten ihr innerHTML ("≠",
">") an eine Whitelist, die "!=" erwartete - jede Bedingung "ungleich"
wurde still zu "gleich". Ausgeblendete Wertfelder sendeten ihren Inhalt
trotzdem mit. Beides entfaellt, weil der Editor jetzt JSON aus einem
Modell schickt statt durchnummerierter Formularfelder.

Die vier Endpunkte fillSensorDD, fillActorDD, sensorDetails und
actorDetails entfallen: der Geraetekatalog reist einmal mit dem Editor
mit, statt je Bedingungszeile zwei Anfragen nachzuladen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 19:07:29 +02:00

205 lines
13 KiB
PHP

<?php require_once(__DIR__ . "/rooms.php"); ?>
<!--begin::App Main-->
<main class="app-main">
<!--begin::App Content Header-->
<div class="app-content-header">
<!--begin::Container-->
<div class="container-fluid">
<!--begin::Row-->
<div class="row">
<div class="col-sm-12">
<h3 class="mb-0">Home</h3>
</div>
</div>
<!--end::Row-->
</div>
<!--end::Container-->
</div>
<!--end::App Content Header-->
<!--begin::App Content-->
<div class="app-content">
<!--begin::Container-->
<div class="container-fluid">
<!--begin::Row-->
<div class="row">
<!-- Start col -->
<div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 d-flex align-items-stretch">
<div class="card p-0 mb-4" style="width:100%">
<div class="card-header pb-0 pt-1">
<h3 class="card-title">Home</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
<i class="bi bi-x-lg"></i>
</button>
</div>
</div>
<div class="card-body pb-1">
<div lass="img-overlay-wrap">
<svg viewBox="0 0 400 300" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
<defs>
<g id="floorBtn">
<path fill="transparent" stroke-width="4"
d="M 99.86386438745993 22.00011880076356 A 50 50 0 1 0 100 22" />
</g>
<g id="heater" filter="url(#shadow)" transform="translate(1.5,1),scale(0.2,0.2)" fill="#993311" stroke="#FF2211">
<path clip-path="M-22 2.24h42V22h-42z"
d="M16.543 8.028c-.023 1.503-.523 3.538-2.867 4.327.734-1.746.846-3.417.326-4.979-.695-2.097-3.014-3.735-4.557-4.627-.527-.306-1.203.074-1.193.683.02 1.112-.318 2.737-1.959 4.378C4.107 9.994 3 12.251 3 14.517 3 17.362 5 21 9 21c-4.041-4.041-1-7.483-1-7.483C8.846 19.431 12.988 21 15 21c1.711 0 5-1.25 5-6.448 0-3.133-1.332-5.511-2.385-6.899-.347-.458-1.064-.198-1.072.375" />
</g>
<g id="buffer" filter="url(#shadow)" transform="translate(18,1),scale(0.3,0.3)" fill="#ffffff">
<path d="M5 12.5a1.5 1.5 0 1 1-2-1.415V2.5a.5.5 0 0 1 1 0v8.585A1.5 1.5 0 0 1 5 12.5"/>
<path d="M1 2.5a2.5 2.5 0 0 1 5 0v7.55a3.5 3.5 0 1 1-5 0zM3.5 1A1.5 1.5 0 0 0 2 2.5v7.987l-.167.15a2.5 2.5 0 1 0 3.333 0L5 10.486V2.5A1.5 1.5 0 0 0 3.5 1m5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0v-1a.5.5 0 0 1 .5-.5m4.243 1.757a.5.5 0 0 1 0 .707l-.707.708a.5.5 0 1 1-.708-.708l.708-.707a.5.5 0 0 1 .707 0M8 5.5a.5.5 0 0 1 .5-.5 3 3 0 1 1 0 6 .5.5 0 0 1 0-1 2 2 0 0 0 0-4 .5.5 0 0 1-.5-.5M12.5 8a.5.5 0 0 1 .5-.5h1a.5.5 0 1 1 0 1h-1a.5.5 0 0 1-.5-.5m-1.172 2.828a.5.5 0 0 1 .708 0l.707.708a.5.5 0 0 1-.707.707l-.708-.707a.5.5 0 0 1 0-.708M8.5 12a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0v-1a.5.5 0 0 1 .5-.5"/>
</g>
</defs>
<g>
<g id="UGimg" <?php if($_GET["floor"] != "UG"){echo "opacity='0'";} ?> >
<animate begin="UG.click" attributetype="CSS" attributeName="opacity" to=1.0 dur="0.7s"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
<animate begin="EG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
<animate begin="OG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
<image href="assets/img/UG.png" height="100%" width="100%" x=0
y=0 />
</g>
<g id="EGimg" <?php if($_GET["floor"] != "EG"){echo "opacity='0'";} ?> >
<animate begin="EG.click" attributetype="CSS" attributeName="opacity" to=1.0 dur="0.7s"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
<animate begin="OG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
<animate begin="UG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
<image href="assets/img/EG.png" height="100%" width="100%" x=0
y=0 />
</g>
<g id="OGimg" <?php if($_GET["floor"] != "OG"){echo "opacity='0'";} ?> >
<animate begin="OG.click" attributetype="CSS" attributeName="opacity" to=1.0 dur="0.7s"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
<animate begin="EG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
<animate begin="UG.click" attributetype="CSS" attributeName="opacity" to=0.0 dur="0.7s"
repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1" fill="freeze" />
<image href="assets/img/OG.png" border="1px solid white" height="100%" width="100%" x=0
y=0 />
</g>
<g id="OG" onclick="switchFloor('OG')" xcursor="pointer" transform="translate(0,0), scale(0.50,0.50)">
<animate id="showOG" begin=click attributetype="CSS" attributeName="opacity" from=0 to=1
dur="0.1s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze">
</animate>
<use href="#floorBtn" stroke="#aa7713" />
<text fill="#aa7713" style="font: 3em sans-serif;" transform="translate(62,90)">OG</text>
</g>
<g id="EG" onclick="switchFloor('EG')" cursor="pointer" transform="translate(0,100), scale(0.50,0.50)">
<animate id="showEG" begin=click attributetype="CSS" attributeName="opacity" from=0 to=1
dur="0.1s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze"></animate>
<use href="#floorBtn" stroke="#aa7713" />
<text fill="#aa7713" style="font: 3em sans-serif;" transform="translate(64,90)">EG</text>
</g>
<g id="UG" onclick="switchFloor('UG')" cursor="pointer" transform="translate(0,200), scale(0.50,0.50)">
<animate id="showUG" begin=click attributetype="CSS" attributeName="opacity" from=0 to=1
dur="0.1s" repeatCount="1" calcMode="spline" keyTimes="0;1" keySplines=".1,0,.27,1"
fill="freeze"></animate>
<use href="#floorBtn" stroke="#aa7713" />
<text fill="#aa7713" style="font: 3em sans-serif;" transform="translate(63,90)">UG</text>
</g>
<?php foreach ($floors as $floor): ?>
<g id="<?= $floor ?>_Info" <?php if ($floor != "OG") echo 'opacity="0" '; ?><?php if($_GET["floor"] != $floor){echo "display='none'";} ?> >
<?php foreach (roomsOnFloor($floor) as $room): ?>
<g transform="translate(<?= $room["x"] ?>,<?= $room["y"] ?>)" onclick="openHeaterSettings('<?= $floor ?>_<?= $room["mqtt"] ?>');" cursor="pointer">
<rect width="24" height="19" rx="5" fill="#0006" />
<use id="<?= $floor ?>_<?= $room["id"] ?>_heater" href="#heater" display="none" />
<use id="<?= $floor ?>_<?= $room["id"] ?>_buffer" href="#buffer" display="none" />
<text fill="#fff" style="font: 4px sans-serif;">
<tspan id="<?= $floor ?>_pres_<?= $room["id"] ?>" y="5" x="12" text-anchor="middle">---- hPa</tspan>
<tspan id="<?= $floor ?>_tmp_<?= $room["id"] ?>" x="12" dy="1em" font-size="1.6em" text-anchor="middle">--,- °C</tspan>
<tspan id="<?= $floor ?>_hum_<?= $room["id"] ?>" x="12" dy="1.2em" text-anchor="middle">-- %rF</tspan>
</text>
</g>
<?php endforeach; ?>
</g>
<?php endforeach; ?>
</g>
</svg>
</div>
</div>
</div>
<!-- /.card -->
</div>
<div class="col-xxl-12 col-xl-12 col-lg-12 col-md-12 d-flex align-items-stretch">
<div class="card p-0 mb-4" style="width:100%">
<div class="card-header pb-0 pt-1">
<h3 class="card-title">Automatismen</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" data-lte-toggle="card-remove">
<i class="bi bi-x-lg"></i>
</button>
</div>
</div>
<div class="card-body pb-1">
<div class="card-header p-0 pt-1">
<ul class="nav nav-tabs" id="actions-tab" role="tablist">
<li class="nav-item">
<a class="nav-link <?php if($_GET["floor"] == "OG") echo "active"; ?>" id="actions-OG-tab"href="#actions-OG" onclick="switchTab('actions-OG')" aria-controls="actions-OG" aria-selected="true">OG</a>
</li>
<li class="nav-item">
<a class="nav-link <?php if($_GET["floor"] == "EG") echo "active"; ?>" id="actions-EG-tab" href="#actions-EG" onclick="switchTab('actions-EG')" aria-controls="actions-EG" aria-selected="false">EG</a>
</li>
<li class="nav-item">
<a class="nav-link <?php if($_GET["floor"] == "UG") echo "active"; ?>" id="actions-UG-tab" href="#actions-UG" onclick="switchTab('actions-UG')" aria-controls="actions-UG" aria-selected="false">UG</a>
</li>
</ul>
</div>
<div class="tab-content" id="actions-tabContent">
<div class="tab-pane fade <?php if($_GET["floor"] == "OG") echo "active show"; ?>" id="actions-OG" role="tabpanel" aria-labelledby="actions-OG-tab">
<!-- Inhalt kommt aus ajax/AutoAction.php?action=list, gefuellt von
refreshAutomations() in js/solar/autoActionFuncs.js -->
<div id="actions-OG-list">Wird geladen...</div>
<button type="button" class="btn btn-success" title="Neue Automatik"
onclick="openAutoActionModal('?action=editor&floor=OG')"><i class="bi bi-plus-square"></i></button>
</div>
<div class="tab-pane fade <?php if($_GET["floor"] == "EG") echo "active show"; ?>" id="actions-EG" role="tabpanel" aria-labelledby="actions-EG-tab">
<!-- Inhalt kommt aus ajax/AutoAction.php?action=list, gefuellt von
refreshAutomations() in js/solar/autoActionFuncs.js -->
<div id="actions-EG-list">Wird geladen...</div>
<button type="button" class="btn btn-success" title="Neue Automatik"
onclick="openAutoActionModal('?action=editor&floor=EG')"><i class="bi bi-plus-square"></i></button>
</div>
<div class="tab-pane fade <?php if($_GET["floor"] == "UG") echo "active show"; ?>" id="actions-UG" role="tabpanel" aria-labelledby="actions-UG-tab">
<!-- Inhalt kommt aus ajax/AutoAction.php?action=list, gefuellt von
refreshAutomations() in js/solar/autoActionFuncs.js -->
<div id="actions-UG-list">Wird geladen...</div>
<button type="button" class="btn btn-success" title="Neue Automatik"
onclick="openAutoActionModal('?action=editor&floor=UG')"><i class="bi bi-plus-square"></i></button>
</div>
</div>
</div>
</div>
</div>
<!-- /.Start col -->
</div>
<!-- /.row (main row) -->
</div>
<!--end::Container-->
</div>
<!--end::App Content-->
</main>
<!--end::App Main-->
<script>
// Raumtabelle aus restricted/rooms.php - homeMQTT.js aktualisiert darueber
// die SVG-Kacheln, ohne die Raeume noch einmal aufzufuehren.
const homeRooms = <?= json_encode($rooms) ?>;
<?php if ($_GET["floor"] != "OG" && in_array($_GET["floor"], $floors)): ?>
document.addEventListener('readystatechange', function () {
if (event.target.readyState === 'complete') {
switchFloor('<?= $_GET["floor"] ?>');
}
});
<?php endif; ?>
</script>