DeviceSwitch, DeviceShutter incl. UI
This commit is contained in:
parent
08f1c6f93f
commit
4939d9398f
@ -6,7 +6,7 @@ import {environment} from "../../environments/environment";
|
||||
export function NO_OP() {
|
||||
}
|
||||
|
||||
export function NO_SORT<T>(a: T, b: T): number {
|
||||
export function NO_COMPARE<T>(a: T, b: T): number {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ export class ApiService {
|
||||
this.http.get<any>(environment.apiBasePath + path).pipe(map(fromJson)).subscribe(next, errorInterceptor(error));
|
||||
}
|
||||
|
||||
getList<T>(path: string, fromJson: (json: any) => T, compare: (a: T, b: T) => number = NO_SORT, next: (list: T[]) => void = NO_OP, error: (error: any) => void = NO_OP) {
|
||||
getList<T>(path: string, fromJson: (json: any) => T, compare: (a: T, b: T) => number = NO_COMPARE, next: (list: T[]) => void = NO_OP, error: (error: any) => void = NO_OP) {
|
||||
this.http.get<any[]>(environment.apiBasePath + path).pipe(map(list => list.map(fromJson).sort(compare))).subscribe(next, errorInterceptor(error));
|
||||
}
|
||||
|
||||
|
||||
73
src/main/angular/src/app/api/device/Device.ts
Normal file
73
src/main/angular/src/app/api/device/Device.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import {validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators";
|
||||
import {Property} from "../property/property.service";
|
||||
|
||||
export abstract class Device {
|
||||
|
||||
constructor(
|
||||
readonly id: number,
|
||||
readonly title: string,
|
||||
readonly type: string,
|
||||
) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
static fromJson(json: any): Device {
|
||||
const type: string = validateStringNotEmptyNotNull(json['type']);
|
||||
switch (type) {
|
||||
case "DeviceSwitch":
|
||||
return new DeviceSwitch(
|
||||
validateNumberNotNull(json['id']),
|
||||
validateStringNotEmptyNotNull(json['title']),
|
||||
type,
|
||||
Property.fromJsonAllowNull(json['getState']),
|
||||
Property.fromJsonAllowNull(json['setState']),
|
||||
);
|
||||
case "DeviceShutter":
|
||||
return new DeviceShutter(
|
||||
validateNumberNotNull(json['id']),
|
||||
validateStringNotEmptyNotNull(json['title']),
|
||||
type,
|
||||
Property.fromJsonAllowNull(json['getPercent']),
|
||||
Property.fromJsonAllowNull(json['setPercent']),
|
||||
);
|
||||
}
|
||||
throw new Error("No such type: " + type);
|
||||
}
|
||||
|
||||
public static trackBy(index: number, item: Device): string {
|
||||
return item.title;
|
||||
}
|
||||
|
||||
public static compareTitle(a: Device, b: Device): number {
|
||||
return a.title.localeCompare(b.title);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class DeviceSwitch extends Device {
|
||||
|
||||
constructor(
|
||||
id: number,
|
||||
title: string,
|
||||
type: string,
|
||||
readonly getState: Property | null,
|
||||
readonly setState: Property | null,
|
||||
) {
|
||||
super(id, title, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class DeviceShutter extends Device {
|
||||
|
||||
constructor(
|
||||
id: number,
|
||||
title: string,
|
||||
type: string,
|
||||
readonly getPercent: Property | null,
|
||||
readonly setPercent: Property | null,
|
||||
) {
|
||||
super(id, title, type);
|
||||
}
|
||||
|
||||
}
|
||||
0
src/main/angular/src/app/api/device/DeviceSwitch.ts
Normal file
0
src/main/angular/src/app/api/device/DeviceSwitch.ts
Normal file
16
src/main/angular/src/app/api/device/device.service.spec.ts
Normal file
16
src/main/angular/src/app/api/device/device.service.spec.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
|
||||
import {DeviceService} from './device.service';
|
||||
|
||||
describe('DeviceService', () => {
|
||||
let service: DeviceService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(DeviceService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
20
src/main/angular/src/app/api/device/device.service.ts
Normal file
20
src/main/angular/src/app/api/device/device.service.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {ApiService, NO_COMPARE, NO_OP} from "../api.service";
|
||||
import {Device} from "./Device";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DeviceService {
|
||||
|
||||
constructor(
|
||||
readonly api: ApiService,
|
||||
) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
findAll(next: (list: Device[]) => void, compare: (a: Device, b: Device) => number = NO_COMPARE, error: (error: any) => void = NO_OP): void {
|
||||
this.api.getList("device/findAll", Device.fromJson, compare, next, error);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {ApiService, NO_OP} from "../api.service";
|
||||
import {validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators";
|
||||
import {validateBooleanAllowNull, validateDateAllowNull, validateNumberAllowNull, validateStringNotEmptyNotNull} from "../validators";
|
||||
import {ISearchService} from "../ISearchService";
|
||||
import {KeyValuePair} from "../KeyValuePair";
|
||||
|
||||
@ -8,17 +8,30 @@ export class Property {
|
||||
|
||||
constructor(
|
||||
public name: string,
|
||||
public type: string,
|
||||
public value: number,
|
||||
public title: string,
|
||||
public propertyType: string,
|
||||
public booleanValue: boolean | null,
|
||||
public numberValue: number | null,
|
||||
public timestamp: Date | null,
|
||||
) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
static fromJsonAllowNull(json: any): Property | null {
|
||||
if (json === undefined || json === null) {
|
||||
return null;
|
||||
}
|
||||
return this.fromJson(json);
|
||||
}
|
||||
|
||||
static fromJson(json: any): Property {
|
||||
return new Property(
|
||||
validateStringNotEmptyNotNull(json['name']),
|
||||
validateStringNotEmptyNotNull(json['type']),
|
||||
validateNumberNotNull(json['value']),
|
||||
validateStringNotEmptyNotNull(json['title']),
|
||||
validateStringNotEmptyNotNull(json['propertyType']),
|
||||
validateBooleanAllowNull(json['booleanValue']),
|
||||
validateNumberAllowNull(json['numberValue']),
|
||||
validateDateAllowNull(json['timestamp']),
|
||||
);
|
||||
}
|
||||
|
||||
@ -51,4 +64,8 @@ export class PropertyService implements ISearchService {
|
||||
this.api.postReturnList("property/searchLike", term, KeyValuePair.fromJson, next, error);
|
||||
}
|
||||
|
||||
set(name: string, value: number, next: () => void = NO_OP, error: (error: any) => void = NO_OP): void {
|
||||
this.api.postReturnNone("property/set", {name: name, value: value}, next, error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,8 +2,10 @@ import {NgModule} from '@angular/core';
|
||||
import {RouterModule, Routes} from '@angular/router';
|
||||
import {ScheduleListComponent} from "./pages/schedule-list/schedule-list.component";
|
||||
import {ScheduleComponent} from "./pages/schedule/schedule.component";
|
||||
import {DeviceListComponent} from "./pages/device-list/device-list.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{path: 'DeviceList', component: DeviceListComponent},
|
||||
{path: 'Schedule', component: ScheduleComponent},
|
||||
{path: 'ScheduleList', component: ScheduleListComponent},
|
||||
{path: '**', redirectTo: '/ScheduleList'},
|
||||
|
||||
@ -4,6 +4,10 @@
|
||||
Zeitpläne
|
||||
</div>
|
||||
|
||||
<div class="item" routerLink="/DeviceList" routerLinkActive="itemActive">
|
||||
Geräte
|
||||
</div>
|
||||
|
||||
<!-- <div class="item breadcrumb" [routerLink]="['/Schedule', {id: dataService.schedule.id}]" routerLinkActive="itemActive" *ngIf="dataService.schedule">-->
|
||||
<!-- {{dataService.schedule.name}}-->
|
||||
<!-- </div>-->
|
||||
|
||||
@ -7,6 +7,10 @@
|
||||
border-right: 1px solid black;
|
||||
}
|
||||
|
||||
.item:hover {
|
||||
background-color: lightskyblue;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||
import {NumberComponent} from './shared/number/number.component';
|
||||
import {ScheduleComponent} from "./pages/schedule/schedule.component";
|
||||
import {SearchComponent} from './shared/search/search.component';
|
||||
import {DeviceListComponent} from './pages/device-list/device-list.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -20,6 +21,7 @@ import {SearchComponent} from './shared/search/search.component';
|
||||
ScheduleListComponent,
|
||||
NumberComponent,
|
||||
SearchComponent,
|
||||
DeviceListComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
<ng-container *ngFor="let device of devices">
|
||||
<ng-container [ngSwitch]="device.type">
|
||||
<div class="device" *ngSwitchCase="'DeviceSwitch'" [class.switchOn]="isSwitchStateOn(device)" [class.switchOff]="isSwitchStateOff(device)" [class.switchUnknown]="isSwitchStateUnknown(device)">
|
||||
<div class="title">
|
||||
{{device.title}}
|
||||
</div>
|
||||
<div class="controls">
|
||||
<img class="control" src="assets/switch-on.svg" (click)="setSwitchState(device, true)"/>
|
||||
<img class="control" src="assets/switch-off.svg" (click)="setSwitchState(device, false)"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="device" *ngSwitchCase="'DeviceShutter'" [class.blindOpen]="isShutterStateOpen(device)" [class.shutterBetween]="isShutterStateBetween(device)" [class.shutterClosed]="isShutterStateClosed(device)" [class.shutterUnknown]="isShutterStateUnknown(device)">
|
||||
<div class="title">
|
||||
{{device.title}}
|
||||
</div>
|
||||
<div class="controls">
|
||||
<div class="control button" (click)="setShutterPercent(device, 0)">
|
||||
<span class="center">Auf</span>
|
||||
</div>
|
||||
<div class="control button" (click)="setShutterPercent(device, 40)">
|
||||
<span class="center">50%</span>
|
||||
</div>
|
||||
<div class="control button" (click)="setShutterPercent(device, 75)">
|
||||
<span class="center">90%</span>
|
||||
</div>
|
||||
<div class="control button" (click)="setShutterPercent(device, 85)">
|
||||
<span class="center">Schlitze</span>
|
||||
</div>
|
||||
<div class="control button" (click)="setShutterPercent(device, 100)">
|
||||
<span class="center">Zu</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
@ -0,0 +1,66 @@
|
||||
.device {
|
||||
padding: 5px;
|
||||
margin-bottom: 5px;
|
||||
border-radius: 10px;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.controls {
|
||||
.control {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
border-radius: 25%;
|
||||
|
||||
.center {
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: lightblue;
|
||||
}
|
||||
|
||||
.control:hover {
|
||||
background-color: lightskyblue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.switchOn {
|
||||
background-color: palegreen;
|
||||
}
|
||||
|
||||
.switchOff {
|
||||
background-color: indianred;
|
||||
}
|
||||
|
||||
.switchUnknown {
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
.blindOpen {
|
||||
background-color: palegreen;
|
||||
}
|
||||
|
||||
.shutterBetween {
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
.shutterClosed {
|
||||
background-color: indianred;
|
||||
}
|
||||
|
||||
.shutterUnknown {
|
||||
background-color: gray;
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {DeviceListComponent} from './device-list.component';
|
||||
|
||||
describe('DeviceListComponent', () => {
|
||||
let component: DeviceListComponent;
|
||||
let fixture: ComponentFixture<DeviceListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [DeviceListComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DeviceListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,81 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {DeviceService} from "../../api/device/device.service";
|
||||
import {PropertyService} from "../../api/property/property.service";
|
||||
import {Device, DeviceShutter, DeviceSwitch} from "../../api/device/Device";
|
||||
|
||||
@Component({
|
||||
selector: 'app-device-list',
|
||||
templateUrl: './device-list.component.html',
|
||||
styleUrls: ['./device-list.component.less']
|
||||
})
|
||||
export class DeviceListComponent implements OnInit {
|
||||
|
||||
devices: Device[] = [];
|
||||
|
||||
constructor(
|
||||
readonly deviceService: DeviceService,
|
||||
readonly propertyService: PropertyService,
|
||||
) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.deviceService.findAll(devices => this.devices = devices);
|
||||
}
|
||||
|
||||
asDeviceSwitch(device: Device): DeviceSwitch {
|
||||
return device as DeviceSwitch;
|
||||
}
|
||||
|
||||
asDeviceShutter(device: Device): DeviceShutter {
|
||||
return device as DeviceShutter;
|
||||
}
|
||||
|
||||
setSwitchState(d: Device, value: boolean): void {
|
||||
const device: DeviceSwitch = d as DeviceSwitch;
|
||||
if (!device.setState) {
|
||||
throw new Error("Property 'setState' not set for: " + device);
|
||||
}
|
||||
this.propertyService.set(device.setState.name, value ? 1 : 0);
|
||||
}
|
||||
|
||||
setShutterPercent(d: Device, value: number): void {
|
||||
const device: DeviceShutter = d as DeviceShutter;
|
||||
if (!device.setPercent) {
|
||||
throw new Error("Property 'setPercent' not set for: " + device);
|
||||
}
|
||||
this.propertyService.set(device.setPercent.name, value);
|
||||
}
|
||||
|
||||
isSwitchStateOn(device: Device): boolean {
|
||||
return (device as DeviceSwitch).getState?.booleanValue === true;
|
||||
}
|
||||
|
||||
isSwitchStateOff(device: Device): boolean {
|
||||
return (device as DeviceSwitch).getState?.booleanValue === false;
|
||||
}
|
||||
|
||||
isSwitchStateUnknown(device: Device): boolean {
|
||||
const value: boolean | null | undefined = (device as DeviceSwitch).getState?.booleanValue;
|
||||
return value === null || value === undefined;
|
||||
}
|
||||
|
||||
isShutterStateOpen(device: Device): boolean {
|
||||
return (device as DeviceShutter).getPercent?.numberValue === 0;
|
||||
}
|
||||
|
||||
isShutterStateBetween(device: Device): boolean {
|
||||
const value: number | null | undefined = (device as DeviceShutter).getPercent?.numberValue;
|
||||
return value !== null && value !== undefined && value > 0 && value < 100;
|
||||
}
|
||||
|
||||
isShutterStateClosed(device: Device): boolean {
|
||||
return (device as DeviceShutter).getPercent?.numberValue === 100;
|
||||
}
|
||||
|
||||
isShutterStateUnknown(device: Device): boolean {
|
||||
const value: number | null | undefined = (device as DeviceShutter).getPercent?.numberValue;
|
||||
return value === null || value === undefined;
|
||||
}
|
||||
|
||||
}
|
||||
@ -91,7 +91,6 @@ export class SearchComponent<T> implements OnInit {
|
||||
}
|
||||
|
||||
select(result: KeyValuePair): void {
|
||||
console.log(result);
|
||||
this.searching = false;
|
||||
this.selected = result;
|
||||
this.valueChange.emit(this.selected?.key);
|
||||
|
||||
8
src/main/angular/src/assets/switch-off.svg
Normal file
8
src/main/angular/src/assets/switch-off.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 496.158 496.158" xml:space="preserve">
|
||||
<path style="fill:#EB9783;" d="M496.158,248.085c0-137.021-111.07-248.082-248.076-248.082C111.07,0.003,0,111.063,0,248.085 c0,137.002,111.07,248.07,248.082,248.07C385.088,496.155,496.158,385.087,496.158,248.085z"/>
|
||||
<g>
|
||||
<path style="fill:#D63232;" d="M373.299,154.891c-19.558-26.212-47.401-46.023-78.401-55.787c-0.759-0.238-1.588-0.103-2.229,0.369 c-0.643,0.471-1.021,1.22-1.021,2.016l0.16,40.256c0,1.074,0.514,2.06,1.332,2.562c31.732,19.456,66.504,47,66.504,103.237 c0,61.515-50.047,111.56-111.562,111.56c-61.517,0-111.566-50.045-111.566-111.56c0-58.737,35.199-84.661,67.615-103.917 c0.836-0.496,1.363-1.492,1.363-2.58l0.154-39.909c0-0.793-0.375-1.539-1.013-2.01c-0.638-0.472-1.46-0.611-2.219-0.381 c-31.283,9.586-59.41,29.357-79.202,55.672c-20.467,27.215-31.285,59.603-31.285,93.662c0,86.099,70.049,156.146,156.152,156.146 c86.1,0,156.147-70.047,156.147-156.146C404.228,214.235,393.533,182.01,373.299,154.891z"/>
|
||||
<path style="fill:#D63232;" d="M251.851,67.009h-7.549c-11.788,0-21.378,9.59-21.378,21.377v181.189 c0,11.787,9.59,21.377,21.378,21.377h7.549c11.788,0,21.378-9.59,21.378-21.377V88.386 C273.229,76.599,263.64,67.009,251.851,67.009z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
8
src/main/angular/src/assets/switch-on.svg
Normal file
8
src/main/angular/src/assets/switch-on.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 496.158 496.158" xml:space="preserve">
|
||||
<path style="fill:#97EB83;" d="M496.158,248.085c0-137.021-111.07-248.082-248.076-248.082C111.07,0.003,0,111.063,0,248.085 c0,137.002,111.07,248.07,248.082,248.07C385.088,496.155,496.158,385.087,496.158,248.085z"/>
|
||||
<g>
|
||||
<path style="fill:#32D632;" d="M373.299,154.891c-19.558-26.212-47.401-46.023-78.401-55.787c-0.759-0.238-1.588-0.103-2.229,0.369 c-0.643,0.471-1.021,1.22-1.021,2.016l0.16,40.256c0,1.074,0.514,2.06,1.332,2.562c31.732,19.456,66.504,47,66.504,103.237 c0,61.515-50.047,111.56-111.562,111.56c-61.517,0-111.566-50.045-111.566-111.56c0-58.737,35.199-84.661,67.615-103.917 c0.836-0.496,1.363-1.492,1.363-2.58l0.154-39.909c0-0.793-0.375-1.539-1.013-2.01c-0.638-0.472-1.46-0.611-2.219-0.381 c-31.283,9.586-59.41,29.357-79.202,55.672c-20.467,27.215-31.285,59.603-31.285,93.662c0,86.099,70.049,156.146,156.152,156.146 c86.1,0,156.147-70.047,156.147-156.146C404.228,214.235,393.533,182.01,373.299,154.891z"/>
|
||||
<path style="fill:#32D632;" d="M251.851,67.009h-7.549c-11.788,0-21.378,9.59-21.378,21.377v181.189 c0,11.787,9.59,21.377,21.378,21.377h7.549c11.788,0,21.378-9.59,21.378-21.377V88.386 C273.229,76.599,263.64,67.009,251.851,67.009z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
@ -1,9 +1,11 @@
|
||||
package de.ph87.homeautomation;
|
||||
|
||||
import com.luckycatlabs.sunrisesunset.Zenith;
|
||||
import de.ph87.homeautomation.device.DeviceWriteService;
|
||||
import de.ph87.homeautomation.knx.group.KnxGroupDto;
|
||||
import de.ph87.homeautomation.knx.group.KnxGroupRepository;
|
||||
import de.ph87.homeautomation.knx.group.KnxGroupWriteService;
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import de.ph87.homeautomation.property.PropertyType;
|
||||
import de.ph87.homeautomation.schedule.Schedule;
|
||||
import de.ph87.homeautomation.schedule.ScheduleRepository;
|
||||
@ -23,7 +25,9 @@ import java.time.ZonedDateTime;
|
||||
@RequiredArgsConstructor
|
||||
public class DemoDataService {
|
||||
|
||||
public static final int MIN30 = 30 * 60;
|
||||
private static final int MIN30 = 30 * 60;
|
||||
|
||||
private static final Zenith BETWEEN_OFFICIAL_AND_CIVIL = new Zenith(93.0);
|
||||
|
||||
private final KnxGroupWriteService knxGroupWriteService;
|
||||
|
||||
@ -31,19 +35,25 @@ public class DemoDataService {
|
||||
|
||||
private final KnxGroupRepository knxGroupRepository;
|
||||
|
||||
private final DeviceWriteService deviceWriteService;
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
final KnxGroupDto eg_flur_licht_schalten = createKnxGroupIfNotExists("EG Flur Licht Schalten", 1294, "1.001", PropertyType.ON_OFF, false, false);
|
||||
final KnxGroupDto eg_ambiente_schalten = createKnxGroupIfNotExists("EG Ambiente Schalten", 848, "1.001", PropertyType.ON_OFF, false, false);
|
||||
final KnxGroupDto og_ambiente_schalten = createKnxGroupIfNotExists("OG Ambiente Schalten", 1539, "1.001", PropertyType.ON_OFF, false, false);
|
||||
final KnxGroupDto wohnzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Wohnzimmer Rollladen Position Anfahren", new GroupAddress(0, 4, 24), "5.001", PropertyType.PERCENT, false, false);
|
||||
final KnxGroupDto schlafzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Schlafzimmer Rollladen Position Anfahren", new GroupAddress(0, 3, 3), "5.001", PropertyType.PERCENT, false, false);
|
||||
final KnxGroupDto flur_rollladen_position_anfahren = createKnxGroupIfNotExists("Flur Rollladen Position Anfahren", new GroupAddress(0, 5, 13), "5.001", PropertyType.PERCENT, false, false);
|
||||
final KnxGroupDto bad_licht_mitte_schalten = createKnxGroupIfNotExists("Bad Licht Mitte Schalten", 797, "1.001", PropertyType.ON_OFF, false, false);
|
||||
final KnxGroupDto helligkeit = createKnxGroupIfNotExists("Helligkeit", 1286, "9.004", PropertyType.LUX, false, true);
|
||||
final KnxGroupDto eg_flur_licht_schalten = createKnxGroupIfNotExists("EG Flur Licht Schalten", 0, 5, 14, "1.001", PropertyType.ON_OFF, false, false);
|
||||
final KnxGroupDto eg_ambiente_schalten = createKnxGroupIfNotExists("EG Ambiente Schalten", 0, 3, 80, "1.001", PropertyType.ON_OFF, false, false);
|
||||
final KnxGroupDto og_ambiente_schalten = createKnxGroupIfNotExists("OG Ambiente Schalten", 0, 6, 3, "1.001", PropertyType.ON_OFF, false, false);
|
||||
final KnxGroupDto wohnzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Wohnzimmer Rollladen Position Anfahren", 0, 4, 24, "5.001", PropertyType.PERCENT, false, false);
|
||||
final KnxGroupDto schlafzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Schlafzimmer Rollladen Position Anfahren", 0, 3, 3, "5.001", PropertyType.PERCENT, false, false);
|
||||
final KnxGroupDto flur_rollladen_position_anfahren = createKnxGroupIfNotExists("Flur Rollladen Position Anfahren", 0, 5, 13, "5.001", PropertyType.PERCENT, false, false);
|
||||
final KnxGroupDto bad_licht_mitte_schalten = createKnxGroupIfNotExists("Bad Licht Mitte Schalten", 0, 3, 29, "1.001", PropertyType.ON_OFF, false, false);
|
||||
final KnxGroupDto bad_licht_mitte_status = createKnxGroupIfNotExists("Bad Licht Mitte Status", 0, 3, 30, "1.001", PropertyType.ON_OFF, true, false);
|
||||
final KnxGroupDto helligkeit = createKnxGroupIfNotExists("Helligkeit", 0, 5, 6, "9.004", PropertyType.LUX, false, true);
|
||||
|
||||
deviceWriteService.createDeviceSwitch("Bad Licht Mitte", bad_licht_mitte_status, bad_licht_mitte_schalten);
|
||||
deviceWriteService.createDeviceShutter("Flur OG Rollladen", null, flur_rollladen_position_anfahren);
|
||||
|
||||
if (scheduleRepository.count() == 0) {
|
||||
final Schedule scheduleEgFlurLicht = createSchedule("EG Flur Licht", eg_flur_licht_schalten, PropertyType.ON_OFF);
|
||||
final Schedule scheduleEgFlurLicht = createSchedule("EG Flur Licht", eg_flur_licht_schalten);
|
||||
createTime(scheduleEgFlurLicht, 11, 30, 0, MIN30, true);
|
||||
createTime(scheduleEgFlurLicht, 12, 30, 0, MIN30, false);
|
||||
createTime(scheduleEgFlurLicht, 16, 30, 0, MIN30, true);
|
||||
@ -54,36 +64,36 @@ public class DemoDataService {
|
||||
createTime(scheduleEgFlurLicht, 2, 0, 0, MIN30, false);
|
||||
scheduleRepository.save(scheduleEgFlurLicht);
|
||||
|
||||
final Schedule scheduleEgAmbiente = createSchedule("EG Ambiente", eg_ambiente_schalten, PropertyType.ON_OFF);
|
||||
final Schedule scheduleEgAmbiente = createSchedule("EG Ambiente", eg_ambiente_schalten);
|
||||
createTime(scheduleEgAmbiente, 7, 15, 0, MIN30, true);
|
||||
createTime(scheduleEgAmbiente, 9, 30, 0, MIN30, false);
|
||||
createSunset(scheduleEgAmbiente, Zenith.OFFICIAL, MIN30, true);
|
||||
createSunset(scheduleEgAmbiente, Zenith.ASTRONOMICAL, MIN30, false);
|
||||
scheduleRepository.save(scheduleEgAmbiente);
|
||||
|
||||
final Schedule scheduleOgAmbiente = createSchedule("OG Ambiente", og_ambiente_schalten, PropertyType.ON_OFF);
|
||||
final Schedule scheduleOgAmbiente = createSchedule("OG Ambiente", og_ambiente_schalten);
|
||||
createTime(scheduleOgAmbiente, 7, 15, 0, MIN30, true);
|
||||
createTime(scheduleOgAmbiente, 9, 30, 0, MIN30, false);
|
||||
createSunset(scheduleOgAmbiente, Zenith.OFFICIAL, MIN30, true);
|
||||
createSunset(scheduleOgAmbiente, Zenith.ASTRONOMICAL, MIN30, false);
|
||||
scheduleRepository.save(scheduleOgAmbiente);
|
||||
|
||||
final Schedule scheduleWohnzimmerRollladen = createSchedule("Rollläden Wohnzimmer", wohnzimmer_rollladen_position_anfahren, PropertyType.SHUTTER);
|
||||
createSunrise(scheduleWohnzimmerRollladen, Zenith.CIVIL, 0, 0);
|
||||
createSunset(scheduleWohnzimmerRollladen, Zenith.CIVIL, 0, 100);
|
||||
final Schedule scheduleWohnzimmerRollladen = createSchedule("Rollläden Wohnzimmer", wohnzimmer_rollladen_position_anfahren);
|
||||
createSunrise(scheduleWohnzimmerRollladen, BETWEEN_OFFICIAL_AND_CIVIL, 0, 0);
|
||||
createSunset(scheduleWohnzimmerRollladen, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100);
|
||||
scheduleRepository.save(scheduleWohnzimmerRollladen);
|
||||
|
||||
final Schedule scheduleSchlafzimmerRollladen = createSchedule("Rollläden Schlafzimmer", schlafzimmer_rollladen_position_anfahren, PropertyType.SHUTTER);
|
||||
final Schedule scheduleSchlafzimmerRollladen = createSchedule("Rollläden Schlafzimmer", schlafzimmer_rollladen_position_anfahren);
|
||||
createTime(scheduleSchlafzimmerRollladen, 7, 0, 0, 0, 0);
|
||||
createSunset(scheduleSchlafzimmerRollladen, Zenith.CIVIL, 0, 100);
|
||||
createSunset(scheduleSchlafzimmerRollladen, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100);
|
||||
scheduleRepository.save(scheduleSchlafzimmerRollladen);
|
||||
|
||||
final Schedule scheduleFlurRollladen = createSchedule("Rollladen Flur", flur_rollladen_position_anfahren, PropertyType.SHUTTER);
|
||||
createSunrise(scheduleFlurRollladen, Zenith.CIVIL, 0, 0);
|
||||
createSunset(scheduleFlurRollladen, Zenith.CIVIL, 0, 100);
|
||||
final Schedule scheduleFlurRollladen = createSchedule("Rollladen Flur", flur_rollladen_position_anfahren);
|
||||
createSunrise(scheduleFlurRollladen, BETWEEN_OFFICIAL_AND_CIVIL, 0, 0);
|
||||
createSunset(scheduleFlurRollladen, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100);
|
||||
scheduleRepository.save(scheduleFlurRollladen);
|
||||
|
||||
final Schedule scheduleBadLichtMitte = createSchedule("Bad Licht Mitte", bad_licht_mitte_schalten, PropertyType.ON_OFF);
|
||||
final Schedule scheduleBadLichtMitte = createSchedule("Bad Licht Mitte", bad_licht_mitte_schalten);
|
||||
createTime(scheduleBadLichtMitte, 10, 30, 0, MIN30, true);
|
||||
createTime(scheduleBadLichtMitte, 11, 30, 0, MIN30, false);
|
||||
createTime(scheduleBadLichtMitte, 15, 30, 0, MIN30, true);
|
||||
@ -96,20 +106,17 @@ public class DemoDataService {
|
||||
}
|
||||
}
|
||||
|
||||
private Schedule createSchedule(final String s, final KnxGroupDto knxGroupDto, final PropertyType propertyType) {
|
||||
private Schedule createSchedule(final String s, final PropertyDto propertyDto) {
|
||||
final Schedule schedule = new Schedule();
|
||||
schedule.setEnabled(true);
|
||||
schedule.setName(s);
|
||||
schedule.setPropertyName(knxGroupDto.propertyName);
|
||||
schedule.setPropertyType(propertyType);
|
||||
schedule.setPropertyName(propertyDto.getName());
|
||||
schedule.setPropertyType(propertyDto.getPropertyType());
|
||||
return schedule;
|
||||
}
|
||||
|
||||
private KnxGroupDto createKnxGroupIfNotExists(final String name, final int address, final String dpt, final PropertyType type, final boolean readable, final boolean multiGroup) {
|
||||
return createKnxGroupIfNotExists(name, new GroupAddress(address), dpt, type, readable, multiGroup);
|
||||
}
|
||||
|
||||
private KnxGroupDto createKnxGroupIfNotExists(final String name, final GroupAddress address, final String dpt, final PropertyType type, final boolean readable, final boolean multiGroup) {
|
||||
private KnxGroupDto createKnxGroupIfNotExists(final String name, final int main, final int mid, final int sub, final String dpt, final PropertyType type, final boolean readable, final boolean multiGroup) {
|
||||
final GroupAddress address = new GroupAddress(main, mid, sub);
|
||||
return knxGroupRepository.findByAddressRaw(address.getRawAddress()).map(KnxGroupDto::new).orElseGet(() -> knxGroupWriteService.create(name, address, dpt, type, readable, multiGroup));
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package de.ph87.homeautomation.device;
|
||||
|
||||
import de.ph87.homeautomation.device.devices.DeviceDto;
|
||||
import de.ph87.homeautomation.property.PropertySetException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -14,9 +14,16 @@ public class DeviceController {
|
||||
|
||||
private final DeviceReadService deviceReadService;
|
||||
|
||||
private final DeviceWriteService deviceWriteService;
|
||||
|
||||
@GetMapping("findAll")
|
||||
public List<DeviceDto> findAll() {
|
||||
return deviceReadService.findAll();
|
||||
}
|
||||
|
||||
@PostMapping("set")
|
||||
public void set(@RequestBody final DeviceSetDto dto) throws PropertySetException {
|
||||
deviceWriteService.set(dto);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package de.ph87.homeautomation.device;
|
||||
|
||||
import de.ph87.homeautomation.device.devices.*;
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import de.ph87.homeautomation.property.PropertyService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -10,6 +11,8 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.ph87.homeautomation.shared.Helpers.mapIfNotNull;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional
|
||||
@ -27,12 +30,16 @@ public class DeviceReadService {
|
||||
private DeviceDto toDto(final Device device) {
|
||||
if (device instanceof DeviceSwitch) {
|
||||
final DeviceSwitch deviceSwitch = (DeviceSwitch) device;
|
||||
return new DeviceSwitchDto(deviceSwitch, propertyService.readBoolean(deviceSwitch.getStatePropertyName()));
|
||||
} else if (device instanceof DeviceNumber) {
|
||||
final DeviceNumber deviceNumber = (DeviceNumber) device;
|
||||
return new DeviceNumberDto(deviceNumber, propertyService.readNumber(deviceNumber.getValuePropertyName()));
|
||||
final PropertyDto getState = mapIfNotNull(deviceSwitch.getGetState(), propertyService::getById);
|
||||
final PropertyDto setState = mapIfNotNull(deviceSwitch.getSetState(), propertyService::getById);
|
||||
return new DeviceSwitchDto(deviceSwitch, getState, setState);
|
||||
} else if (device instanceof DeviceShutter) {
|
||||
final DeviceShutter deviceShutter = (DeviceShutter) device;
|
||||
final PropertyDto getPercent = mapIfNotNull(deviceShutter.getGetPercent(), propertyService::getById);
|
||||
final PropertyDto setPercent = mapIfNotNull(deviceShutter.getSetPercent(), propertyService::getById);
|
||||
return new DeviceShutterDto(deviceShutter, getPercent, setPercent);
|
||||
}
|
||||
throw new RuntimeException("Not imeplemented: toDto(" + device + ")");
|
||||
throw new RuntimeException("Not implemented: toDto(" + device + ")");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
package de.ph87.homeautomation.device;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DeviceSetDto {
|
||||
|
||||
private long id;
|
||||
|
||||
private String property;
|
||||
|
||||
private double value;
|
||||
|
||||
}
|
||||
@ -1,13 +1,18 @@
|
||||
package de.ph87.homeautomation.device;
|
||||
|
||||
import de.ph87.homeautomation.device.devices.DeviceNumber;
|
||||
import de.ph87.homeautomation.device.devices.Device;
|
||||
import de.ph87.homeautomation.device.devices.DeviceShutter;
|
||||
import de.ph87.homeautomation.device.devices.DeviceSwitch;
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import de.ph87.homeautomation.property.PropertyService;
|
||||
import de.ph87.homeautomation.property.PropertySetException;
|
||||
import de.ph87.office.web.NotFoundException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import static de.ph87.homeautomation.shared.Helpers.mapIfNotNull;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -17,17 +22,49 @@ public class DeviceWriteService {
|
||||
|
||||
private final DeviceRepository deviceRepository;
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
private final PropertyService propertyService;
|
||||
|
||||
public void createDeviceSwitch(final String title, final PropertyDto getState, final PropertyDto setState) {
|
||||
final DeviceSwitch deviceSwitch = new DeviceSwitch();
|
||||
deviceSwitch.setName("TEST");
|
||||
deviceSwitch.setStatePropertyName("knx.group.0.3.6");
|
||||
deviceSwitch.setTitle(title);
|
||||
deviceSwitch.setGetState(mapIfNotNull(getState, PropertyDto::getName));
|
||||
deviceSwitch.setSetState(mapIfNotNull(setState, PropertyDto::getName));
|
||||
deviceRepository.save(deviceSwitch);
|
||||
}
|
||||
|
||||
final DeviceNumber deviceNumber = new DeviceNumber();
|
||||
deviceNumber.setName("Helligkeit");
|
||||
deviceNumber.setValuePropertyName("knx.group.0.5.6");
|
||||
deviceRepository.save(deviceNumber);
|
||||
public void createDeviceShutter(final String title, final PropertyDto getPercent, final PropertyDto setPercent) {
|
||||
final DeviceShutter deviceShutter = new DeviceShutter();
|
||||
deviceShutter.setTitle(title);
|
||||
deviceShutter.setGetPercent(mapIfNotNull(getPercent, PropertyDto::getName));
|
||||
deviceShutter.setSetPercent(mapIfNotNull(setPercent, PropertyDto::getName));
|
||||
deviceRepository.save(deviceShutter);
|
||||
}
|
||||
|
||||
public void set(final DeviceSetDto dto) throws PropertySetException {
|
||||
final Device device = getById(dto.getId());
|
||||
if (device instanceof DeviceSwitch) {
|
||||
setSwitch((DeviceSwitch) device, dto.getProperty(), dto.getValue());
|
||||
} else if (device instanceof DeviceShutter) {
|
||||
setShutter((DeviceShutter) device, dto.getProperty(), dto.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void setSwitch(final DeviceSwitch device, final String property, final double value) throws PropertySetException {
|
||||
switch (property) {
|
||||
case "switch":
|
||||
propertyService.set(device.getSetState(), value);
|
||||
}
|
||||
}
|
||||
|
||||
private void setShutter(final DeviceShutter device, final String property, final double value) throws PropertySetException {
|
||||
switch (property) {
|
||||
case "percent":
|
||||
propertyService.set(device.getSetPercent(), value);
|
||||
}
|
||||
}
|
||||
|
||||
private Device getById(final long id) {
|
||||
return deviceRepository.findById(id).orElseThrow(() -> new NotFoundException("Device.id=%d", id));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -19,6 +19,6 @@ public abstract class Device {
|
||||
@Setter(AccessLevel.NONE)
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
private String title;
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package de.ph87.homeautomation.device;
|
||||
package de.ph87.homeautomation.device.devices;
|
||||
|
||||
import de.ph87.homeautomation.device.devices.Device;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ -8,13 +7,13 @@ public abstract class DeviceDto {
|
||||
|
||||
public final long id;
|
||||
|
||||
public final String name;
|
||||
public final String title;
|
||||
|
||||
public final String type;
|
||||
|
||||
public DeviceDto(final Device device) {
|
||||
this.id = device.getId();
|
||||
this.name = device.getName();
|
||||
this.title = device.getTitle();
|
||||
this.type = device.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
package de.ph87.homeautomation.device.devices;
|
||||
|
||||
import de.ph87.homeautomation.device.DeviceDto;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class DeviceNumberDto extends DeviceDto {
|
||||
|
||||
public final Number value;
|
||||
|
||||
public DeviceNumberDto(final DeviceNumber device, final Number value) {
|
||||
super(device);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
||||
@ -10,8 +10,10 @@ import javax.persistence.Entity;
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
public class DeviceNumber extends Device {
|
||||
public class DeviceShutter extends Device {
|
||||
|
||||
private String valuePropertyName;
|
||||
private String getPercent;
|
||||
|
||||
private String setPercent;
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package de.ph87.homeautomation.device.devices;
|
||||
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class DeviceShutterDto extends DeviceDto {
|
||||
|
||||
public final PropertyDto getPercent;
|
||||
|
||||
public final PropertyDto setPercent;
|
||||
|
||||
public DeviceShutterDto(final DeviceShutter device, final PropertyDto getPercent, final PropertyDto setPercent) {
|
||||
super(device);
|
||||
this.getPercent = getPercent;
|
||||
this.setPercent = setPercent;
|
||||
}
|
||||
|
||||
}
|
||||
@ -12,8 +12,8 @@ import javax.persistence.Entity;
|
||||
@Entity
|
||||
public class DeviceSwitch extends Device {
|
||||
|
||||
private String switchPropertyName;
|
||||
private String setState;
|
||||
|
||||
private String statePropertyName;
|
||||
private String getState;
|
||||
|
||||
}
|
||||
|
||||
@ -1,16 +1,19 @@
|
||||
package de.ph87.homeautomation.device.devices;
|
||||
|
||||
import de.ph87.homeautomation.device.DeviceDto;
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class DeviceSwitchDto extends DeviceDto {
|
||||
|
||||
public final Boolean state;
|
||||
public final PropertyDto getState;
|
||||
|
||||
public DeviceSwitchDto(final DeviceSwitch device, final Boolean state) {
|
||||
public final PropertyDto setState;
|
||||
|
||||
public DeviceSwitchDto(final DeviceSwitch device, final PropertyDto getState, final PropertyDto setState) {
|
||||
super(device);
|
||||
this.state = state;
|
||||
this.getState = getState;
|
||||
this.setState = setState;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -7,7 +7,6 @@ import de.ph87.homeautomation.shared.AbstractThreadService;
|
||||
import de.ph87.network.router.Router;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
import tuwien.auto.calimero.CloseEvent;
|
||||
@ -153,9 +152,8 @@ public class KnxThreadService extends AbstractThreadService implements NetworkLi
|
||||
// ignore
|
||||
}
|
||||
|
||||
@EventListener(KnxThreadWakeUpEvent.class)
|
||||
@TransactionalEventListener
|
||||
public void wakeUp() {
|
||||
public void wakeUp(final KnxThreadWakeUpEvent event) {
|
||||
_wakeUp();
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import de.ph87.homeautomation.property.IProperty;
|
||||
import de.ph87.homeautomation.property.PropertyType;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
@ -14,7 +15,7 @@ import java.time.ZonedDateTime;
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
public class KnxGroup {
|
||||
public class KnxGroup implements IProperty {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import de.ph87.homeautomation.property.PropertyType;
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@Getter
|
||||
public class KnxGroupDto {
|
||||
public class KnxGroupDto extends PropertyDto {
|
||||
|
||||
public final long id;
|
||||
|
||||
@ -14,32 +12,14 @@ public class KnxGroupDto {
|
||||
|
||||
public final String addressStr;
|
||||
|
||||
public final String propertyName;
|
||||
|
||||
public final String dpt;
|
||||
|
||||
public final String name;
|
||||
|
||||
public final PropertyType propertyType;
|
||||
|
||||
public final Boolean booleanValue;
|
||||
|
||||
public final Double numberValue;
|
||||
|
||||
public final ZonedDateTime valueTimestamp;
|
||||
|
||||
public KnxGroupDto(final KnxGroup knxGroup) {
|
||||
super(knxGroup.getPropertyName(), knxGroup.getTitle(), knxGroup.getPropertyType(), knxGroup.getBooleanValue(), knxGroup.getNumberValue(), knxGroup.getValueTimestamp());
|
||||
id = knxGroup.getId();
|
||||
addressRaw = knxGroup.getAddressRaw();
|
||||
addressStr = knxGroup.getAddressStr();
|
||||
propertyName = knxGroup.getPropertyName();
|
||||
dpt = knxGroup.getDpt();
|
||||
name = knxGroup.getTitle();
|
||||
propertyType = knxGroup.getPropertyType();
|
||||
|
||||
booleanValue = knxGroup.getBooleanValue();
|
||||
numberValue = knxGroup.getNumberValue();
|
||||
valueTimestamp = knxGroup.getValueTimestamp();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import de.ph87.homeautomation.knx.KnxThreadService;
|
||||
import de.ph87.homeautomation.property.IPropertyOwner;
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import de.ph87.homeautomation.property.PropertySetException;
|
||||
@ -11,6 +10,7 @@ import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import tuwien.auto.calimero.GroupAddress;
|
||||
|
||||
import java.util.List;
|
||||
@ -23,14 +23,13 @@ import static de.ph87.homeautomation.shared.Helpers.quoteOrNull;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
public class KnxGroupSetService implements IPropertyOwner {
|
||||
|
||||
@Getter
|
||||
private final Pattern propertyNamePattern = Pattern.compile("^knx\\.group\\.(\\d+)\\.(\\d+)\\.(\\d+)$");
|
||||
|
||||
private final KnxThreadService knxThreadService;
|
||||
|
||||
private final KnxGroupWriteService knxGroupWriteService;
|
||||
|
||||
private final KnxGroupRepository knxGroupRepository;
|
||||
@ -68,28 +67,18 @@ public class KnxGroupSetService implements IPropertyOwner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<PropertyDto> findPropertyByName(final String propertyName) {
|
||||
return knxGroupRepository.findByPropertyName(propertyName).map(this::toPropertyDto);
|
||||
public Optional<KnxGroupDto> findPropertyByName(final String propertyName) {
|
||||
return knxGroupRepository.findByPropertyName(propertyName).map(KnxGroupDto::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyDto> findAllProperties() {
|
||||
return knxGroupRepository.findAll().stream().map(this::toPropertyDto).collect(Collectors.toList());
|
||||
return knxGroupRepository.findAll().stream().map(KnxGroupDto::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyDto> findAllPropertiesLike(final String like) {
|
||||
return knxGroupRepository.findAllByPropertyNameLikeIgnoreCaseOrTitleLikeIgnoreCase(like, like).stream().map(this::toPropertyDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private PropertyDto toPropertyDto(final KnxGroup knxGroup) {
|
||||
return new PropertyDto(
|
||||
knxGroup.getPropertyName(),
|
||||
knxGroup.getTitle(),
|
||||
knxGroup.getBooleanValue(),
|
||||
knxGroup.getNumberValue(),
|
||||
knxGroup.getValueTimestamp()
|
||||
);
|
||||
return knxGroupRepository.findAllByPropertyNameLikeIgnoreCaseOrTitleLikeIgnoreCase(like, like).stream().map(KnxGroupDto::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private GroupAddress parseGroupAddress(final String propertyName) {
|
||||
|
||||
@ -125,7 +125,6 @@ public class KnxGroupWriteService {
|
||||
return false;
|
||||
}
|
||||
final KnxGroup knxGroup = knxGroupOptional.get();
|
||||
|
||||
try {
|
||||
final DPTXlator translator = findTranslator(knxGroup);
|
||||
if (translator instanceof DPTXlatorBoolean) {
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
package de.ph87.homeautomation.property;
|
||||
|
||||
public interface IProperty {
|
||||
|
||||
String getPropertyName();
|
||||
|
||||
}
|
||||
@ -18,6 +18,6 @@ public interface IPropertyOwner {
|
||||
|
||||
List<PropertyDto> findAllPropertiesLike(final String like);
|
||||
|
||||
Optional<PropertyDto> findPropertyByName(final String propertyName);
|
||||
Optional<? extends PropertyDto> findPropertyByName(final String propertyName);
|
||||
|
||||
}
|
||||
|
||||
@ -31,4 +31,9 @@ public class PropertyController implements ISearchController {
|
||||
return propertyService.findAllLike("%" + term + "%").stream().map(propertyDto -> new KeyValuePair(propertyDto.name, propertyDto.title)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@PostMapping("set")
|
||||
public void set(@RequestBody final PropertySetDto dto) throws PropertySetException {
|
||||
propertyService.set(dto.getName(), dto.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -11,15 +11,18 @@ public class PropertyDto {
|
||||
|
||||
public final String title;
|
||||
|
||||
public final PropertyType propertyType;
|
||||
|
||||
public final Boolean booleanValue;
|
||||
|
||||
public final Number numberValue;
|
||||
|
||||
public final ZonedDateTime timestamp;
|
||||
|
||||
public PropertyDto(final String name, final String title, final Boolean booleanValue, final Number numberValue, final ZonedDateTime timestamp) {
|
||||
public PropertyDto(final String name, final String title, final PropertyType propertyType, final Boolean booleanValue, final Number numberValue, final ZonedDateTime timestamp) {
|
||||
this.name = name;
|
||||
this.title = title;
|
||||
this.propertyType = propertyType;
|
||||
this.booleanValue = booleanValue;
|
||||
this.numberValue = numberValue;
|
||||
this.timestamp = timestamp;
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
package de.ph87.homeautomation.property;
|
||||
|
||||
import de.ph87.homeautomation.shared.Helpers;
|
||||
import de.ph87.office.web.NotFoundException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -34,17 +37,17 @@ public class PropertyService {
|
||||
}
|
||||
|
||||
public List<PropertyDto> findAll() {
|
||||
return propertyOwners.stream().map(IPropertyOwner::findAllProperties).reduce(new ArrayList<>(), Helpers::merge);
|
||||
return mergeDtoLists(propertyOwners.stream().map(IPropertyOwner::findAllProperties));
|
||||
}
|
||||
|
||||
public List<PropertyDto> findAllLike(final String like) {
|
||||
return propertyOwners.stream().map(iProperyOwner -> iProperyOwner.findAllPropertiesLike(like)).reduce(PropertyService::merge).orElse(Collections.emptyList());
|
||||
return mergeDtoLists(propertyOwners.stream().map(iProperyOwner -> iProperyOwner.findAllPropertiesLike(like)));
|
||||
}
|
||||
|
||||
private static <T> List<T> merge(final List<T> a, final List<T> b) {
|
||||
final ArrayList<T> c = new ArrayList<>(a);
|
||||
c.addAll(b);
|
||||
return c;
|
||||
private List<PropertyDto> mergeDtoLists(final Stream<? extends List<? extends PropertyDto>> stream) {
|
||||
final List<PropertyDto> result = new ArrayList<>();
|
||||
stream.forEach(result::addAll);
|
||||
return result;
|
||||
}
|
||||
|
||||
public PropertyDto getById(final String propertyName) {
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
package de.ph87.homeautomation.property;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PropertySetDto {
|
||||
|
||||
private String name;
|
||||
|
||||
private double value;
|
||||
|
||||
}
|
||||
@ -2,9 +2,17 @@ package de.ph87.homeautomation.shared;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class Helpers {
|
||||
|
||||
public static <T, U> U mapIfNotNull(final T value, final Function<T, U> map) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return map.apply(value);
|
||||
}
|
||||
|
||||
public static String quoteOrNull(final String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
@ -33,7 +41,7 @@ public class Helpers {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> List<T> merge(final List<T> a, final List<T> b) {
|
||||
public static <T> List<T> merge(final List<? extends T> a, final List<? extends T> b) {
|
||||
final List<T> c = new ArrayList<>(a);
|
||||
c.addAll(b);
|
||||
return c;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user