diff --git a/src/main/angular/src/app/Area/Area.ts b/src/main/angular/src/app/Area/Area.ts index 10153a8..6b51769 100644 --- a/src/main/angular/src/app/Area/Area.ts +++ b/src/main/angular/src/app/Area/Area.ts @@ -1,8 +1,9 @@ -import {validateString} from "../api/validators"; +import {orNull, validateString} from "../api/validators"; export class Area { constructor( + readonly parent: Area | null, readonly uuid: string, readonly slug: string, readonly name: string, @@ -12,6 +13,7 @@ export class Area { static fromJson(json: any): Area { return new Area( + orNull(json.parent, Area.fromJson), validateString(json.uuid), validateString(json.slug), validateString(json.name), diff --git a/src/main/java/de/ph87/home/area/Area.java b/src/main/java/de/ph87/home/area/Area.java index e20e5cb..6aa4caa 100644 --- a/src/main/java/de/ph87/home/area/Area.java +++ b/src/main/java/de/ph87/home/area/Area.java @@ -1,9 +1,11 @@ package de.ph87.home.area; import de.ph87.home.search.ISearchable; +import jakarta.annotation.Nullable; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.NonNull; @@ -22,6 +24,10 @@ public class Area implements ISearchable { @NonNull private String uuid = UUID.randomUUID().toString(); + @Nullable + @ManyToOne + private Area parent; + @NonNull @Column(nullable = false) private String name; @@ -35,7 +41,8 @@ public class Area implements ISearchable { return List.of(slug, name); } - public Area(@NonNull final String name, @NonNull final String slug) { + public Area(@Nullable final Area parent, @NonNull final String name, @NonNull final String slug) { + this.parent = parent; this.name = name; this.slug = slug; } diff --git a/src/main/java/de/ph87/home/area/AreaDto.java b/src/main/java/de/ph87/home/area/AreaDto.java index 8d3c337..859e95c 100644 --- a/src/main/java/de/ph87/home/area/AreaDto.java +++ b/src/main/java/de/ph87/home/area/AreaDto.java @@ -1,12 +1,15 @@ package de.ph87.home.area; import de.ph87.home.web.IWebSocketMessage; +import jakarta.annotation.Nullable; import lombok.Getter; import lombok.NonNull; import lombok.ToString; import java.util.List; +import static de.ph87.home.common.map.MapHelper.map; + @Getter @ToString public class AreaDto implements IWebSocketMessage { @@ -14,6 +17,9 @@ public class AreaDto implements IWebSocketMessage { @ToString.Exclude private final List websocketTopic = List.of("Area"); + @Nullable + private final AreaDto parent; + @NonNull private final String uuid; @@ -24,6 +30,7 @@ public class AreaDto implements IWebSocketMessage { private final String slug; public AreaDto(@NonNull final Area area) { + this.parent = map(area.getParent(), AreaDto::new); this.uuid = area.getUuid(); this.name = area.getName(); this.slug = area.getSlug(); diff --git a/src/main/java/de/ph87/home/area/AreaService.java b/src/main/java/de/ph87/home/area/AreaService.java index bf8ac6e..21a359f 100644 --- a/src/main/java/de/ph87/home/area/AreaService.java +++ b/src/main/java/de/ph87/home/area/AreaService.java @@ -25,8 +25,9 @@ public class AreaService { private final ApplicationEventPublisher applicationEventPublisher; @NonNull - public AreaDto create(@NonNull final String name, @NonNull final String slug) { - return publish(areaRepository.save(new Area(name, slug)), CrudAction.UPDATED); + public AreaDto create(@Nullable final String parentUuid, @NonNull final String name, @NonNull final String slug) { + final Area parent = parentUuid == null ? null : areaRepository.findById(parentUuid).orElseThrow(); + return publish(areaRepository.save(new Area(parent, name, slug)), CrudAction.UPDATED); } @NonNull diff --git a/src/main/java/de/ph87/home/demo/DemoService.java b/src/main/java/de/ph87/home/demo/DemoService.java index 2cd7670..e8290fb 100644 --- a/src/main/java/de/ph87/home/demo/DemoService.java +++ b/src/main/java/de/ph87/home/demo/DemoService.java @@ -21,6 +21,8 @@ import tuwien.auto.calimero.GroupAddress; import java.util.Arrays; +import static de.ph87.home.common.map.MapHelper.map; + @Slf4j @Service @Transactional @@ -44,6 +46,7 @@ public class DemoService { public void startup() { final TagDto tagLight = tagService.create("light", "Licht"); final TagDto tagDevice = tagService.create("device", "Gerät"); + final TagDto tagConfirm = tagService.create("confirm", "Bestätigen"); final TagDto tagDecoration = tagService.create("decoration", "Dekoration"); final TagDto tagDecorationInside = tagService.create("decoration_inside", "Dekoration Innen"); final TagDto tagDecorationWindow = tagService.create("decoration_window", "Dekoration Fenster"); @@ -54,37 +57,96 @@ public class DemoService { final TagDto tagShutter = tagService.create("shutter", "Rollladen"); final TagDto tagFront = tagService.create("house_front", "Haus Vorne"); final TagDto tagSide = tagService.create("house_side", "Haus Seite"); - final TagDto tagHinten = tagService.create("house_backside", "Haus Hinten"); + final TagDto tagBack = tagService.create("house_backside", "Haus Hinten"); - final AreaDto eg = area("eg", "EG"); + /* EG ----------------------------------------------------------------------------------------- */ - final AreaDto wohnzimmer = area("wohnzimmer", "Wohnzimmer"); - device(wohnzimmer, "fernseher", "Fernseher", 20, 4, tagDevice, tagMedia, tagVideo); - device(wohnzimmer, "verstaerker", "Verstärker", 825, 824, tagDevice, tagMedia, tagAudio); - device(wohnzimmer, "haengelampe", "Hängelampe", 1794, 1799, tagLight); - device(wohnzimmer, "fensterdeko", "Fenster", 1823, 1822, tagDecoration, tagDecorationWindow); - tunable(wohnzimmer, "spots", "", 28, 828, 2344, 2343, 1825, 1824, tagLight); + final AreaDto eg = area(null, "eg", "EG"); + device(eg, "eg_ambiente", "Ambiente", 849, 848, tagDecoration, tagDecorationInside); + + final AreaDto wohnzimmer = area(eg, "wohnzimmer", "Wohnzimmer"); + tunable(wohnzimmer, "spots", "Spots", 28, 828, 2344, 2343, 1825, 1824, tagLight); shutter(wohnzimmer, "links", "Links", 1048, tagShutter, tagFront); shutter(wohnzimmer, "rechts", "Rechts", 1811, tagShutter, tagFront); + device(wohnzimmer, "fernseher", "Fernseher", 20, 4, tagDevice, tagMedia, tagVideo, tagConfirm); + device(wohnzimmer, "verstaerker", "Verstärker", 825, 824, tagDevice, tagMedia, tagAudio, tagConfirm); + device(wohnzimmer, "haengelampe", "Hängelampe", 1794, 1799, tagLight); + device(wohnzimmer, "fensterdekoration", "Fenster", 1823, 1822, tagDecoration, tagDecorationWindow); - final AreaDto kueche = area("kueche", "Küche"); - tunable(kueche, "kueche_spots", "", 2311, 2304, 2342, 2341, 2321, 2317, tagLight); - shutter(kueche, "kueche_seite", "Seite", 2316, tagShutter, tagSide); - shutter(kueche, "kueche_theke", "Theke", 2320, tagShutter, tagHinten); - shutter(kueche, "kueche_tuer", "Tür", 2324, tagShutter, tagHinten); + final AreaDto kueche = area(eg, "kueche", "Küche"); + tunable(kueche, "spots", "Spots", 2311, 2304, 2342, 2341, 2321, 2317, tagLight); + device(kueche, "haengelampe", "Hängelampe", 2313, 2312, tagLight); + shutter(kueche, "seite", "Seite", 2316, tagShutter, tagSide); + shutter(kueche, "theke", "Theke", 2320, tagShutter, tagBack); + shutter(kueche, "tuer", "Tür", 2324, tagShutter, tagBack); - device(eg, "eg_ambiente", "Ambiente", 849, 848, tagLight); + final AreaDto waschkueche = area(eg, "waschkueche", "Waschküche"); + tunable(waschkueche, "spots", "Spots", 1827, 1826, 1829, 1828, 1831, 1830, tagLight); + shutter(waschkueche, "seite", "Seite", 1820, tagShutter, tagBack); - final AreaDto arbeitszimmer = area("arbeitszimmer", "Arbeitszimmer"); - tunable(arbeitszimmer, "spots", "", 2058, 2057, 2067, 2069, 2049, 2054, tagLight); + final AreaDto flurEg = area(eg, "flur", "Flur EG"); + tunable(flurEg, "spots", "Spots", 1032, 1294, 2340, 2339, 2327, 2325, tagLight); + + /* OG ----------------------------------------------------------------------------------------- */ + + final AreaDto og = area(null, "og", "OG"); + + final AreaDto flurOg = area(og, "flur", "Flur OG"); + tunable(flurOg, "spots", "Spots", 814, 813, 2086, 2070, 2074, 2073, tagLight); + shutter(flurOg, "vorne", "Vorne", 1293, tagShutter, tagFront); + shutter(flurOg, "hinten", "Hinten", 2080, 2079, tagShutter, tagBack); + device(flurOg, "ambiente", "Ambiente", 1538, 1539, tagDecoration, tagDecorationInside); + device(flurOg, "fenster", "Fenster", 2331, 2332, tagDecoration, tagDecorationWindow); + + final AreaDto badOg = area(og, "bad", "Bad"); + shutter(badOg, "", "", 1308, 1307, tagShutter, tagBack); + tunable(badOg, "spots", "Spots", 1299, 841, 1320, 1319, 1318, 1317, tagLight); + tunable(badOg, "waschbecken", "Waschbecken", 790, 789, 1320, 1319, 1318, 1317, tagLight); + tunable(badOg, "badewanne", "Badewanne", 782, 781, 1320, 1319, 1318, 1317, tagLight); + tunable(badOg, "dusche", "Dusche", 774, 773, 1320, 1319, 1318, 1317, tagLight); + tunable(badOg, "toilette", "Toilette", 798, 797, 1320, 1319, 1318, 1317, tagLight); + + final AreaDto arbeitszimmer = area(og, "arbeitszimmer", "Arbeitszimmer"); + shutter(arbeitszimmer, "", "", 2064, tagShutter, tagBack); + tunable(arbeitszimmer, "spots", "Spots", 2058, 2057, 2067, 2069, 2049, 2054, tagLight); + device(arbeitszimmer, "pc", "Patrick PC", 2052, 2051, tagDevice, tagMedia, tagAudio, tagVideo, tagConfirm); + device(arbeitszimmer, "schreibtisch", "Patrick Schreibtisch", 2050, 2048, tagDevice, tagMedia, tagAudio, tagVideo, tagConfirm); + device(arbeitszimmer, "drucker", "Drucker", 2066, 2065, tagDevice, tagConfirm); + + final AreaDto schlafzimmer = area(og, "schlafzimmer", "Schlafzimmer"); + shutter(schlafzimmer, "links", "Links", 1303, tagShutter, tagFront); + shutter(schlafzimmer, "rechts", "Rechts", 1304, tagShutter, tagFront); + tunable(schlafzimmer, "spots", "Spots", 1309, 829, 1322, 1321, 1316, 1315, tagLight); + device(schlafzimmer, "loewe", "Löwe", 844, 843, tagDecoration, tagDecorationInside); + device(schlafzimmer, "sternenhimmel", "Sternenhimmel", 846, 845, tagDecoration, tagDecorationInside); + device(schlafzimmer, "fenster", "Fenster", 2333, 2334, tagDecoration, tagDecorationWindow); + + final AreaDto emil = area(og, "emil", "Emil"); + shutter(emil, "", "", 1807, tagShutter, tagFront); + tunable(emil, "spots", "Spots", 1796, 1795, 2085, 2084, 2083, 2082, tagLight); + device(emil, "fenster_links", "Fenster Links", 1804, 1803, tagDecoration, tagDecorationWindow); + device(emil, "fenster_rechts", "Fenster Rechts", 1802, 1801, tagDevice); + device(emil, "wand_scheune", "Wand Scheune", 2072, 2071, tagDevice); + + final AreaDto keller = area(null, "keller", "Keller"); + device(keller, "receiver", "Receiver", 2561, 2560, tagDevice, tagConfirm); + + /* AUSSEN ------------------------------------------------------------------------------------- */ + + final AreaDto aussen = area(null, "aussen", "Außen"); + + final AreaDto terrasse = area(aussen, "terrasse", "Terrasse"); + device(terrasse, "dekoration", "Dekoration", 2337, 2338, tagDecoration, tagDecorationOutside); + + final AreaDto vorgarten = area(aussen, "vorgarten", "Vorgarten"); + device(vorgarten, "dekoration", "Dekoration", 1036, 1035, tagDecoration, tagDecorationOutside); - final AreaDto keller = area("keller", "Keller"); - device(keller, "receiver", "Receiver", 2561, 2560, tagDevice); } @NonNull - private AreaDto area(@NonNull final String slug, @NonNull final String name) { - return areaService.create(name, slug); + private AreaDto area(@Nullable final AreaDto parent, @NonNull final String subSlug, @NonNull final String name) { + final String slug = parent == null ? subSlug : parent.getSlug() + "_" + subSlug; + return areaService.create(map(parent, AreaDto::getUuid), name, slug); } private void device( @@ -107,10 +169,21 @@ public class DemoService { @NonNull final String name, @Nullable final Integer positionReadWrite, @NonNull final TagDto... tagList + ) { + shutter(area, subSlug, name, positionReadWrite, positionReadWrite, tagList); + } + + private void shutter( + @NonNull final AreaDto area, + @NonNull final String subSlug, + @NonNull final String name, + @Nullable final Integer positionRead, + @Nullable final Integer positionWrite, + @NonNull final TagDto... tagList ) { final String slug = area.getSlug() + "_" + subSlug; final String statePropertyId = slug + "_state"; - knxPropertyService.create(statePropertyId, KnxPropertyType.DOUBLE, adr(positionReadWrite), adr(positionReadWrite)); + knxPropertyService.create(statePropertyId, KnxPropertyType.DOUBLE, adr(positionRead), adr(positionWrite)); shutterService.create(area.getUuid(), name, slug, statePropertyId, Arrays.stream(tagList).map(TagDto::getUuid).toList()); }