Tunable
This commit is contained in:
parent
850d23f293
commit
bb2af44542
44
data/G
44
data/G
@ -8,8 +8,8 @@
|
|||||||
<GA Id="P-02E5-0_GA-43" Address="1" Name="Erdgeschoss / Szene" Description="" DatapointType="DPST-17-1" Puid="156" />
|
<GA Id="P-02E5-0_GA-43" Address="1" Name="Erdgeschoss / Szene" Description="" DatapointType="DPST-17-1" Puid="156" />
|
||||||
<GA Id="P-02E5-0_GA-48" Address="22" Name="Haus / Tag, Nacht" Description="" DatapointType="DPST-1-2" Puid="178" />
|
<GA Id="P-02E5-0_GA-48" Address="22" Name="Haus / Tag, Nacht" Description="" DatapointType="DPST-1-2" Puid="178" />
|
||||||
<GA Id="P-02E5-0_GA-86" Address="28" Name="Wohnzimmer / Licht / Vorne / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="284" />
|
<GA Id="P-02E5-0_GA-86" Address="28" Name="Wohnzimmer / Licht / Vorne / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="284" />
|
||||||
<GA Id="P-02E5-0_GA-108" Address="4" Name="Wohnzimmer / Fernseher / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="347" />
|
<GA Id="P-02E5-0_GA-108" Address="4" Name="Wohnzimmer / Verstärker / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="347" />
|
||||||
<GA Id="P-02E5-0_GA-109" Address="20" Name="Wohnzimmer / Fernseher / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="349" />
|
<GA Id="P-02E5-0_GA-109" Address="20" Name="Wohnzimmer / Verstärker / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="349" />
|
||||||
</GR>
|
</GR>
|
||||||
<GR Id="P-02E5-0_GR-5" RangeStart="768" RangeEnd="1023" Name="Neue Mittelgruppe" Puid="331">
|
<GR Id="P-02E5-0_GR-5" RangeStart="768" RangeEnd="1023" Name="Neue Mittelgruppe" Puid="331">
|
||||||
<GA Id="P-02E5-0_GA-107" Address="770" Name="Obergeschoss / Szene" Description="" DatapointType="DPST-17-1" Puid="336" />
|
<GA Id="P-02E5-0_GA-107" Address="770" Name="Obergeschoss / Szene" Description="" DatapointType="DPST-17-1" Puid="336" />
|
||||||
@ -39,8 +39,8 @@
|
|||||||
<GA Id="P-02E5-0_GA-197" Address="844" Name="Schlafzimmer / Löwe / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="588" />
|
<GA Id="P-02E5-0_GA-197" Address="844" Name="Schlafzimmer / Löwe / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="588" />
|
||||||
<GA Id="P-02E5-0_GA-198" Address="845" Name="Schlafzimmer / Sternenhimmel / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="590" />
|
<GA Id="P-02E5-0_GA-198" Address="845" Name="Schlafzimmer / Sternenhimmel / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="590" />
|
||||||
<GA Id="P-02E5-0_GA-199" Address="846" Name="Schlafzimmer / Sternenhimmel / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="592" />
|
<GA Id="P-02E5-0_GA-199" Address="846" Name="Schlafzimmer / Sternenhimmel / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="592" />
|
||||||
<GA Id="P-02E5-0_GA-201" Address="824" Name="Wohnzimmer / Verstärker / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="638" />
|
<GA Id="P-02E5-0_GA-201" Address="824" Name="Wohnzimmer / Fernseher / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="638" />
|
||||||
<GA Id="P-02E5-0_GA-202" Address="825" Name="Wohnzimmer / Verstärker / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="640" />
|
<GA Id="P-02E5-0_GA-202" Address="825" Name="Wohnzimmer / Fernseher / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="640" />
|
||||||
<GA Id="P-02E5-0_GA-203" Address="828" Name="Wohnzimmer / Licht / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="642" />
|
<GA Id="P-02E5-0_GA-203" Address="828" Name="Wohnzimmer / Licht / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="642" />
|
||||||
<GA Id="P-02E5-0_GA-204" Address="837" Name="Wohnzimmer / Licht / Helligkeit / Schritt" Description="" DatapointType="DPST-3-7" Puid="644" />
|
<GA Id="P-02E5-0_GA-204" Address="837" Name="Wohnzimmer / Licht / Helligkeit / Schritt" Description="" DatapointType="DPST-3-7" Puid="644" />
|
||||||
<GA Id="P-02E5-0_GA-205" Address="847" Name="Wohnzimmer / Licht / Farbtemperatur / Schritt" Description="" DatapointType="DPST-3-7" Puid="646" />
|
<GA Id="P-02E5-0_GA-205" Address="847" Name="Wohnzimmer / Licht / Farbtemperatur / Schritt" Description="" DatapointType="DPST-3-7" Puid="646" />
|
||||||
@ -58,8 +58,8 @@
|
|||||||
<GA Id="P-02E5-0_GA-232" Address="1047" Name="Flur OG / Gesamt / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="716" />
|
<GA Id="P-02E5-0_GA-232" Address="1047" Name="Flur OG / Gesamt / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="716" />
|
||||||
<GA Id="P-02E5-0_GA-248" Address="1048" Name="Wohnzimmer / Rollladen / Links / Position" Description="" DatapointType="DPST-5-1" Puid="759" />
|
<GA Id="P-02E5-0_GA-248" Address="1048" Name="Wohnzimmer / Rollladen / Links / Position" Description="" DatapointType="DPST-5-1" Puid="759" />
|
||||||
<GA Id="P-02E5-0_GA-272" Address="1049" Name="Wohnzimmer / Licht / Status / Lesen" Description="" DatapointType="DPST-1-2" Puid="851" />
|
<GA Id="P-02E5-0_GA-272" Address="1049" Name="Wohnzimmer / Licht / Status / Lesen" Description="" DatapointType="DPST-1-2" Puid="851" />
|
||||||
<GA Id="P-02E5-0_GA-282" Address="1035" Name="Vorgarten / Steckdosen / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="960" />
|
<GA Id="P-02E5-0_GA-282" Address="1035" Name="Vorgarten / Dekoration / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="960" />
|
||||||
<GA Id="P-02E5-0_GA-283" Address="1036" Name="Vorgarten / Steckdosen / Status / Lesen" Description="" DatapointType="DPST-1-11" Puid="962" />
|
<GA Id="P-02E5-0_GA-283" Address="1036" Name="Vorgarten / Dekoration / Status / Lesen" Description="" DatapointType="DPST-1-11" Puid="962" />
|
||||||
</GR>
|
</GR>
|
||||||
<GR Id="P-02E5-0_GR-7" RangeStart="1280" RangeEnd="1535" Name="Neue Mittelgruppe" Puid="704">
|
<GR Id="P-02E5-0_GR-7" RangeStart="1280" RangeEnd="1535" Name="Neue Mittelgruppe" Puid="704">
|
||||||
<GA Id="P-02E5-0_GA-228" Address="1280" Name="Waschküche / Licht / Neon / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="705" />
|
<GA Id="P-02E5-0_GA-228" Address="1280" Name="Waschküche / Licht / Neon / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="705" />
|
||||||
@ -95,8 +95,8 @@
|
|||||||
<GA Id="P-02E5-0_GA-382" Address="1312" Name="Bad / Licht / Spiegel / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="1386" />
|
<GA Id="P-02E5-0_GA-382" Address="1312" Name="Bad / Licht / Spiegel / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="1386" />
|
||||||
<GA Id="P-02E5-0_GA-383" Address="1313" Name="Bad / Licht / Spiegel / Status / Lesen" Description="" DatapointType="DPST-1-2" Puid="1388" />
|
<GA Id="P-02E5-0_GA-383" Address="1313" Name="Bad / Licht / Spiegel / Status / Lesen" Description="" DatapointType="DPST-1-2" Puid="1388" />
|
||||||
<GA Id="P-02E5-0_GA-384" Address="1314" Name="Bad / Licht / Spiegel / Helligkeit / Schritt" Description="" DatapointType="DPST-3-7" Puid="1390" />
|
<GA Id="P-02E5-0_GA-384" Address="1314" Name="Bad / Licht / Spiegel / Helligkeit / Schritt" Description="" DatapointType="DPST-3-7" Puid="1390" />
|
||||||
<GA Id="P-02E5-0_GA-423" Address="1303" Name="Schlafzimmer / Rollladen / Links / Position Anfahren" Description="" DatapointType="DPST-5-1" Puid="1495" />
|
<GA Id="P-02E5-0_GA-423" Address="1303" Name="Schlafzimmer / Rollladen / Links / Position" Description="" DatapointType="DPST-5-1" Puid="1495" />
|
||||||
<GA Id="P-02E5-0_GA-424" Address="1304" Name="Schlafzimmer / Rollladen / Rechts / Position Anfahren" Description="" DatapointType="DPST-5-1" Puid="1497" />
|
<GA Id="P-02E5-0_GA-424" Address="1304" Name="Schlafzimmer / Rollladen / Rechts / Position" Description="" DatapointType="DPST-5-1" Puid="1497" />
|
||||||
<GA Id="P-02E5-0_GA-435" Address="1315" Name="Schlafzimmer / Licht / Farbtemperatur / Setzen" DatapointType="DPST-5-1" Puid="1561" />
|
<GA Id="P-02E5-0_GA-435" Address="1315" Name="Schlafzimmer / Licht / Farbtemperatur / Setzen" DatapointType="DPST-5-1" Puid="1561" />
|
||||||
<GA Id="P-02E5-0_GA-436" Address="1316" Name="Schlafzimmer / Licht / Farbtemperatur / Lesen" DatapointType="DPST-5-1" Puid="1563" />
|
<GA Id="P-02E5-0_GA-436" Address="1316" Name="Schlafzimmer / Licht / Farbtemperatur / Lesen" DatapointType="DPST-5-1" Puid="1563" />
|
||||||
<GA Id="P-02E5-0_GA-441" Address="1317" Name="Bad / Licht / Farbtemperatur / Setzen" DatapointType="DPST-5-1" Puid="1573" />
|
<GA Id="P-02E5-0_GA-441" Address="1317" Name="Bad / Licht / Farbtemperatur / Setzen" DatapointType="DPST-5-1" Puid="1573" />
|
||||||
@ -126,7 +126,7 @@
|
|||||||
<GA Id="P-02E5-0_GA-297" Address="1804" Name="Emil / Steckdose Fenster Links / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="1012" />
|
<GA Id="P-02E5-0_GA-297" Address="1804" Name="Emil / Steckdose Fenster Links / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="1012" />
|
||||||
<GA Id="P-02E5-0_GA-298" Address="1805" Name="Emil / Rollladen / Fahren" Description="" DatapointType="DPST-1-8" Puid="1014" />
|
<GA Id="P-02E5-0_GA-298" Address="1805" Name="Emil / Rollladen / Fahren" Description="" DatapointType="DPST-1-8" Puid="1014" />
|
||||||
<GA Id="P-02E5-0_GA-299" Address="1806" Name="Emil / Rollladen / Stopp" Description="" DatapointType="DPST-1-1" Puid="1016" />
|
<GA Id="P-02E5-0_GA-299" Address="1806" Name="Emil / Rollladen / Stopp" Description="" DatapointType="DPST-1-1" Puid="1016" />
|
||||||
<GA Id="P-02E5-0_GA-300" Address="1807" Name="Emil / Rollladen / Position Anfahren" Description="" DatapointType="DPST-5-1" Puid="1018" />
|
<GA Id="P-02E5-0_GA-300" Address="1807" Name="Emil / Rollladen / Position" Description="" DatapointType="DPST-5-1" Puid="1018" />
|
||||||
<GA Id="P-02E5-0_GA-320" Address="1808" Name="Flur EG / Licht / Szene" Description="" DatapointType="DPST-17-1" Puid="1093" />
|
<GA Id="P-02E5-0_GA-320" Address="1808" Name="Flur EG / Licht / Szene" Description="" DatapointType="DPST-17-1" Puid="1093" />
|
||||||
<GA Id="P-02E5-0_GA-323" Address="1809" Name="Flur EG / Langzeitpräsenz" Description="" DatapointType="DPST-1-2" Puid="1153" />
|
<GA Id="P-02E5-0_GA-323" Address="1809" Name="Flur EG / Langzeitpräsenz" Description="" DatapointType="DPST-1-2" Puid="1153" />
|
||||||
<GA Id="P-02E5-0_GA-324" Address="1810" Name="Wohnzimmer / Langzeitpräsenz" Description="" DatapointType="DPST-1-2" Puid="1155" />
|
<GA Id="P-02E5-0_GA-324" Address="1810" Name="Wohnzimmer / Langzeitpräsenz" Description="" DatapointType="DPST-1-2" Puid="1155" />
|
||||||
@ -144,8 +144,8 @@
|
|||||||
<GA Id="P-02E5-0_GA-404" Address="1820" Name="Waschküche / Rollladen / Position" Description="" DatapointType="DPST-5-1" Puid="1441" />
|
<GA Id="P-02E5-0_GA-404" Address="1820" Name="Waschküche / Rollladen / Position" Description="" DatapointType="DPST-5-1" Puid="1441" />
|
||||||
<GA Id="P-02E5-0_GA-405" Address="1821" Name="Waschküche / Szene" Description="" DatapointType="DPST-17-1" Puid="1443" />
|
<GA Id="P-02E5-0_GA-405" Address="1821" Name="Waschküche / Szene" Description="" DatapointType="DPST-17-1" Puid="1443" />
|
||||||
<GA Id="P-02E5-0_GA-425" Address="1811" Name="Wohnzimmer / Rollladen / Rechts / Position" Description="" DatapointType="DPST-5-1" Puid="1523" />
|
<GA Id="P-02E5-0_GA-425" Address="1811" Name="Wohnzimmer / Rollladen / Rechts / Position" Description="" DatapointType="DPST-5-1" Puid="1523" />
|
||||||
<GA Id="P-02E5-0_GA-426" Address="1822" Name="Wohnzimmer / Weihnachtsbeleuchtung / Status / Setzen" DatapointType="DPST-1-1" Puid="1531" />
|
<GA Id="P-02E5-0_GA-426" Address="1822" Name="Wohnzimmer / Fenster Dekoration / Status / Setzen" DatapointType="DPST-1-1" Puid="1531" />
|
||||||
<GA Id="P-02E5-0_GA-427" Address="1823" Name="Wohnzimmer / Weihnachtsbeleuchtung / Status / Lesen" DatapointType="DPST-1-11" Puid="1533" />
|
<GA Id="P-02E5-0_GA-427" Address="1823" Name="Wohnzimmer / Fenster Dekoration / Status / Lesen" DatapointType="DPST-1-11" Puid="1533" />
|
||||||
<GA Id="P-02E5-0_GA-431" Address="1824" Name="Wohnzimmer / Licht / Farbtemperatur / Setzen" DatapointType="DPST-5-1" Puid="1553" />
|
<GA Id="P-02E5-0_GA-431" Address="1824" Name="Wohnzimmer / Licht / Farbtemperatur / Setzen" DatapointType="DPST-5-1" Puid="1553" />
|
||||||
<GA Id="P-02E5-0_GA-432" Address="1825" Name="Wohnzimmer / Licht / Farbtemperatur / Lesen" DatapointType="DPST-5-1" Puid="1555" />
|
<GA Id="P-02E5-0_GA-432" Address="1825" Name="Wohnzimmer / Licht / Farbtemperatur / Lesen" DatapointType="DPST-5-1" Puid="1555" />
|
||||||
<GA Id="P-02E5-0_GA-451" Address="1826" Name="Waschküche / Licht / Spots / Setzen" DatapointType="DPST-1-1" Puid="1597" />
|
<GA Id="P-02E5-0_GA-451" Address="1826" Name="Waschküche / Licht / Spots / Setzen" DatapointType="DPST-1-1" Puid="1597" />
|
||||||
@ -174,7 +174,7 @@
|
|||||||
<GA Id="P-02E5-0_GA-314" Address="2061" Name="Arbeitszimmer / Gesamt / Status / Lesen" Description="" DatapointType="DPST-1-2" Puid="1073" />
|
<GA Id="P-02E5-0_GA-314" Address="2061" Name="Arbeitszimmer / Gesamt / Status / Lesen" Description="" DatapointType="DPST-1-2" Puid="1073" />
|
||||||
<GA Id="P-02E5-0_GA-315" Address="2062" Name="Arbeitszimmer / Rollladen / Fahren" Description="" DatapointType="DPST-1-8" Puid="1076" />
|
<GA Id="P-02E5-0_GA-315" Address="2062" Name="Arbeitszimmer / Rollladen / Fahren" Description="" DatapointType="DPST-1-8" Puid="1076" />
|
||||||
<GA Id="P-02E5-0_GA-316" Address="2063" Name="Arbeitszimmer / Rollladen / Stopp" Description="" DatapointType="DPST-1-1" Puid="1078" />
|
<GA Id="P-02E5-0_GA-316" Address="2063" Name="Arbeitszimmer / Rollladen / Stopp" Description="" DatapointType="DPST-1-1" Puid="1078" />
|
||||||
<GA Id="P-02E5-0_GA-317" Address="2064" Name="Arbeitszimmer / Rollladen / Position Setzen" Description="" DatapointType="DPST-5-1" Puid="1080" />
|
<GA Id="P-02E5-0_GA-317" Address="2064" Name="Arbeitszimmer / Rollladen / Position" Description="" DatapointType="DPST-5-1" Puid="1080" />
|
||||||
<GA Id="P-02E5-0_GA-318" Address="2065" Name="Arbeitszimmer / Drucker / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="1082" />
|
<GA Id="P-02E5-0_GA-318" Address="2065" Name="Arbeitszimmer / Drucker / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="1082" />
|
||||||
<GA Id="P-02E5-0_GA-319" Address="2066" Name="Arbeitszimmer / Drucker / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="1084" />
|
<GA Id="P-02E5-0_GA-319" Address="2066" Name="Arbeitszimmer / Drucker / Status / Lesen" Description="" DatapointType="DPST-1-1" Puid="1084" />
|
||||||
<GA Id="P-02E5-0_GA-354" Address="2071" Name="Emil / Steckdose Wand Scheune / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="1280" />
|
<GA Id="P-02E5-0_GA-354" Address="2071" Name="Emil / Steckdose Wand Scheune / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="1280" />
|
||||||
@ -204,13 +204,13 @@
|
|||||||
<GA Id="P-02E5-0_GA-357" Address="2307" Name="Außen / Szene" Description="" DatapointType="DPST-17-1" Puid="1287" />
|
<GA Id="P-02E5-0_GA-357" Address="2307" Name="Außen / Szene" Description="" DatapointType="DPST-17-1" Puid="1287" />
|
||||||
<GA Id="P-02E5-0_GA-390" Address="2314" Name="Küche / Rollladen / Seite / Fahren" Description="" DatapointType="DPST-1-8" Puid="1408" />
|
<GA Id="P-02E5-0_GA-390" Address="2314" Name="Küche / Rollladen / Seite / Fahren" Description="" DatapointType="DPST-1-8" Puid="1408" />
|
||||||
<GA Id="P-02E5-0_GA-391" Address="2315" Name="Küche / Rollladen / Seite / Stopp" Description="" DatapointType="DPST-1-7" Puid="1410" />
|
<GA Id="P-02E5-0_GA-391" Address="2315" Name="Küche / Rollladen / Seite / Stopp" Description="" DatapointType="DPST-1-7" Puid="1410" />
|
||||||
<GA Id="P-02E5-0_GA-392" Address="2316" Name="Küche / Rollladen / Seite / Position Setzen" Description="" DatapointType="DPST-5-1" Puid="1412" />
|
<GA Id="P-02E5-0_GA-392" Address="2316" Name="Küche / Rollladen / Seite / Position" Description="" DatapointType="DPST-5-1" Puid="1412" />
|
||||||
<GA Id="P-02E5-0_GA-394" Address="2318" Name="Küche / Rollladen / Theke / Fahren" Description="" DatapointType="DPST-1-8" Puid="1416" />
|
<GA Id="P-02E5-0_GA-394" Address="2318" Name="Küche / Rollladen / Theke / Fahren" Description="" DatapointType="DPST-1-8" Puid="1416" />
|
||||||
<GA Id="P-02E5-0_GA-395" Address="2319" Name="Küche / Rollladen / Theke / Stopp" Description="" DatapointType="DPST-1-7" Puid="1418" />
|
<GA Id="P-02E5-0_GA-395" Address="2319" Name="Küche / Rollladen / Theke / Stopp" Description="" DatapointType="DPST-1-7" Puid="1418" />
|
||||||
<GA Id="P-02E5-0_GA-396" Address="2320" Name="Küche / Rollladen / Theke / Position Setzen" Description="" DatapointType="DPST-5-1" Puid="1420" />
|
<GA Id="P-02E5-0_GA-396" Address="2320" Name="Küche / Rollladen / Theke / Position" Description="" DatapointType="DPST-5-1" Puid="1420" />
|
||||||
<GA Id="P-02E5-0_GA-398" Address="2322" Name="Küche / Rollladen / Tür / Fahren" Description="" DatapointType="DPST-1-8" Puid="1424" />
|
<GA Id="P-02E5-0_GA-398" Address="2322" Name="Küche / Rollladen / Tür / Fahren" Description="" DatapointType="DPST-1-8" Puid="1424" />
|
||||||
<GA Id="P-02E5-0_GA-399" Address="2323" Name="Küche / Rollladen / Tür / Stopp" Description="" DatapointType="DPST-1-7" Puid="1426" />
|
<GA Id="P-02E5-0_GA-399" Address="2323" Name="Küche / Rollladen / Tür / Stopp" Description="" DatapointType="DPST-1-7" Puid="1426" />
|
||||||
<GA Id="P-02E5-0_GA-400" Address="2324" Name="Küche / Rollladen / Tür / Position Setzen" Description="" DatapointType="DPST-5-1" Puid="1428" />
|
<GA Id="P-02E5-0_GA-400" Address="2324" Name="Küche / Rollladen / Tür / Position" Description="" DatapointType="DPST-5-1" Puid="1428" />
|
||||||
<GA Id="P-02E5-0_GA-406" Address="2326" Name="Küche / Rollladen / Tür / Zwang AUF" Description="" DatapointType="DPT-1" Puid="1445" />
|
<GA Id="P-02E5-0_GA-406" Address="2326" Name="Küche / Rollladen / Tür / Zwang AUF" Description="" DatapointType="DPT-1" Puid="1445" />
|
||||||
<GA Id="P-02E5-0_GA-408" Address="2304" Name="Küche / Licht / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="1453" />
|
<GA Id="P-02E5-0_GA-408" Address="2304" Name="Küche / Licht / Status / Setzen" Description="" DatapointType="DPST-1-1" Puid="1453" />
|
||||||
<GA Id="P-02E5-0_GA-409" Address="2305" Name="Küche / Licht / Helligkeit / Schritt" Description="" DatapointType="DPST-3-7" Puid="1455" />
|
<GA Id="P-02E5-0_GA-409" Address="2305" Name="Küche / Licht / Helligkeit / Schritt" Description="" DatapointType="DPST-3-7" Puid="1455" />
|
||||||
@ -227,6 +227,20 @@
|
|||||||
<GA Id="P-02E5-0_GA-433" Address="2325" Name="Flur EG / Licht / Farbtemperatur / Setzen" DatapointType="DPST-5-1" Puid="1557" />
|
<GA Id="P-02E5-0_GA-433" Address="2325" Name="Flur EG / Licht / Farbtemperatur / Setzen" DatapointType="DPST-5-1" Puid="1557" />
|
||||||
<GA Id="P-02E5-0_GA-434" Address="2327" Name="Flur EG / Licht / Farbtemperatur / Lesen" DatapointType="DPST-5-1" Puid="1559" />
|
<GA Id="P-02E5-0_GA-434" Address="2327" Name="Flur EG / Licht / Farbtemperatur / Lesen" DatapointType="DPST-5-1" Puid="1559" />
|
||||||
<GA Id="P-02E5-0_GA-459" Address="2330" Name="Haus / Überwachung / Bewegung" DatapointType="DPST-1-1" Puid="1613" />
|
<GA Id="P-02E5-0_GA-459" Address="2330" Name="Haus / Überwachung / Bewegung" DatapointType="DPST-1-1" Puid="1613" />
|
||||||
|
<GA Id="P-02E5-0_GA-462" Address="2331" Name="Flur OG / Fenster Dekoration / Lesen" DatapointType="DPST-1-11" Puid="1621" />
|
||||||
|
<GA Id="P-02E5-0_GA-463" Address="2332" Name="Flur OG / Fenster Dekoration / Setzen" DatapointType="DPST-1-1" Puid="1623" />
|
||||||
|
<GA Id="P-02E5-0_GA-464" Address="2333" Name="Schlafzimmer / Fenster Dekoration / Lesen" DatapointType="DPST-1-11" Puid="1625" />
|
||||||
|
<GA Id="P-02E5-0_GA-465" Address="2334" Name="Schlafzimmer / Fenster Dekoration / Setzen" DatapointType="DPST-1-1" Puid="1627" />
|
||||||
|
<GA Id="P-02E5-0_GA-466" Address="2335" Name="Wohnzimmer / Steckdose / Hinter Tür / Lesen" DatapointType="DPST-1-11" Puid="1634" />
|
||||||
|
<GA Id="P-02E5-0_GA-467" Address="2336" Name="Wohnzimmer / Steckdose / Hinter Tür / Setzen" DatapointType="DPST-1-1" Puid="1636" />
|
||||||
|
<GA Id="P-02E5-0_GA-468" Address="2337" Name="Terrasse / Dekoration / Lesen" DatapointType="DPST-1-11" Puid="1638" />
|
||||||
|
<GA Id="P-02E5-0_GA-469" Address="2338" Name="Terrasse / Dekoration / Setzen" DatapointType="DPST-1-1" Puid="1640" />
|
||||||
|
<GA Id="P-02E5-0_GA-470" Address="2339" Name="Flur EG / Licht / Helligkeit / Setzen" DatapointType="DPST-5-1" Puid="1642" />
|
||||||
|
<GA Id="P-02E5-0_GA-471" Address="2340" Name="Flur EG / Licht / Helligkeit / Lesen" DatapointType="DPST-5-1" Puid="1644" />
|
||||||
|
<GA Id="P-02E5-0_GA-472" Address="2341" Name="Küche / Licht / Helligkeit / Setzen" DatapointType="DPST-5-1" Puid="1646" />
|
||||||
|
<GA Id="P-02E5-0_GA-473" Address="2342" Name="Küche / Licht / Helligkeit / Lesen" DatapointType="DPST-5-1" Puid="1648" />
|
||||||
|
<GA Id="P-02E5-0_GA-474" Address="2343" Name="Wohnzimmer / Licht / Helligkeit / Setzen" DatapointType="DPST-5-1" Puid="1652" />
|
||||||
|
<GA Id="P-02E5-0_GA-475" Address="2344" Name="Wohnzimmer / Licht / Helligkeit / Lesen" DatapointType="DPST-5-1" Puid="1654" />
|
||||||
</GR>
|
</GR>
|
||||||
<GR Id="P-02E5-0_GR-14" RangeStart="2560" RangeEnd="2815" Name="Neue Mittelgruppe" Puid="1616">
|
<GR Id="P-02E5-0_GR-14" RangeStart="2560" RangeEnd="2815" Name="Neue Mittelgruppe" Puid="1616">
|
||||||
<GA Id="P-02E5-0_GA-460" Address="2560" Name="Keller / Sat. Receiver / Status / Setzen" DatapointType="DPST-1-1" Puid="1617" />
|
<GA Id="P-02E5-0_GA-460" Address="2560" Name="Keller / Sat. Receiver / Status / Setzen" DatapointType="DPST-1-1" Puid="1617" />
|
||||||
|
|||||||
37
src/main/angular/src/app/api/Tunable/Tunable.ts
Normal file
37
src/main/angular/src/app/api/Tunable/Tunable.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import {Property} from "../Property/Property";
|
||||||
|
import {orNull, validateString} from "../common/validators";
|
||||||
|
|
||||||
|
export class Tunable {
|
||||||
|
constructor(
|
||||||
|
readonly uuid: string,
|
||||||
|
readonly name: string,
|
||||||
|
readonly slug: string,
|
||||||
|
readonly statePropertyId: string,
|
||||||
|
readonly stateProperty: Property | null,
|
||||||
|
readonly brightnessPropertyId: string,
|
||||||
|
readonly brightnessProperty: Property | null,
|
||||||
|
readonly coldnessPropertyId: string,
|
||||||
|
readonly coldnessProperty: Property | null,
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: any): Tunable {
|
||||||
|
return new Tunable(
|
||||||
|
validateString(json.uuid),
|
||||||
|
validateString(json.name),
|
||||||
|
validateString(json.slug),
|
||||||
|
validateString(json.statePropertyId),
|
||||||
|
orNull(json.stateProperty, Property.fromJson),
|
||||||
|
validateString(json.brightnessPropertyId),
|
||||||
|
orNull(json.brightnessProperty, Property.fromJson),
|
||||||
|
validateString(json.coldnessPropertyId),
|
||||||
|
orNull(json.coldnessProperty, Property.fromJson),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static trackBy(index: number, tunable: Tunable) {
|
||||||
|
return tunable.uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
5
src/main/angular/src/app/api/Tunable/TunableFilter.ts
Normal file
5
src/main/angular/src/app/api/Tunable/TunableFilter.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export class TunableFilter {
|
||||||
|
|
||||||
|
search: string = "";
|
||||||
|
|
||||||
|
}
|
||||||
40
src/main/angular/src/app/api/Tunable/tunable.service.ts
Normal file
40
src/main/angular/src/app/api/Tunable/tunable.service.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import {Injectable} from '@angular/core';
|
||||||
|
import {CrudService} from '../common/CrudService';
|
||||||
|
import {Tunable} from './Tunable';
|
||||||
|
import {ApiService} from '../common/api.service';
|
||||||
|
import {Next} from '../common/types';
|
||||||
|
|
||||||
|
import {TunableFilter} from './TunableFilter';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class TunableService extends CrudService<Tunable> {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
api: ApiService,
|
||||||
|
) {
|
||||||
|
super(api, ['Tunable'], Tunable.fromJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
getByUuid(uuid: string, next: Next<Tunable>): void {
|
||||||
|
this.getSingle(['getByUuid', uuid], next);
|
||||||
|
}
|
||||||
|
|
||||||
|
list(filter: TunableFilter | null, next: Next<Tunable[]>): void {
|
||||||
|
this.postList(['list'], filter, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(tunable: Tunable, state: boolean, next?: Next<void>): void {
|
||||||
|
this.getNone(['setState', tunable.uuid, state], next);
|
||||||
|
}
|
||||||
|
|
||||||
|
setBrightness(tunable: Tunable, brightness: number, next?: Next<void>): void {
|
||||||
|
this.getNone(['setBrightness', tunable.uuid, brightness], next);
|
||||||
|
}
|
||||||
|
|
||||||
|
setColdness(tunable: Tunable, coldness: number, next?: Next<void>): void {
|
||||||
|
this.getNone(['setColdness', tunable.uuid, coldness], next);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
<div class="flexBox">
|
<div class="flexBox">
|
||||||
<div class="flexBoxFixed menu">
|
<div class="flexBoxFixed menu">
|
||||||
<div class="item itemLeft" routerLink="DeviceList" routerLinkActive="active">Geräte</div>
|
<div class="item itemLeft" routerLink="DeviceList" routerLinkActive="active">Geräte</div>
|
||||||
|
<div class="item itemLeft" routerLink="TunableList" routerLinkActive="active">Licht</div>
|
||||||
<div class="item itemLeft" routerLink="ShutterList" routerLinkActive="active">Rollläden</div>
|
<div class="item itemLeft" routerLink="ShutterList" routerLinkActive="active">Rollläden</div>
|
||||||
<div class="item itemRight" routerLink="GroupList" routerLinkActive="active">KNX</div>
|
<div class="item itemRight" routerLink="GroupList" routerLinkActive="active">KNX</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -2,9 +2,11 @@ import {Routes} from '@angular/router';
|
|||||||
import {KnxGroupListPageComponent} from './pages/knx-group-list-page/knx-group-list-page.component';
|
import {KnxGroupListPageComponent} from './pages/knx-group-list-page/knx-group-list-page.component';
|
||||||
import {DeviceListPageComponent} from './pages/device-list-page/device-list-page.component';
|
import {DeviceListPageComponent} from './pages/device-list-page/device-list-page.component';
|
||||||
import {ShutterListPageComponent} from './pages/shutter-list-page/shutter-list-page.component';
|
import {ShutterListPageComponent} from './pages/shutter-list-page/shutter-list-page.component';
|
||||||
|
import {TunableListPageComponent} from './pages/tunable-list-page/tunable-list-page.component';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{path: 'DeviceList', component: DeviceListPageComponent},
|
{path: 'DeviceList', component: DeviceListPageComponent},
|
||||||
|
{path: 'TunableList', component: TunableListPageComponent},
|
||||||
{path: 'ShutterList', component: ShutterListPageComponent},
|
{path: 'ShutterList', component: ShutterListPageComponent},
|
||||||
{path: 'GroupList', component: KnxGroupListPageComponent},
|
{path: 'GroupList', component: KnxGroupListPageComponent},
|
||||||
{path: '**', redirectTo: 'GroupList'},
|
{path: '**', redirectTo: 'GroupList'},
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<div class="flexBox">
|
<div class="flexBox">
|
||||||
<div class="flexBoxFixed">
|
<div class="flexBoxFixed">
|
||||||
<input [(ngModel)]="filter.search" (ngModelChange)="fetchDelayed()" placeholder="Suchen...">
|
<input type="text" [(ngModel)]="filter.search" (ngModelChange)="fetchDelayed()" placeholder="Suchen...">
|
||||||
</div>
|
</div>
|
||||||
<div class="flexBoxRest">
|
<div class="flexBoxRest">
|
||||||
<app-device-list [deviceList]="deviceList"></app-device-list>
|
<app-device-list [deviceList]="deviceList"></app-device-list>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<div class="flexBox">
|
<div class="flexBox">
|
||||||
<div class="flexBoxFixed">
|
<div class="flexBoxFixed">
|
||||||
<input [(ngModel)]="filter.search" (ngModelChange)="fetchDelayed()" placeholder="Suchen...">
|
<input type="text" [(ngModel)]="filter.search" (ngModelChange)="fetchDelayed()" placeholder="Suchen...">
|
||||||
</div>
|
</div>
|
||||||
<div class="flexBoxRest">
|
<div class="flexBoxRest">
|
||||||
<app-knx-group-list [groupList]="groupList"></app-knx-group-list>
|
<app-knx-group-list [groupList]="groupList"></app-knx-group-list>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<div class="flexBox">
|
<div class="flexBox">
|
||||||
<div class="flexBoxFixed">
|
<div class="flexBoxFixed">
|
||||||
<input [(ngModel)]="filter.search" (ngModelChange)="fetchDelayed()" placeholder="Suchen...">
|
<input type="text" [(ngModel)]="filter.search" (ngModelChange)="fetchDelayed()" placeholder="Suchen...">
|
||||||
</div>
|
</div>
|
||||||
<div class="flexBoxRest">
|
<div class="flexBoxRest">
|
||||||
<app-shutter-list [shutterList]="shutterList"></app-shutter-list>
|
<app-shutter-list [shutterList]="shutterList"></app-shutter-list>
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
<div class="flexBox">
|
||||||
|
<div class="flexBoxFixed">
|
||||||
|
<input type="text" [(ngModel)]="filter.search" (ngModelChange)="fetchDelayed()" placeholder="Suchen...">
|
||||||
|
</div>
|
||||||
|
<div class="flexBoxRest">
|
||||||
|
<app-tunable-list [tunableList]="tunableList"></app-tunable-list>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
@import "../../../config";
|
||||||
|
|
||||||
|
input {
|
||||||
|
border-bottom: @border solid lightgray;
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
|
import {TunableListComponent} from '../../shared/tunable-list/tunable-list.component';
|
||||||
|
import {Tunable} from '../../api/Tunable/Tunable';
|
||||||
|
import {TunableService} from '../../api/Tunable/tunable.service';
|
||||||
|
import {FormsModule} from '@angular/forms';
|
||||||
|
import {TunableFilter} from '../../api/Tunable/TunableFilter';
|
||||||
|
import {Subscription} from 'rxjs';
|
||||||
|
import {ApiService} from '../../api/common/api.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-tunable-list-page',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
TunableListComponent,
|
||||||
|
FormsModule
|
||||||
|
],
|
||||||
|
templateUrl: './tunable-list-page.component.html',
|
||||||
|
styleUrl: './tunable-list-page.component.less'
|
||||||
|
})
|
||||||
|
export class TunableListPageComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
private readonly subs: Subscription[] = [];
|
||||||
|
|
||||||
|
protected tunableList: Tunable[] = [];
|
||||||
|
|
||||||
|
protected filter: TunableFilter = new TunableFilter();
|
||||||
|
|
||||||
|
private fetchTimeout: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected readonly tunableService: TunableService,
|
||||||
|
protected readonly apiService: ApiService,
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.fetch();
|
||||||
|
this.subs.push(this.tunableService.subscribe(tunable => this.updateTunable(tunable)));
|
||||||
|
this.apiService.connected(() => this.fetch());
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.subs.forEach(sub => sub.unsubscribe());
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchDelayed() {
|
||||||
|
if (this.fetchTimeout) {
|
||||||
|
clearTimeout(this.fetchTimeout);
|
||||||
|
this.fetchTimeout = undefined;
|
||||||
|
}
|
||||||
|
this.fetchTimeout = setTimeout(() => this.fetch(), 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fetch() {
|
||||||
|
this.tunableService.list(this.filter, list => this.tunableList = list)
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateTunable(tunable: Tunable) {
|
||||||
|
const index = this.tunableList.findIndex(d => d.uuid === tunable.uuid);
|
||||||
|
if (index >= 0) {
|
||||||
|
this.tunableList.splice(index, 1, tunable);
|
||||||
|
} else {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
<div class="tunableList tileContainer">
|
||||||
|
|
||||||
|
<div *ngFor="let tunable of tunableList; trackBy: Tunable.trackBy" class="tile">
|
||||||
|
|
||||||
|
<div [ngClass]="ngClass(tunable)" class="tunable tileInner">
|
||||||
|
|
||||||
|
<div class="name">
|
||||||
|
{{ tunable.name }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="timestamp details">
|
||||||
|
{{ tunable.stateProperty?.lastValueChange | relative:now }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sliders">
|
||||||
|
<div class="slider">
|
||||||
|
<input type="range" [ngModel]="tunable.brightnessProperty?.state?.value" (ngModelChange)="tunableService.setBrightness(tunable, $event)">
|
||||||
|
</div>
|
||||||
|
<div class="slider">
|
||||||
|
<input type="range" [ngModel]="tunable.coldnessProperty?.state?.value" (ngModelChange)="tunableService.setColdness(tunable, $event)">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="actions">
|
||||||
|
<div class="switch switchOn" (click)="tunableService.setState(tunable, true)"></div>
|
||||||
|
<div class="switch switchOff" (click)="tunableService.setState(tunable, false)"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
@import "../../../config";
|
||||||
|
|
||||||
|
.tunableList {
|
||||||
|
overflow-y: auto;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.tunable {
|
||||||
|
|
||||||
|
.name {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timestamp {
|
||||||
|
float: right;
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sliders {
|
||||||
|
float: left;
|
||||||
|
clear: left;
|
||||||
|
width: 60%;
|
||||||
|
overflow: visible;
|
||||||
|
padding-top: 0.4em;
|
||||||
|
|
||||||
|
.slider {
|
||||||
|
float: left;
|
||||||
|
clear: left;
|
||||||
|
margin-left: @space;
|
||||||
|
width: 100%;
|
||||||
|
overflow: visible;
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
height: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
float: right;
|
||||||
|
|
||||||
|
.switch {
|
||||||
|
float: left;
|
||||||
|
margin-left: @space;
|
||||||
|
width: 4em;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switchOn {
|
||||||
|
//noinspection CssUnknownTarget
|
||||||
|
background-image: url("/switchOn.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.switchOff {
|
||||||
|
//noinspection CssUnknownTarget
|
||||||
|
background-image: url("/switchOff.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
||||||
|
import {NgClass, NgForOf} from '@angular/common';
|
||||||
|
import {Tunable} from '../../api/Tunable/Tunable';
|
||||||
|
import {TunableService} from '../../api/Tunable/tunable.service';
|
||||||
|
import {RelativePipe} from '../../api/common/relative.pipe';
|
||||||
|
import {Subscription, timer} from 'rxjs';
|
||||||
|
import {FormsModule} from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-tunable-list',
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
NgForOf,
|
||||||
|
NgClass,
|
||||||
|
RelativePipe,
|
||||||
|
FormsModule
|
||||||
|
],
|
||||||
|
templateUrl: './tunable-list.component.html',
|
||||||
|
styleUrl: './tunable-list.component.less'
|
||||||
|
})
|
||||||
|
export class TunableListComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
tunableList: Tunable[] = [];
|
||||||
|
|
||||||
|
protected readonly Tunable = Tunable;
|
||||||
|
|
||||||
|
protected now: Date = new Date();
|
||||||
|
|
||||||
|
private readonly subs: Subscription[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected readonly tunableService: TunableService,
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.now = new Date();
|
||||||
|
this.subs.push(timer(1000, 1000).subscribe(() => this.now = new Date()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.subs.forEach(sub => sub.unsubscribe());
|
||||||
|
}
|
||||||
|
|
||||||
|
ngClass(tunable: Tunable) {
|
||||||
|
return {
|
||||||
|
"stateOn": tunable.stateProperty?.state?.value === true,
|
||||||
|
"stateOff": tunable.stateProperty?.state?.value === false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -17,7 +17,7 @@ div {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input[type=text] {
|
||||||
all: unset;
|
all: unset;
|
||||||
width: calc(100% - 2 * 0.2em - @border);
|
width: calc(100% - 2 * 0.2em - @border);
|
||||||
padding-left: 0.2em;
|
padding-left: 0.2em;
|
||||||
|
|||||||
69
src/main/java/de/ph87/home/common/map/MapHelper.java
Normal file
69
src/main/java/de/ph87/home/common/map/MapHelper.java
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package de.ph87.home.common.map;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class MapHelper {
|
||||||
|
|
||||||
|
public static <T> void apply(@Nullable final T t, @NonNull final Consumer<@NonNull T> apply) {
|
||||||
|
if (t == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
apply.accept(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, U> void apply(@Nullable final T t, @NonNull final U u, @NonNull final BiConsumer<@NonNull T, @NonNull U> apply) {
|
||||||
|
if (t == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
apply.accept(t, u);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static <T, R> R map(@Nullable final T t, @NonNull final Function<@NonNull T, R> map) {
|
||||||
|
return map(t, map, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static <T, R> R map(@Nullable final T t, @NonNull final Function<@NonNull T, @NonNull R> map, @Nullable final R fallback) {
|
||||||
|
if (t == null) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
return map.apply(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static <T, R> R mapNN(@Nullable final T t, @NonNull final Function<@NonNull T, @NonNull R> map, @NonNull final R fallback) {
|
||||||
|
if (t == null) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
return map.apply(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static <T, U, R> R biMap(@Nullable final T t, @NonNull final U u, @NonNull final BiFunction<@NonNull T, @NonNull U, R> map) {
|
||||||
|
return biMap(t, u, map, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static <T, U, R> R biMap(@Nullable final T t, @NonNull final U u, @NonNull final BiFunction<@NonNull T, @NonNull U, @NonNull R> map, @Nullable final R fallback) {
|
||||||
|
if (t == null) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
return map.apply(t, u);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static <T, U, R> R biMapNN(@Nullable final T t, @NonNull final U u, @NonNull final BiFunction<@NonNull T, @NonNull U, @NonNull R> map, @NonNull final R fallback) {
|
||||||
|
if (t == null) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
return map.apply(t, u);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -4,6 +4,9 @@ import de.ph87.home.device.DeviceService;
|
|||||||
import de.ph87.home.knx.property.KnxPropertyService;
|
import de.ph87.home.knx.property.KnxPropertyService;
|
||||||
import de.ph87.home.knx.property.KnxPropertyType;
|
import de.ph87.home.knx.property.KnxPropertyType;
|
||||||
import de.ph87.home.shutter.ShutterService;
|
import de.ph87.home.shutter.ShutterService;
|
||||||
|
import de.ph87.home.tunable.TunableService;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||||
@ -24,43 +27,73 @@ public class DemoService {
|
|||||||
|
|
||||||
private final ShutterService shutterService;
|
private final ShutterService shutterService;
|
||||||
|
|
||||||
|
private final TunableService tunableService;
|
||||||
|
|
||||||
@EventListener(ApplicationStartedEvent.class)
|
@EventListener(ApplicationStartedEvent.class)
|
||||||
public void startup() {
|
public void startup() {
|
||||||
knxPropertyService.create("eg_ambiente", KnxPropertyType.BOOLEAN, adr(849), adr(848));
|
device("eg_ambiente", "EG Ambiente", 849, 848);
|
||||||
deviceService.create("EG Ambiente", "eg_ambiente", "eg_ambiente");
|
device("fernseher", "Wohnzimmer Fernseher", 20, 4);
|
||||||
|
device("verstaerker", "Wohnzimmer Verstärker", 825, 824);
|
||||||
|
device("fensterdeko", "Wohnzimmer Fenster", 1823, 1822);
|
||||||
|
device("haengelampe", "Wohnzimmer Hängelampe", 1794, 1799);
|
||||||
|
device("receiver", "Receiver", 2561, 2560);
|
||||||
|
|
||||||
knxPropertyService.create("fernseher", KnxPropertyType.BOOLEAN, adr(20), adr(4));
|
tunable("wohnzimmer_spots", "Wohnzimmer", 28, 828, 2344, 2343, 1825, 1824);
|
||||||
deviceService.create("Wohnzimmer Fernseher", "fernseher", "fernseher");
|
tunable("kueche_spots", "Küche", 2311, 2304, 2342, 2341, 2321, 2317);
|
||||||
|
tunable("arbeitszimmer_spots", "Arbeitszimmer", 2058, 2057, 2067, 2069, 2049, 2054);
|
||||||
|
|
||||||
knxPropertyService.create("verstaerker", KnxPropertyType.BOOLEAN, adr(825), adr(824));
|
shutter("wohnzimmer_links", "Wohnzimmer Links", 1048);
|
||||||
deviceService.create("Wohnzimmer Verstärker", "verstaerker", "verstaerker");
|
shutter("wohnzimmer_rechts", "Wohnzimmer Rechts", 1811);
|
||||||
|
shutter("kueche_seite", "Küche Seite", 2316);
|
||||||
knxPropertyService.create("fensterdeko", KnxPropertyType.BOOLEAN, adr(1823), adr(1822));
|
shutter("kueche_theke", "Küche Theke", 2320);
|
||||||
deviceService.create("Wohnzimmer Fenster", "fensterdeko", "fensterdeko");
|
shutter("kueche_tuer", "Küche Tür", 2324);
|
||||||
|
|
||||||
knxPropertyService.create("haengelampe", KnxPropertyType.BOOLEAN, adr(1794), adr(1799));
|
|
||||||
deviceService.create("Wohnzimmer Hängelampe", "haengelampe", "haengelampe");
|
|
||||||
|
|
||||||
knxPropertyService.create("receiver", KnxPropertyType.BOOLEAN, adr(2561), adr(2560));
|
|
||||||
deviceService.create("Receiver", "receiver", "receiver");
|
|
||||||
|
|
||||||
knxPropertyService.create("wohnzimmer_links", KnxPropertyType.DOUBLE, adr(1048), adr(1048));
|
|
||||||
shutterService.create("Wohnzimmer Links", "wohnzimmer_links", "wohnzimmer_links");
|
|
||||||
|
|
||||||
knxPropertyService.create("wohnzimmer_rechts", KnxPropertyType.DOUBLE, adr(1811), adr(1811));
|
|
||||||
shutterService.create("Wohnzimmer Rechts", "wohnzimmer_rechts", "wohnzimmer_rechts");
|
|
||||||
|
|
||||||
knxPropertyService.create("kueche_seite", KnxPropertyType.DOUBLE, adr(2316), adr(2316));
|
|
||||||
shutterService.create("Küche Seite", "kueche_seite", "kueche_seite");
|
|
||||||
|
|
||||||
knxPropertyService.create("kueche_theke", KnxPropertyType.DOUBLE, adr(2320), adr(2320));
|
|
||||||
shutterService.create("Küche Theke", "kueche_theke", "kueche_theke");
|
|
||||||
|
|
||||||
knxPropertyService.create("kueche_tuer", KnxPropertyType.DOUBLE, adr(2324), adr(2324));
|
|
||||||
shutterService.create("Küche Tür", "kueche_tuer", "kueche_tuer");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GroupAddress adr(final int rawGroupAddress) {
|
private void device(
|
||||||
|
@NonNull final String slug,
|
||||||
|
@NonNull final String name,
|
||||||
|
@Nullable final Integer stateRead,
|
||||||
|
@Nullable final Integer stateWrite
|
||||||
|
) {
|
||||||
|
knxPropertyService.create(slug, KnxPropertyType.BOOLEAN, adr(stateRead), adr(stateWrite));
|
||||||
|
deviceService.create(name, slug, slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shutter(
|
||||||
|
@NonNull final String slug,
|
||||||
|
@NonNull final String name,
|
||||||
|
@Nullable final Integer positionReadWrite
|
||||||
|
) {
|
||||||
|
knxPropertyService.create(slug, KnxPropertyType.DOUBLE, adr(positionReadWrite), adr(positionReadWrite));
|
||||||
|
shutterService.create(name, slug, slug);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tunable(
|
||||||
|
@NonNull final String slug,
|
||||||
|
@NonNull final String name,
|
||||||
|
@Nullable final Integer stateRead,
|
||||||
|
@Nullable final Integer stateWrite,
|
||||||
|
@Nullable final Integer brightnessRead,
|
||||||
|
@Nullable final Integer brightnessWrite,
|
||||||
|
@Nullable final Integer coldnessRead,
|
||||||
|
@Nullable final Integer coldnessWrite
|
||||||
|
) {
|
||||||
|
final String stateProperty = slug + "_state";
|
||||||
|
knxPropertyService.create(stateProperty, KnxPropertyType.BOOLEAN, adr(stateRead), adr(stateWrite));
|
||||||
|
|
||||||
|
final String brightnessProperty = slug + "_brightness";
|
||||||
|
knxPropertyService.create(brightnessProperty, KnxPropertyType.DOUBLE, adr(brightnessRead), adr(brightnessWrite));
|
||||||
|
|
||||||
|
final String coldnessProperty = slug + "_coldness";
|
||||||
|
knxPropertyService.create(coldnessProperty, KnxPropertyType.DOUBLE, adr(coldnessRead), adr(coldnessWrite));
|
||||||
|
|
||||||
|
tunableService.create(name, slug, stateProperty, brightnessProperty, coldnessProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GroupAddress adr(final Integer rawGroupAddress) {
|
||||||
|
if (rawGroupAddress == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return GroupAddress.freeStyle(rawGroupAddress);
|
return GroupAddress.freeStyle(rawGroupAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
51
src/main/java/de/ph87/home/tunable/Tunable.java
Normal file
51
src/main/java/de/ph87/home/tunable/Tunable.java
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package de.ph87.home.tunable;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Tunable {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@NonNull
|
||||||
|
private String uuid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false, unique = true)
|
||||||
|
private String slug;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String statePropertyId;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String brightnessPropertyId;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String coldnessPropertyId;
|
||||||
|
|
||||||
|
public Tunable(@NonNull final String name, @NonNull final String slug, @NonNull final String statePropertyId, @NonNull final String brightnessPropertyId, @NonNull final String coldnessPropertyId) {
|
||||||
|
this.name = name;
|
||||||
|
this.slug = slug;
|
||||||
|
this.statePropertyId = statePropertyId;
|
||||||
|
this.brightnessPropertyId = brightnessPropertyId;
|
||||||
|
this.coldnessPropertyId = coldnessPropertyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
85
src/main/java/de/ph87/home/tunable/TunableController.java
Normal file
85
src/main/java/de/ph87/home/tunable/TunableController.java
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package de.ph87.home.tunable;
|
||||||
|
|
||||||
|
import de.ph87.home.property.PropertyNotFound;
|
||||||
|
import de.ph87.home.property.PropertyNotWritable;
|
||||||
|
import de.ph87.home.property.PropertyTypeMismatch;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import tuwien.auto.calimero.KNXFormatException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("Tunable")
|
||||||
|
public class TunableController {
|
||||||
|
|
||||||
|
private final TunableService tunableService;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@GetMapping("getByUuid/{id}")
|
||||||
|
@ExceptionHandler(KNXFormatException.class)
|
||||||
|
private TunableDto getByUuid(@PathVariable final String id, @NonNull final HttpServletRequest request) {
|
||||||
|
log.debug("getByUuid: path={}", request.getServletPath());
|
||||||
|
return tunableService.getByUuidDto(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@RequestMapping(value = "list", method = {RequestMethod.GET, RequestMethod.POST})
|
||||||
|
private List<TunableDto> list(@RequestBody(required = false) @Nullable final TunableFilter filter, @NonNull final HttpServletRequest request) throws PropertyTypeMismatch {
|
||||||
|
log.debug("list: path={} filter={}", request.getServletPath(), filter);
|
||||||
|
return tunableService.list(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@GetMapping("get/{uuidOrSlug}")
|
||||||
|
private TunableDto get(@PathVariable @NonNull final String uuidOrSlug, @NonNull final HttpServletRequest request) {
|
||||||
|
log.debug("get: path={}", request.getServletPath());
|
||||||
|
return tunableService.getByUuidOrSlugDto(uuidOrSlug);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@GetMapping("getState/{uuidOrSlug}")
|
||||||
|
private Boolean getState(@PathVariable @NonNull final String uuidOrSlug, @NonNull final HttpServletRequest request) throws PropertyTypeMismatch {
|
||||||
|
log.debug("getState: path={}", request.getServletPath());
|
||||||
|
return tunableService.getByUuidOrSlugDto(uuidOrSlug).getStateValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("setState/{uuidOrSlug}/{state}")
|
||||||
|
private TunableDto setState(@PathVariable @NonNull final String uuidOrSlug, @PathVariable final boolean state, @NonNull final HttpServletRequest request) throws PropertyNotFound, PropertyNotWritable, PropertyTypeMismatch {
|
||||||
|
log.debug("setState: path={}", request.getServletPath());
|
||||||
|
return tunableService.setState(uuidOrSlug, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@GetMapping("getBrightness/{uuidOrSlug}")
|
||||||
|
private Double getBrightness(@PathVariable @NonNull final String uuidOrSlug, @NonNull final HttpServletRequest request) throws PropertyTypeMismatch {
|
||||||
|
log.debug("getBrightness: path={}", request.getServletPath());
|
||||||
|
return tunableService.getByUuidOrSlugDto(uuidOrSlug).getBrightnessValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("setBrightness/{uuidOrSlug}/{brightness}")
|
||||||
|
private TunableDto setBrightness(@PathVariable @NonNull final String uuidOrSlug, @PathVariable final double brightness, @NonNull final HttpServletRequest request) throws PropertyNotFound, PropertyNotWritable, PropertyTypeMismatch {
|
||||||
|
log.debug("setBrightness: path={}", request.getServletPath());
|
||||||
|
return tunableService.setBrightness(uuidOrSlug, brightness);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@GetMapping("getColdness/{uuidOrSlug}")
|
||||||
|
private Double getColdness(@PathVariable @NonNull final String uuidOrSlug, @NonNull final HttpServletRequest request) throws PropertyTypeMismatch {
|
||||||
|
log.debug("getColdness: path={}", request.getServletPath());
|
||||||
|
return tunableService.getByUuidOrSlugDto(uuidOrSlug).getColdnessValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("setColdness/{uuidOrSlug}/{coldness}")
|
||||||
|
private TunableDto setColdness(@PathVariable @NonNull final String uuidOrSlug, @PathVariable final double coldness, @NonNull final HttpServletRequest request) throws PropertyNotFound, PropertyNotWritable, PropertyTypeMismatch {
|
||||||
|
log.debug("setColdness: path={}", request.getServletPath());
|
||||||
|
return tunableService.setColdness(uuidOrSlug, coldness);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
96
src/main/java/de/ph87/home/tunable/TunableDto.java
Normal file
96
src/main/java/de/ph87/home/tunable/TunableDto.java
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
package de.ph87.home.tunable;
|
||||||
|
|
||||||
|
import de.ph87.home.property.PropertyDto;
|
||||||
|
import de.ph87.home.property.PropertyTypeMismatch;
|
||||||
|
import de.ph87.home.web.IWebSocketMessage;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class TunableDto implements IWebSocketMessage {
|
||||||
|
|
||||||
|
@ToString.Exclude
|
||||||
|
private final List<Object> websocketTopic = List.of("Tunable");
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String uuid;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String slug;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String statePropertyId;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String brightnessPropertyId;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String coldnessPropertyId;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@ToString.Exclude
|
||||||
|
private final PropertyDto<Boolean> stateProperty;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@ToString.Exclude
|
||||||
|
private final PropertyDto<Double> brightnessProperty;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@ToString.Exclude
|
||||||
|
private final PropertyDto<Double> coldnessProperty;
|
||||||
|
|
||||||
|
public TunableDto(@NonNull final Tunable tunable, @Nullable final PropertyDto<Boolean> stateProperty, @Nullable final PropertyDto<Double> brightnessProperty, @Nullable final PropertyDto<Double> coldnessProperty) {
|
||||||
|
this.uuid = tunable.getUuid();
|
||||||
|
this.name = tunable.getName();
|
||||||
|
this.slug = tunable.getSlug();
|
||||||
|
this.statePropertyId = tunable.getStatePropertyId();
|
||||||
|
this.brightnessPropertyId = tunable.getBrightnessPropertyId();
|
||||||
|
this.coldnessPropertyId = tunable.getColdnessPropertyId();
|
||||||
|
this.stateProperty = stateProperty;
|
||||||
|
this.brightnessProperty = brightnessProperty;
|
||||||
|
this.coldnessProperty = coldnessProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@ToString.Include
|
||||||
|
public String state() {
|
||||||
|
try {
|
||||||
|
return "" + getStateValue();
|
||||||
|
} catch (PropertyTypeMismatch e) {
|
||||||
|
return "[PropertyTypeMismatch]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Boolean getStateValue() throws PropertyTypeMismatch {
|
||||||
|
if (stateProperty == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return stateProperty.getStateValueAs(Boolean.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Double getBrightnessValue() throws PropertyTypeMismatch {
|
||||||
|
if (brightnessProperty == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return brightnessProperty.getStateValueAs(Double.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Double getColdnessValue() throws PropertyTypeMismatch {
|
||||||
|
if (coldnessProperty == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return coldnessProperty.getStateValueAs(Double.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
src/main/java/de/ph87/home/tunable/TunableFilter.java
Normal file
41
src/main/java/de/ph87/home/tunable/TunableFilter.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package de.ph87.home.tunable;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import de.ph87.home.common.crud.AbstractSearchFilter;
|
||||||
|
import de.ph87.home.property.PropertyTypeMismatch;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class TunableFilter extends AbstractSearchFilter {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@JsonProperty
|
||||||
|
private Boolean stateNull;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@JsonProperty
|
||||||
|
private Boolean stateTrue;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@JsonProperty
|
||||||
|
private Boolean stateFalse;
|
||||||
|
|
||||||
|
public boolean filter(@NonNull final TunableDto dto) throws PropertyTypeMismatch {
|
||||||
|
if (stateNull != null && stateNull != (dto.getStateProperty() == null)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final Boolean value = dto.getStateValue();
|
||||||
|
if (stateTrue != null && (value == null || stateTrue != value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (stateFalse != null && (value == null || stateFalse == value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return search(dto.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
15
src/main/java/de/ph87/home/tunable/TunableRepository.java
Normal file
15
src/main/java/de/ph87/home/tunable/TunableRepository.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package de.ph87.home.tunable;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.springframework.data.repository.ListCrudRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface TunableRepository extends ListCrudRepository<Tunable, String> {
|
||||||
|
|
||||||
|
Optional<Tunable> findByUuidOrSlug(@NonNull String uuid, @NonNull String slug);
|
||||||
|
|
||||||
|
List<Tunable> findDistinctByStatePropertyIdOrBrightnessPropertyIdOrColdnessPropertyId(@NonNull String state, @NonNull String brightness, @NonNull String coldness);
|
||||||
|
|
||||||
|
}
|
||||||
115
src/main/java/de/ph87/home/tunable/TunableService.java
Normal file
115
src/main/java/de/ph87/home/tunable/TunableService.java
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
package de.ph87.home.tunable;
|
||||||
|
|
||||||
|
import de.ph87.home.common.crud.CrudAction;
|
||||||
|
import de.ph87.home.common.crud.EntityNotFound;
|
||||||
|
import de.ph87.home.property.*;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@Transactional
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class TunableService {
|
||||||
|
|
||||||
|
private final PropertyService propertyService;
|
||||||
|
|
||||||
|
private final TunableRepository tunableRepository;
|
||||||
|
|
||||||
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public TunableDto create(@NonNull final String name, @NonNull final String slug, @NonNull final String stateProperty, @NonNull final String brightnessProperty, @NonNull final String coldnessProperty) {
|
||||||
|
return publish(tunableRepository.save(new Tunable(name, slug, stateProperty, brightnessProperty, coldnessProperty)), CrudAction.UPDATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public TunableDto setState(@NonNull final String uuidOrSlug, final boolean state) throws PropertyNotFound, PropertyNotWritable, PropertyTypeMismatch {
|
||||||
|
log.debug("setState: uuidOrSlug={}, state={}", uuidOrSlug, state);
|
||||||
|
final Tunable tunable = getByUuidOrSlug(uuidOrSlug);
|
||||||
|
propertyService.write(tunable.getStatePropertyId(), state, Boolean.class);
|
||||||
|
return publish(tunable, CrudAction.UPDATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public TunableDto setBrightness(@NonNull final String uuidOrSlug, final double brightness) throws PropertyNotFound, PropertyNotWritable, PropertyTypeMismatch {
|
||||||
|
log.debug("setBrightness: uuidOrSlug={}, brightness={}", uuidOrSlug, brightness);
|
||||||
|
final Tunable tunable = getByUuidOrSlug(uuidOrSlug);
|
||||||
|
propertyService.write(tunable.getBrightnessPropertyId(), brightness, Double.class);
|
||||||
|
return publish(tunable, CrudAction.UPDATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public TunableDto setColdness(@NonNull final String uuidOrSlug, final double coldness) throws PropertyNotFound, PropertyNotWritable, PropertyTypeMismatch {
|
||||||
|
log.debug("setColdness: uuidOrSlug={}, coldness={}", uuidOrSlug, coldness);
|
||||||
|
final Tunable tunable = getByUuidOrSlug(uuidOrSlug);
|
||||||
|
propertyService.write(tunable.getColdnessPropertyId(), coldness, Double.class);
|
||||||
|
return publish(tunable, CrudAction.UPDATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public TunableDto getByUuidOrSlugDto(final @NonNull String uuidOrSlug) {
|
||||||
|
return toDto(getByUuidOrSlug(uuidOrSlug));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Tunable getByUuidOrSlug(@NonNull final String uuidOrSlug) {
|
||||||
|
return tunableRepository.findByUuidOrSlug(uuidOrSlug, uuidOrSlug).orElseThrow(() -> new EntityNotFound("uuidOrSlug", uuidOrSlug));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public TunableDto toDto(@NonNull final Tunable tunable) {
|
||||||
|
final PropertyDto<Boolean> state = propertyService.dtoByIdAndTypeOrNull(tunable.getStatePropertyId(), Boolean.class);
|
||||||
|
final PropertyDto<Double> brightness = propertyService.dtoByIdAndTypeOrNull(tunable.getBrightnessPropertyId(), Double.class);
|
||||||
|
final PropertyDto<Double> coldness = propertyService.dtoByIdAndTypeOrNull(tunable.getColdnessPropertyId(), Double.class);
|
||||||
|
return new TunableDto(tunable, state, brightness, coldness);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private Tunable getByUuid(@NonNull final String uuid) {
|
||||||
|
return tunableRepository.findById(uuid).orElseThrow(() -> new EntityNotFound("uuid", uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public List<TunableDto> list(@Nullable final TunableFilter filter) throws PropertyTypeMismatch {
|
||||||
|
final List<TunableDto> all = tunableRepository.findAll().stream().map(this::toDto).toList();
|
||||||
|
if (filter == null) {
|
||||||
|
return all;
|
||||||
|
}
|
||||||
|
final List<TunableDto> results = new ArrayList<>();
|
||||||
|
for (final TunableDto dto : all) {
|
||||||
|
if (filter.filter(dto)) {
|
||||||
|
results.add(dto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener(PropertyDto.class)
|
||||||
|
public void onPropertyChange(@NonNull final PropertyDto<?> dto) {
|
||||||
|
tunableRepository.findDistinctByStatePropertyIdOrBrightnessPropertyIdOrColdnessPropertyId(dto.getId(), dto.getId(), dto.getId()).forEach(tunable -> publish(tunable, CrudAction.CREATED));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private TunableDto publish(@NonNull final Tunable tunable, @NonNull final CrudAction action) {
|
||||||
|
final TunableDto dto = toDto(tunable);
|
||||||
|
log.info("Tunable {}: {}", action, dto);
|
||||||
|
applicationEventPublisher.publishEvent(dto);
|
||||||
|
return dto;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public TunableDto getByUuidDto(@NonNull final String uuid) {
|
||||||
|
return toDto(getByUuid(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user