UI: Area, Room WIP

This commit is contained in:
Patrick Haßel 2022-03-01 10:24:52 +01:00
parent b03ba679e7
commit 6e82cc3855
31 changed files with 713 additions and 122 deletions

View File

@ -0,0 +1,87 @@
import {Area} from './area/Area';
import {Room} from './room/Room';
import {Device, DeviceStateScene, DeviceSwitch} from './device/Device';
const ____ = null;
let areaId = 0;
const OG2 = ++areaId;
const OG1 = ++areaId;
const EG = ++areaId;
const KELLER = ++areaId;
const GARAGE = ++areaId;
const GARTEN = ++areaId;
export const STUB_AREAS: Area[] = [
new Area(OG2, OG2, 'Dachgeschoss'),
new Area(OG1, OG1, 'Obergeschoss'),
new Area(EG, EG, 'Erdgeschoss'),
new Area(KELLER, KELLER, 'Keller'),
new Area(GARAGE, GARAGE, 'Garage'),
new Area(GARTEN, GARTEN, 'Garten'),
];
let roomId = 0;
const PATRICK = ++roomId;
const KATRIN = ++roomId;
const FLUR = ++roomId;
const BAD = ++roomId;
const ELTERN = ++roomId;
const EMIL = ++roomId;
const KIND2 = ++roomId;
const FLUR_OG1 = ++roomId;
const KUECHE = ++roomId;
const WOHNZIMMER = ++roomId;
const WASCHKUECHE = ++roomId;
const FLUR_EG = ++roomId;
const BIERKELLER = ++roomId;
const HEIZUNGSRAUM = ++roomId;
const GARAGE_KATRIN = ++roomId;
const GARAGE_PATRICK = ++roomId;
const WERKSTATT = ++roomId;
const TERRASSE = ++roomId;
const VORGARTEN = ++roomId;
export const STUB_ROOMS: Room[] = [
new Room(PATRICK, PATRICK, 'Patrick', OG2),
new Room(KATRIN, KATRIN, 'Katrin', OG2),
new Room(FLUR, FLUR, 'Flur', OG2),
new Room(BAD, BAD, 'Bad', OG1),
new Room(ELTERN, ELTERN, 'Eltern', OG1),
new Room(EMIL, EMIL, 'Emil', OG1),
new Room(KIND2, KIND2, 'Kind 2', OG1),
new Room(FLUR_OG1, FLUR_OG1, 'Flur', OG1),
new Room(KUECHE, KUECHE, 'Küche', EG),
new Room(WOHNZIMMER, WOHNZIMMER, 'Wohnzimmer', EG),
new Room(WASCHKUECHE, WASCHKUECHE, 'Waschküche', EG),
new Room(FLUR_EG, FLUR_EG, 'Flur', EG),
new Room(BIERKELLER, BIERKELLER, 'Bierkeller', KELLER),
new Room(HEIZUNGSRAUM, HEIZUNGSRAUM, 'Heizungsraum', KELLER),
new Room(GARAGE_KATRIN, GARAGE_KATRIN, 'Katrin', GARAGE),
new Room(GARAGE_PATRICK, GARAGE_PATRICK, 'Patrick', GARAGE),
new Room(WERKSTATT, WERKSTATT, 'Werkstatt', GARAGE),
new Room(TERRASSE, TERRASSE, 'Terrasse', GARTEN),
new Room(VORGARTEN, VORGARTEN, 'Vorgarten', GARTEN),
];
let deviceId = 0;
export const STUB_DEVICES: Device[] = [
new DeviceStateScene(++deviceId, deviceId, ____, ____, 'Alles Aus', 'DeviceStateScene', null, null, [1]),
new DeviceStateScene(++deviceId, deviceId, ____, ____, 'Rollläden Runter', 'DeviceStateScene', null, null, [40]),
new DeviceStateScene(++deviceId, deviceId, OG2, ____, 'Alles Aus', 'DeviceStateScene', null, null, [1]),
new DeviceStateScene(++deviceId, deviceId, OG2, ____, 'Rollläden Runter', 'DeviceStateScene', null, null, [40]),
new DeviceStateScene(++deviceId, deviceId, OG2, PATRICK, 'Alles Aus', 'DeviceStateScene', null, null, [1]),
new DeviceStateScene(++deviceId, deviceId, OG2, PATRICK, 'Rollläden Runter', 'DeviceStateScene', null, null, [40]),
new DeviceStateScene(++deviceId, deviceId, OG2, KATRIN, 'Alles Aus', 'DeviceStateScene', null, null, [1]),
new DeviceStateScene(++deviceId, deviceId, OG2, KATRIN, 'Rollläden Runter', 'DeviceStateScene', null, null, [40]),
new DeviceStateScene(++deviceId, deviceId, OG2, FLUR, 'Alles Aus', 'DeviceStateScene', null, null, [1]),
new DeviceStateScene(++deviceId, deviceId, OG2, FLUR, 'Rollläden Runter', 'DeviceStateScene', null, null, [40]),
new DeviceStateScene(++deviceId, deviceId, OG1, ____, 'Alles Aus', 'DeviceStateScene', null, null, [1]),
new DeviceSwitch(++deviceId, deviceId, OG1, BAD, 'Licht', 'DeviceSwitch', null),
new DeviceStateScene(++deviceId, deviceId, OG1, BAD, 'Alles Aus', 'DeviceStateScene', null, null, [1]),
];

View File

@ -0,0 +1,29 @@
import {validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators";
export class Area {
constructor(
readonly id: number,
readonly position: number,
readonly title: string,
) {
// nothing
}
static fromJson(json: any) {
return new Area(
validateNumberNotNull(json['id']),
validateNumberNotNull(json['position']),
validateStringNotEmptyNotNull(json['title']),
);
}
static comparePosition(a: Area, b: Area) {
return a.position - b.position;
}
static filterById(id: number): (_: Area) => boolean {
return a => a.id === id;
}
}

View File

@ -0,0 +1,16 @@
import {TestBed} from '@angular/core/testing';
import {AreaService} from './area.service';
describe('AreaService', () => {
let service: AreaService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(AreaService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,39 @@
import {Injectable} from '@angular/core';
import {ApiService, NO_COMPARE, NO_OP} from "../api.service";
import {ISearchService} from "../ISearchService";
import {SearchResult} from "../SearchResult";
import {Update} from "../Update";
import {Area} from "./Area";
@Injectable({
providedIn: 'root'
})
export class AreaService implements ISearchService {
constructor(
readonly api: ApiService,
) {
// nothing
}
findAll(next: (list: Area[]) => void, compare: (a: Area, b: Area) => number = NO_COMPARE, error: (error: any) => void = NO_OP): void {
this.api.getList("area/findAll", Area.fromJson, compare, next, error);
}
subscribe(next: (area: Update<Area>) => void): void {
this.api.subscribe("AreaDto", Area.fromJson, next);
}
get(id: number, next: (results: SearchResult) => void, error: (error: any) => void): void {
this.api.getItem("area/getById/" + id, SearchResult.fromJson, next, error);
}
search(term: string, next: (results: SearchResult[]) => void = NO_OP, error: (error: any) => void = NO_OP): void {
this.api.postReturnList("area/searchLike", term, SearchResult.fromJson, next, error);
}
set(area: Area, key: string, value: any, next: (item: Area) => void = NO_OP, error: (error: any) => void = NO_OP): void {
this.api.postReturnItem("area/set/" + area.id + "/" + key, value, Area.fromJson, next, error);
}
}

View File

@ -1,12 +1,15 @@
import {validateListOrEmpty, validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators"; import {validateListOrEmpty, validateNumberAllowNull, validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators";
import {Property} from "../property/Property"; import {Property} from "../property/Property";
export abstract class Device { export abstract class Device {
constructor( protected constructor(
readonly id: number, readonly id: number,
readonly position: number,
readonly title: string, readonly title: string,
readonly type: string, readonly type: string,
readonly areaId: number | null,
readonly roomId: number | null,
) { ) {
// nothing // nothing
} }
@ -17,24 +20,34 @@ export abstract class Device {
case "DeviceSwitch": case "DeviceSwitch":
return new DeviceSwitch( return new DeviceSwitch(
validateNumberNotNull(json['id']), validateNumberNotNull(json['id']),
validateNumberAllowNull(json['position']) || 0,
validateNumberAllowNull(json['areaId']),
validateNumberAllowNull(json['roomId']),
validateStringNotEmptyNotNull(json['title']), validateStringNotEmptyNotNull(json['title']),
type, type,
Property.fromJsonAllowNull(json['stateProperty']), Property.fromJsonAllowNull(json['stateProperty'])
); );
case "DeviceStateScene": case "DeviceStateScene":
return new DeviceStateScene( return new DeviceStateScene(
validateNumberNotNull(json['id']), validateNumberNotNull(json['id']),
validateNumberAllowNull(json['position']) || 0,
validateNumberAllowNull(json['areaId']),
validateNumberAllowNull(json['roomId']),
validateStringNotEmptyNotNull(json['title']), validateStringNotEmptyNotNull(json['title']),
type, type,
Property.fromJsonAllowNull(json['stateProperty']), Property.fromJsonAllowNull(json['stateProperty']),
Property.fromJsonAllowNull(json['sceneProperty']), Property.fromJsonAllowNull(json['sceneProperty']),
validateListOrEmpty(json['sceneNumbers'], validateNumberNotNull), validateListOrEmpty(json['sceneNumbers'],
validateNumberNotNull)
); );
case "DeviceShutter": case "DeviceShutter":
return new DeviceShutter( return new DeviceShutter(
validateNumberNotNull(json['id']), validateNumberNotNull(json['id']),
validateNumberAllowNull(json['position']) || 0,
validateStringNotEmptyNotNull(json['title']), validateStringNotEmptyNotNull(json['title']),
type, type,
validateNumberAllowNull(json['areaId']),
validateNumberAllowNull(json['roomId']),
Property.fromJsonAllowNull(json['positionProperty']), Property.fromJsonAllowNull(json['positionProperty']),
); );
} }
@ -45,27 +58,30 @@ export abstract class Device {
return item.title; return item.title;
} }
public static compareTypeThenTitle(a: Device, b: Device): number { public static comparePosition(a: Device, b: Device): number {
const type: number = -a.type.localeCompare(b.type); return a.position - b.position;
if (type !== 0) {
return type;
}
return a.title.localeCompare(b.title);
} }
abstract updateProperty(property: Property): void; abstract updateProperty(property: Property): void;
static filterByAreaIdAndRoomId(areaId: number | null, roomId: number | null): (_: Device) => boolean {
return d => d.areaId === areaId && d.roomId === roomId;
}
} }
export class DeviceSwitch extends Device { export class DeviceSwitch extends Device {
constructor( constructor(
id: number, id: number,
position: number,
areaId: number | null,
roomId: number | null,
title: string, title: string,
type: string, type: string,
public stateProperty: Property | null, public stateProperty: Property | null,
) { ) {
super(id, title, type); super(id, position, title, type, areaId, roomId);
} }
updateProperty(property: Property): void { updateProperty(property: Property): void {
@ -80,13 +96,16 @@ export class DeviceStateScene extends DeviceSwitch {
constructor( constructor(
id: number, id: number,
position: number,
areaId: number | null,
roomId: number | null,
title: string, title: string,
type: string, type: string,
stateProperty: Property | null, stateProperty: Property | null,
public sceneProperty: Property | null, public sceneProperty: Property | null,
public sceneNumbers: number[], public sceneNumbers: number[],
) { ) {
super(id, title, type, stateProperty); super(id, position, areaId, roomId, title, type, stateProperty);
} }
updateProperty(property: Property): void { updateProperty(property: Property): void {
@ -102,11 +121,14 @@ export class DeviceShutter extends Device {
constructor( constructor(
id: number, id: number,
position: number,
title: string, title: string,
type: string, type: string,
areaId: number | null,
roomId: number | null,
public positionProperty: Property | null, public positionProperty: Property | null,
) { ) {
super(id, title, type); super(id, position, title, type, areaId, roomId);
} }
updateProperty(property: Property): void { updateProperty(property: Property): void {

View File

@ -0,0 +1,35 @@
import {validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators";
export class Room {
constructor(
readonly id: number,
readonly position: number,
readonly title: string,
readonly areaId: number,
) {
// nothing
}
static fromJson(json: any) {
return new Room(
validateNumberNotNull(json['id']),
validateNumberNotNull(json['position']),
validateStringNotEmptyNotNull(json['title']),
validateNumberNotNull(json['areaId']),
);
}
static comparePosition(a: Room, b: Room) {
return a.position - b.position;
}
static filterByAreaId(areaId: number): (_: Room) => boolean {
return r => r.areaId === areaId;
}
static filterById(id: number): (_: Room) => boolean {
return r => r.id === id;
}
}

View File

@ -0,0 +1,16 @@
import {TestBed} from '@angular/core/testing';
import {RoomService} from './room.service';
describe('RoomService', () => {
let service: RoomService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(RoomService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,39 @@
import {Injectable} from '@angular/core';
import {ApiService, NO_COMPARE, NO_OP} from "../api.service";
import {ISearchService} from "../ISearchService";
import {SearchResult} from "../SearchResult";
import {Update} from "../Update";
import {Room} from "./Room";
@Injectable({
providedIn: 'root'
})
export class RoomService implements ISearchService {
constructor(
readonly api: ApiService,
) {
// nothing
}
findAll(next: (list: Room[]) => void, compare: (a: Room, b: Room) => number = NO_COMPARE, error: (error: any) => void = NO_OP): void {
this.api.getList("room/findAll", Room.fromJson, compare, next, error);
}
subscribe(next: (room: Update<Room>) => void): void {
this.api.subscribe("RoomDto", Room.fromJson, next);
}
get(id: number, next: (results: SearchResult) => void, error: (error: any) => void): void {
this.api.getItem("room/getById/" + id, SearchResult.fromJson, next, error);
}
search(term: string, next: (results: SearchResult[]) => void = NO_OP, error: (error: any) => void = NO_OP): void {
this.api.postReturnList("room/searchLike", term, SearchResult.fromJson, next, error);
}
set(room: Room, key: string, value: any, next: (item: Room) => void = NO_OP, error: (error: any) => void = NO_OP): void {
this.api.postReturnItem("room/set/" + room.id + "/" + key, value, Room.fromJson, next, error);
}
}

View File

@ -75,11 +75,11 @@ export function validateListOrEmpty<T>(json: any, fromJson: (json: any) => T, co
return json.map(fromJson).sort(compare); return json.map(fromJson).sort(compare);
} }
export function validateMap<T>(json: any, valueFromJson: (json: any) => T): Map<String, T> { export function validateMap<T>(json: any, valueFromJson: (json: any) => T): Map<string, T> {
if (typeof json !== 'object') { if (typeof json !== 'object') {
throw new Error("Not a Map: " + json); throw new Error("Not a Map: " + json);
} }
const map = new Map<String, T>(); const map = new Map<string, T>();
for (const key in json) { for (const key in json) {
if (Object.prototype.hasOwnProperty.call(json, key)) { if (Object.prototype.hasOwnProperty.call(json, key)) {
map.set(key, valueFromJson(json[key])); map.set(key, valueFromJson(json[key]));

View File

@ -2,20 +2,28 @@ import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router'; import {RouterModule, Routes} from '@angular/router';
import {ScheduleListComponent} from "./pages/schedule-list/schedule-list.component"; import {ScheduleListComponent} from "./pages/schedule-list/schedule-list.component";
import {ScheduleComponent} from "./pages/schedule/schedule.component"; import {ScheduleComponent} from "./pages/schedule/schedule.component";
import {DeviceListComponent} from "./pages/device-list/device-list.component"; import {DeviceAllListComponent} from "./pages/device-all-list/device-all-list.component";
import {DeviceComponent} from "./pages/device/device.component"; import {DeviceComponent} from "./pages/device/device.component";
import {PropertyListComponent} from "./pages/property-list/property-list.component"; import {PropertyListComponent} from "./pages/property-list/property-list.component";
import {ChannelListComponent} from "./pages/channel-list/channel-list.component"; import {ChannelListComponent} from "./pages/channel-list/channel-list.component";
import {AreaListComponent} from "./pages/mobile/device-tree/area-list/area-list.component";
import {RoomListComponent} from "./pages/mobile/device-tree/room-list/room-list.component";
import {DeviceListComponent} from "./pages/mobile/device-tree/device-list/device-list.component";
const routes: Routes = [ const routes: Routes = [
{path: 'Device', component: DeviceComponent}, {path: 'Device', component: DeviceComponent},
{path: 'DeviceList', component: DeviceListComponent}, {path: 'DeviceAllList', component: DeviceAllListComponent},
// {path: 'Channel', component: ChannelComponent}, // {path: 'Channel', component: ChannelComponent},
{path: 'ChannelList', component: ChannelListComponent}, {path: 'ChannelList', component: ChannelListComponent},
// {path: 'Property', component: PropertyComponent}, // {path: 'Property', component: PropertyComponent},
{path: 'PropertyList', component: PropertyListComponent}, {path: 'PropertyList', component: PropertyListComponent},
{path: 'Schedule', component: ScheduleComponent}, {path: 'Schedule', component: ScheduleComponent},
{path: 'ScheduleList', component: ScheduleListComponent}, {path: 'ScheduleList', component: ScheduleListComponent},
{path: 'AreaList', component: AreaListComponent},
{path: 'RoomList', component: RoomListComponent},
{path: 'DeviceList', component: DeviceListComponent},
{path: '**', redirectTo: '/ScheduleList'}, {path: '**', redirectTo: '/ScheduleList'},
]; ];

View File

@ -3,7 +3,7 @@
<div class="item" routerLink="/ScheduleList" routerLinkActive="itemActive"> <div class="item" routerLink="/ScheduleList" routerLinkActive="itemActive">
Zeitpläne Zeitpläne
</div> </div>
<div class="item" routerLink="/DeviceList" routerLinkActive="itemActive"> <div class="item" routerLink="/DeviceAllList" routerLinkActive="itemActive">
Geräte Geräte
</div> </div>

View File

@ -26,7 +26,3 @@
} }
} }
.content {
margin: 10px;
}

View File

@ -11,10 +11,13 @@ import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
import {NumberComponent} from './shared/number/number.component'; import {NumberComponent} from './shared/number/number.component';
import {ScheduleComponent} from "./pages/schedule/schedule.component"; import {ScheduleComponent} from "./pages/schedule/schedule.component";
import {SearchComponent} from './shared/search/search.component'; import {SearchComponent} from './shared/search/search.component';
import {DeviceListComponent} from './pages/device-list/device-list.component'; import {DeviceAllListComponent} from './pages/device-all-list/device-all-list.component';
import {DeviceComponent} from './pages/device/device.component'; import {DeviceComponent} from './pages/device/device.component';
import {PropertyListComponent} from './pages/property-list/property-list.component'; import {PropertyListComponent} from './pages/property-list/property-list.component';
import {ChannelListComponent} from './pages/channel-list/channel-list.component'; import {ChannelListComponent} from './pages/channel-list/channel-list.component';
import {AreaListComponent} from './pages/mobile/device-tree/area-list/area-list.component';
import {RoomListComponent} from './pages/mobile/device-tree/room-list/room-list.component';
import {DeviceListComponent} from './pages/mobile/device-tree/device-list/device-list.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -24,10 +27,13 @@ import {ChannelListComponent} from './pages/channel-list/channel-list.component'
ScheduleListComponent, ScheduleListComponent,
NumberComponent, NumberComponent,
SearchComponent, SearchComponent,
DeviceListComponent, DeviceAllListComponent,
DeviceComponent, DeviceComponent,
PropertyListComponent, PropertyListComponent,
ChannelListComponent, ChannelListComponent,
AreaListComponent,
RoomListComponent,
DeviceListComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,

View File

@ -6,7 +6,7 @@
<button (click)="create()">+ Hinzufügen</button> <button (click)="create()">+ Hinzufügen</button>
</div> </div>
<ng-container *ngFor="let device of devices.sort(Device.compareTypeThenTitle); trackBy: Device.trackBy"> <ng-container *ngFor="let device of devices.sort(Device.comparePosition); trackBy: Device.trackBy">
<ng-container [ngSwitch]="device.type"> <ng-container [ngSwitch]="device.type">
<div class="device" *ngSwitchCase="'DeviceSwitch'" [ngClass]="getSwitchClassList(device)"> <div class="device" *ngSwitchCase="'DeviceSwitch'" [ngClass]="getSwitchClassList(device)">

View File

@ -0,0 +1,25 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {DeviceAllListComponent} from './device-all-list.component';
describe('DeviceAllListComponent', () => {
let component: DeviceAllListComponent;
let fixture: ComponentFixture<DeviceAllListComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [DeviceAllListComponent]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(DeviceAllListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -7,11 +7,11 @@ import {Scene} from "../../api/scene/Scene";
import {SceneService} from "../../api/scene/scene.service"; import {SceneService} from "../../api/scene/scene.service";
@Component({ @Component({
selector: 'app-device-list', selector: 'app-device-all-list',
templateUrl: './device-list.component.html', templateUrl: './device-all-list.component.html',
styleUrls: ['./device-list.component.less'] styleUrls: ['./device-all-list.component.less']
}) })
export class DeviceListComponent implements OnInit { export class DeviceAllListComponent implements OnInit {
readonly Device = Device; readonly Device = Device;

View File

@ -57,7 +57,7 @@ export class DeviceComponent implements OnInit {
delete(): void { delete(): void {
if (confirm(this.getDeviceTypeTitle() + " \"" + this.device.title + "\" wirklich löschen?")) { if (confirm(this.getDeviceTypeTitle() + " \"" + this.device.title + "\" wirklich löschen?")) {
this.deviceService.delete(this.device, () => this.router.navigate(["/DeviceList"])); this.deviceService.delete(this.device, () => this.router.navigate(["/DeviceAllList"]));
} }
} }

View File

@ -0,0 +1,17 @@
<div class="list">
<div class="entry">
Haus
</div>
<div class="entry area" *ngFor="let area of areas" [routerLink]="['/RoomList', {id: area.id}]">
{{area.title}}
<fa-icon class="icon" [icon]="faArrowAltCircleRight"></fa-icon>
</div>
<div class="entry device" *ngFor="let device of devices">
{{device.title}}
<fa-icon class="icon" [icon]="faPlayCircle"></fa-icon>
</div>
</div>

View File

@ -0,0 +1,25 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {AreaListComponent} from './area-list.component';
describe('AreaListComponent', () => {
let component: AreaListComponent;
let fixture: ComponentFixture<AreaListComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AreaListComponent]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(AreaListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,27 @@
import {Component, OnInit} from '@angular/core';
import {Area} from "../../../../api/area/Area";
import {Device} from "../../../../api/device/Device";
import {faArrowAltCircleRight, faPlayCircle} from '@fortawesome/free-regular-svg-icons';
import {STUB_AREAS, STUB_DEVICES} from "../../../../api/STUB";
@Component({
selector: 'app-area-list',
templateUrl: './area-list.component.html',
styleUrls: ['../device-tree.less']
})
export class AreaListComponent implements OnInit {
readonly faArrowAltCircleRight = faArrowAltCircleRight;
readonly faPlayCircle = faPlayCircle;
areas: Area[] = STUB_AREAS.sort(Area.comparePosition);
devices: Device[] = STUB_DEVICES.filter(d => d.areaId === null && d.roomId === null).sort(Device.comparePosition);
constructor() {
}
ngOnInit(): void {
}
}

View File

@ -0,0 +1,24 @@
<div class="list devices" *ngIf="room !== undefined">
<div class="entry back" [routerLink]="['/RoomList', {id: room.areaId}]">
<fa-icon [icon]="faArrowAltCircleLeft"></fa-icon>
|
{{room.title}}
</div>
<div class="entry device {{device.type}}" *ngFor="let device of devices">
{{device.title}}
<ng-container *ngIf="device.type === 'DeviceSwitch'">
<fa-icon class="icon" [icon]="faTimesCircle"></fa-icon>
<fa-icon class="icon" [icon]="faCheckCircle"></fa-icon>
</ng-container>
<ng-container *ngIf="device.type === 'DeviceStateScene'">
<fa-icon class="icon" [icon]="faPlayCircle"></fa-icon>
</ng-container>
</div>
</div>

View File

@ -0,0 +1,46 @@
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from "@angular/router";
import {Device} from "../../../../api/device/Device";
import {faArrowAltCircleLeft, faArrowAltCircleRight, faCheckCircle, faPlayCircle, faTimesCircle} from '@fortawesome/free-regular-svg-icons';
import {STUB_DEVICES, STUB_ROOMS} from "../../../../api/STUB";
import {Room} from "../../../../api/room/Room";
@Component({
selector: 'app-device-list',
templateUrl: './device-list.component.html',
styleUrls: ['../device-tree.less']
})
export class DeviceListComponent implements OnInit {
readonly faArrowAltCircleLeft = faArrowAltCircleLeft;
readonly faArrowAltCircleRight = faArrowAltCircleRight;
readonly faPlayCircle = faPlayCircle;
readonly faCheckCircle = faCheckCircle;
readonly faTimesCircle = faTimesCircle;
room?: Room;
devices: Device[] = [];
constructor(
readonly route: ActivatedRoute,
) {
this.route.paramMap.subscribe(params => {
const roomIdStr: string | null = params.get("roomId");
if (roomIdStr != null) {
const roomId: number = parseInt(roomIdStr);
this.room = STUB_ROOMS.find(Room.filterById(roomId));
if (this.room) {
this.devices = STUB_DEVICES.filter(Device.filterByAreaIdAndRoomId(this.room.areaId, this.room.id)).sort(Device.comparePosition);
} else {
this.devices = [];
}
}
})
}
ngOnInit(): void {
}
}

View File

@ -0,0 +1,34 @@
.list {
font-size: 10vmin;
.entry {
padding: 3vmin;
border-bottom: 1px solid black;
.icon {
float: right;
margin-left: 3vmin;
}
}
.area {
background-color: lightsteelblue;
}
.area:active {
background-color: cornflowerblue;
}
.device {
background-color: lightcyan;
}
.DeviceSwitch {
background-color: gray;
}
.device:active {
background-color: darkcyan;
}
}

View File

@ -0,0 +1,15 @@
<div class="list rooms" *ngIf="area !== undefined">
<div class="entry back" [routerLink]="['/AreaList']">
<fa-icon [icon]="faArrowAltCircleLeft"></fa-icon>
|
{{area.title}}
</div>
<div class="entry room" *ngFor="let room of rooms" [routerLink]="['/DeviceList', {roomId: room.id}]">
{{room.title}}
<fa-icon class="icon" [icon]="faArrowAltCircleRight"></fa-icon>
</div>
<div class="entry device" *ngFor="let device of devices">
{{device.title}}
<fa-icon class="icon" [icon]="faPlayCircle"></fa-icon>
</div>
</div>

View File

@ -0,0 +1,25 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {RoomListComponent} from './room-list.component';
describe('RoomListComponent', () => {
let component: RoomListComponent;
let fixture: ComponentFixture<RoomListComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [RoomListComponent]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(RoomListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,44 @@
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from "@angular/router";
import {Room} from "../../../../api/room/Room";
import {Device} from "../../../../api/device/Device";
import {faArrowAltCircleLeft, faArrowAltCircleRight, faPlayCircle} from '@fortawesome/free-regular-svg-icons';
import {STUB_AREAS, STUB_DEVICES, STUB_ROOMS} from "../../../../api/STUB";
import {Area} from "../../../../api/area/Area";
@Component({
selector: 'app-room-list',
templateUrl: './room-list.component.html',
styleUrls: ['../device-tree.less']
})
export class RoomListComponent implements OnInit {
readonly faArrowAltCircleLeft = faArrowAltCircleLeft;
readonly faArrowAltCircleRight = faArrowAltCircleRight;
readonly faPlayCircle = faPlayCircle;
area?: Area;
rooms: Room[] = [];
devices: Device[] = [];
constructor(
readonly route: ActivatedRoute,
) {
this.route.paramMap.subscribe(params => {
const areaIdStr: string | null = params.get("id");
if (areaIdStr != null) {
const areaId: number = parseInt(areaIdStr);
this.area = STUB_AREAS.find(Area.filterById(areaId));
this.rooms = STUB_ROOMS.filter(Room.filterByAreaId(areaId)).sort(Room.comparePosition);
this.devices = STUB_DEVICES.filter(Device.filterByAreaIdAndRoomId(areaId, null)).sort(Device.comparePosition);
}
})
}
ngOnInit(): void {
}
}

View File

@ -15,4 +15,6 @@ public class Config {
private String timezone = "Europe/Berlin"; private String timezone = "Europe/Berlin";
private boolean insertDemoData = false;
} }

View File

@ -4,6 +4,7 @@ import com.luckycatlabs.sunrisesunset.Zenith;
import de.ph87.homeautomation.channel.Channel; import de.ph87.homeautomation.channel.Channel;
import de.ph87.homeautomation.device.DeviceRepository; import de.ph87.homeautomation.device.DeviceRepository;
import de.ph87.homeautomation.device.DeviceWriteService; import de.ph87.homeautomation.device.DeviceWriteService;
import de.ph87.homeautomation.device.devices.DeviceDto;
import de.ph87.homeautomation.knx.group.KnxGroup; import de.ph87.homeautomation.knx.group.KnxGroup;
import de.ph87.homeautomation.knx.group.KnxGroupReadService; import de.ph87.homeautomation.knx.group.KnxGroupReadService;
import de.ph87.homeautomation.logic.Logic; import de.ph87.homeautomation.logic.Logic;
@ -13,6 +14,7 @@ import de.ph87.homeautomation.logic.LogicWriter;
import de.ph87.homeautomation.property.Property; import de.ph87.homeautomation.property.Property;
import de.ph87.homeautomation.property.PropertyRepository; import de.ph87.homeautomation.property.PropertyRepository;
import de.ph87.homeautomation.property.PropertyType; import de.ph87.homeautomation.property.PropertyType;
import de.ph87.homeautomation.scene.SceneDto;
import de.ph87.homeautomation.scene.SceneRepository; import de.ph87.homeautomation.scene.SceneRepository;
import de.ph87.homeautomation.scene.SceneWriteService; import de.ph87.homeautomation.scene.SceneWriteService;
import de.ph87.homeautomation.schedule.Schedule; import de.ph87.homeautomation.schedule.Schedule;
@ -57,100 +59,106 @@ public class DemoDataService {
private final LogicRepository logicRepository; private final LogicRepository logicRepository;
private final Config config;
public void insertDemoData() { public void insertDemoData() {
// final Property erdgeschoss = createProperty("Erdgeschoss", PropertyType.BOOLEAN, knx(0, 4, 2), null); if (!config.isInsertDemoData()) {
// final Property erdgeschoss_szene = createProperty("Erdgeschoss Szene", PropertyType.SCENE, null, knx(0, 0, 1)); return;
// final Property obergeschoss = createProperty("Obergeschoss", PropertyType.BOOLEAN, knx(0, 6, 6), null); }
// final Property obergeschoss_szene = createProperty("Obergeschoss Szene", PropertyType.SCENE, null, knx(0, 3, 2));
//
// final Property fernseher = createProperty("Fernseher", PropertyType.BOOLEAN, knx(0, 0, 20), knx(0, 0, 4));
// final Property verstaerker = createProperty("Verstärker", PropertyType.BOOLEAN, knx(0, 3, 57), knx(0, 3, 56));
// final Property aussendekoration = createProperty("Außendekoration", PropertyType.BOOLEAN, knx(0, 4, 12), knx(0, 4, 11));
// final Property terrasse = createProperty("Terrasse Licht", PropertyType.BOOLEAN, knx(0, 4, 1), knx(0, 4, 0));
//
// final Property ambiente_eg = createProperty("Ambiente EG", PropertyType.BOOLEAN, knx(0, 3, 81), knx(0, 3, 80));
// final Property ambiente_og = createProperty("Ambiente OG", PropertyType.BOOLEAN, knx(0, 6, 2), knx(0, 6, 3));
// final Property flur_eg_licht = createProperty("Flur EG Licht", PropertyType.BOOLEAN, knx(0, 4, 8), knx(0, 5, 14)); final Property erdgeschoss = createProperty("Erdgeschoss", PropertyType.BOOLEAN, knx(0, 4, 2), null);
// final Property erdgeschoss_szene = createProperty("Erdgeschoss Szene", PropertyType.SCENE, null, knx(0, 0, 1));
// final Property wohnzimmer_rollladen = createProperty("Wohnzimmer Rollladen", PropertyType.SHUTTER, null, knx(0, 4, 24)); final Property obergeschoss = createProperty("Obergeschoss", PropertyType.BOOLEAN, knx(0, 6, 6), null);
// final Property schlafzimmer_rollladen = createProperty("Schlafzimmer Rollladen", PropertyType.SHUTTER, null, knx(0, 3, 3)); final Property obergeschoss_szene = createProperty("Obergeschoss Szene", PropertyType.SCENE, null, knx(0, 3, 2));
// final Property flur_og_rollladen = createProperty("Flur OG Rollladen", PropertyType.SHUTTER, null, knx(0, 5, 13));
//
// final Property helligkeit = createProperty("Helligkeit", PropertyType.LUX, knx(0, 5, 6), null);
// final Property szene_haus = createProperty("Szene Haus ", PropertyType.SCENE, null, knx(0, 0, 21));
// final SceneDto alles_aus = sceneWriteService.create(1, "Alles AUS"); final Property fernseher = createProperty("Fernseher", PropertyType.BOOLEAN, knx(0, 0, 20), knx(0, 0, 4));
// final SceneDto nachtlicht = sceneWriteService.create(2, "Nachtlicht"); final Property verstaerker = createProperty("Verstärker", PropertyType.BOOLEAN, knx(0, 3, 57), knx(0, 3, 56));
// final SceneDto aussendekoration_aus = sceneWriteService.create(30, "Außendekoration AUS"); final Property aussendekoration = createProperty("Außendekoration", PropertyType.BOOLEAN, knx(0, 4, 12), knx(0, 4, 11));
// final SceneDto aussendekoration_an = sceneWriteService.create(31, "Außendekoration AN"); final Property terrasse = createProperty("Terrasse Licht", PropertyType.BOOLEAN, knx(0, 4, 1), knx(0, 4, 0));
//
// deviceWriteService.createDeviceStateScene(erdgeschoss, erdgeschoss_szene, alles_aus);
// deviceWriteService.createDeviceStateScene(obergeschoss, obergeschoss_szene, alles_aus);
//
// deviceWriteService.createDeviceSwitch(fernseher);
// deviceWriteService.createDeviceSwitch(verstaerker);
// deviceWriteService.createDeviceSwitch(aussendekoration);
// deviceWriteService.createDeviceSwitch(terrasse);
//
// deviceWriteService.createDeviceSwitch(ambiente_eg);
// deviceWriteService.createDeviceSwitch(ambiente_og);
// deviceWriteService.createDeviceSwitch(flur_eg_licht); final Property ambiente_eg = createProperty("Ambiente EG", PropertyType.BOOLEAN, knx(0, 3, 81), knx(0, 3, 80));
// final Property ambiente_og = createProperty("Ambiente OG", PropertyType.BOOLEAN, knx(0, 6, 2), knx(0, 6, 3));
// deviceWriteService.createDeviceShutter(wohnzimmer_rollladen);
// deviceWriteService.createDeviceShutter(schlafzimmer_rollladen); final Property flur_eg_licht = createProperty("Flur EG Licht", PropertyType.BOOLEAN, knx(0, 4, 8), knx(0, 5, 14));
// deviceWriteService.createDeviceShutter(flur_og_rollladen);
// final Property wohnzimmer_rollladen = createProperty("Wohnzimmer Rollladen", PropertyType.SHUTTER, null, knx(0, 4, 24));
// final Schedule scheduleEgFlurLicht = createSchedule(true, "EG Flur Licht", flur_eg_licht); final Property schlafzimmer_rollladen = createProperty("Schlafzimmer Rollladen", PropertyType.SHUTTER, null, knx(0, 3, 3));
// createTime(scheduleEgFlurLicht, true, 1, 0, 0, MIN30, true); final Property flur_og_rollladen = createProperty("Flur OG Rollladen", PropertyType.SHUTTER, null, knx(0, 5, 13));
// createTime(scheduleEgFlurLicht, true, 2, 0, 0, MIN30, false);
// createTime(scheduleEgFlurLicht, true, 7, 30, 0, MIN30, true); final Property helligkeit = createProperty("Helligkeit", PropertyType.LUX, knx(0, 5, 6), null);
// createTime(scheduleEgFlurLicht, true, 8, 30, 0, MIN30, false); final Property szene_haus = createProperty("Szene Haus ", PropertyType.SCENE, null, knx(0, 0, 21));
// createTime(scheduleEgFlurLicht, true, 13, 30, 0, MIN30, true);
// createTime(scheduleEgFlurLicht, true, 14, 30, 0, MIN30, false); final SceneDto alles_aus = sceneWriteService.create(1, "Alles AUS");
// createTime(scheduleEgFlurLicht, true, 19, 0, 0, MIN30, true); final SceneDto nachtlicht = sceneWriteService.create(2, "Nachtlicht");
// createTime(scheduleEgFlurLicht, true, 20, 0, 0, MIN30, false); final SceneDto aussendekoration_aus = sceneWriteService.create(30, "Außendekoration AUS");
// scheduleRepository.save(scheduleEgFlurLicht); final SceneDto aussendekoration_an = sceneWriteService.create(31, "Außendekoration AN");
//
// final Schedule scheduleEgAmbiente = createSchedule(false, "Ambiente EG", ambiente_eg); deviceWriteService.createDeviceStateScene(erdgeschoss, erdgeschoss_szene, alles_aus);
// createTime(scheduleEgAmbiente, true, 7, 15, 0, MIN30, true); deviceWriteService.createDeviceStateScene(obergeschoss, obergeschoss_szene, alles_aus);
// createTime(scheduleEgAmbiente, true, 9, 30, 0, MIN30, false);
// createSunset(scheduleEgAmbiente, true, Zenith.OFFICIAL, MIN30, true); deviceWriteService.createDeviceSwitch(fernseher);
// createSunset(scheduleEgAmbiente, true, Zenith.ASTRONOMICAL, MIN30, false); deviceWriteService.createDeviceSwitch(verstaerker);
// scheduleRepository.save(scheduleEgAmbiente); deviceWriteService.createDeviceSwitch(aussendekoration);
// deviceWriteService.createDeviceSwitch(terrasse);
// final Schedule scheduleOgAmbiente = createSchedule(false, "Ambiente OG", ambiente_og);
// createTime(scheduleOgAmbiente, true, 7, 15, 0, MIN30, true); deviceWriteService.createDeviceSwitch(ambiente_eg);
// createTime(scheduleOgAmbiente, true, 9, 30, 0, MIN30, false); deviceWriteService.createDeviceSwitch(ambiente_og);
// createSunset(scheduleOgAmbiente, true, Zenith.OFFICIAL, MIN30, true);
// createSunset(scheduleOgAmbiente, true, Zenith.ASTRONOMICAL, MIN30, false); deviceWriteService.createDeviceSwitch(flur_eg_licht);
// scheduleRepository.save(scheduleOgAmbiente);
// deviceWriteService.createDeviceShutter(wohnzimmer_rollladen);
// final Schedule scheduleWohnzimmerRollladen = createSchedule(true, "Rollläden Wohnzimmer", wohnzimmer_rollladen); deviceWriteService.createDeviceShutter(schlafzimmer_rollladen);
// createSunrise(scheduleWohnzimmerRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 0); deviceWriteService.createDeviceShutter(flur_og_rollladen);
// createSunset(scheduleWohnzimmerRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100);
// scheduleRepository.save(scheduleWohnzimmerRollladen); final Schedule scheduleEgFlurLicht = createSchedule(true, "EG Flur Licht", flur_eg_licht);
// createTime(scheduleEgFlurLicht, true, 1, 0, 0, MIN30, true);
// final Schedule scheduleSchlafzimmerRollladen = createSchedule(true, "Rollläden Schlafzimmer", schlafzimmer_rollladen); createTime(scheduleEgFlurLicht, true, 2, 0, 0, MIN30, false);
// createTime(scheduleSchlafzimmerRollladen, true, 7, 0, 0, 0, 0); createTime(scheduleEgFlurLicht, true, 7, 30, 0, MIN30, true);
// createSunset(scheduleSchlafzimmerRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100); createTime(scheduleEgFlurLicht, true, 8, 30, 0, MIN30, false);
// scheduleRepository.save(scheduleSchlafzimmerRollladen); createTime(scheduleEgFlurLicht, true, 13, 30, 0, MIN30, true);
// createTime(scheduleEgFlurLicht, true, 14, 30, 0, MIN30, false);
// final Schedule scheduleFlurRollladen = createSchedule(true, "Rollladen Flur", flur_og_rollladen); createTime(scheduleEgFlurLicht, true, 19, 0, 0, MIN30, true);
// createSunrise(scheduleFlurRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 0); createTime(scheduleEgFlurLicht, true, 20, 0, 0, MIN30, false);
// createSunset(scheduleFlurRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100); scheduleRepository.save(scheduleEgFlurLicht);
// scheduleRepository.save(scheduleFlurRollladen);
// final Schedule scheduleEgAmbiente = createSchedule(false, "Ambiente EG", ambiente_eg);
// final Schedule scheduleSzeneHaus = createSchedule(true, "Dekoration", szene_haus); createTime(scheduleEgAmbiente, true, 7, 15, 0, MIN30, true);
// createTime(scheduleSzeneHaus, true, 6, 0, 0, 0, 31); createTime(scheduleEgAmbiente, true, 9, 30, 0, MIN30, false);
// createTime(scheduleSzeneHaus, true, 8, 30, 0, 0, 30); createSunset(scheduleEgAmbiente, true, Zenith.OFFICIAL, MIN30, true);
// createSunset(scheduleSzeneHaus, true, Zenith.OFFICIAL, 0, 31); createSunset(scheduleEgAmbiente, true, Zenith.ASTRONOMICAL, MIN30, false);
// createTime(scheduleSzeneHaus, true, 22, 0, 0, 0, 30); scheduleRepository.save(scheduleEgAmbiente);
// scheduleRepository.save(scheduleSzeneHaus);
// final Schedule scheduleOgAmbiente = createSchedule(false, "Ambiente OG", ambiente_og);
// final Property propertyBadLicht = createProperty("Bad Licht", PropertyType.BOOLEAN, knx(0, 5, 19), knx(0, 3, 73)); createTime(scheduleOgAmbiente, true, 7, 15, 0, MIN30, true);
// final DeviceDto deviceBadLicht = deviceWriteService.createDeviceSwitch(propertyBadLicht); createTime(scheduleOgAmbiente, true, 9, 30, 0, MIN30, false);
createSunset(scheduleOgAmbiente, true, Zenith.OFFICIAL, MIN30, true);
createSunset(scheduleOgAmbiente, true, Zenith.ASTRONOMICAL, MIN30, false);
scheduleRepository.save(scheduleOgAmbiente);
final Schedule scheduleWohnzimmerRollladen = createSchedule(true, "Rollläden Wohnzimmer", wohnzimmer_rollladen);
createSunrise(scheduleWohnzimmerRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 0);
createSunset(scheduleWohnzimmerRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100);
scheduleRepository.save(scheduleWohnzimmerRollladen);
final Schedule scheduleSchlafzimmerRollladen = createSchedule(true, "Rollläden Schlafzimmer", schlafzimmer_rollladen);
createTime(scheduleSchlafzimmerRollladen, true, 7, 0, 0, 0, 0);
createSunset(scheduleSchlafzimmerRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100);
scheduleRepository.save(scheduleSchlafzimmerRollladen);
final Schedule scheduleFlurRollladen = createSchedule(true, "Rollladen Flur", flur_og_rollladen);
createSunrise(scheduleFlurRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 0);
createSunset(scheduleFlurRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100);
scheduleRepository.save(scheduleFlurRollladen);
final Schedule scheduleSzeneHaus = createSchedule(true, "Dekoration", szene_haus);
createTime(scheduleSzeneHaus, true, 6, 0, 0, 0, 31);
createTime(scheduleSzeneHaus, true, 8, 30, 0, 0, 30);
createSunset(scheduleSzeneHaus, true, Zenith.OFFICIAL, 0, 31);
createTime(scheduleSzeneHaus, true, 22, 0, 0, 0, 30);
scheduleRepository.save(scheduleSzeneHaus);
final Property propertyBadLicht = createProperty("Bad Licht", PropertyType.BOOLEAN, knx(0, 5, 19), knx(0, 3, 73));
final DeviceDto deviceBadLicht = deviceWriteService.createDeviceSwitch(propertyBadLicht);
// final Logic logicStatusOg = getOrCreateLogic("Status OG", LogicOperator.OR, propertyBadLicht); // final Logic logicStatusOg = getOrCreateLogic("Status OG", LogicOperator.OR, propertyBadLicht);
// final Property propertyStatusOg = createProperty(logicStatusOg.getName(), PropertyType.BOOLEAN, logicStatusOg, null); // final Property propertyStatusOg = createProperty(logicStatusOg.getName(), PropertyType.BOOLEAN, logicStatusOg, null);
// final DeviceDto deviceStatusOg = deviceWriteService.createDeviceSwitch(propertyStatusOg); // final DeviceDto deviceStatusOg = deviceWriteService.createDeviceSwitch(propertyStatusOg);

View File

@ -32,9 +32,15 @@ public class KnxGroupImportService {
private void importGroup(final Element ga) { private void importGroup(final Element ga) {
final GroupAddress address = new GroupAddress(Integer.parseInt(ga.attr("Address"))); final GroupAddress address = new GroupAddress(Integer.parseInt(ga.attr("Address")));
final String name = ga.attr("Name");
final String datapointType = ga.attr("DatapointType");
if (datapointType.isEmpty()) {
log.warn("Cannot import Group without DPT: {} \"{}\"", address, name);
return;
}
final KnxGroup knxGroup = knxGroupRepository.findByAddressRaw(address.getRawAddress()).orElseGet(() -> knxGroupRepository.save(new KnxGroup(address))); final KnxGroup knxGroup = knxGroupRepository.findByAddressRaw(address.getRawAddress()).orElseGet(() -> knxGroupRepository.save(new KnxGroup(address)));
setDpt(knxGroup, ga.attr("DatapointType")); setDpt(knxGroup, datapointType);
knxGroup.setName(ga.attr("Name")); knxGroup.setName(name);
knxGroup.setDescription(ga.attr("Description")); knxGroup.setDescription(ga.attr("Description"));
knxGroup.setPuid(Integer.parseInt(ga.attr("Puid"))); knxGroup.setPuid(Integer.parseInt(ga.attr("Puid")));
knxGroup.setEts(true); knxGroup.setEts(true);