UI device editing
This commit is contained in:
parent
4939d9398f
commit
927e8df13a
@ -1,5 +1,4 @@
|
||||
import {validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators";
|
||||
import {Property} from "../property/property.service";
|
||||
import {validateBooleanAllowNull, validateNumberAllowNull, validateNumberNotNull, validateStringNotEmptyNotNull, validateStringNullToEmpty} from "../validators";
|
||||
|
||||
export abstract class Device {
|
||||
|
||||
@ -19,16 +18,18 @@ export abstract class Device {
|
||||
validateNumberNotNull(json['id']),
|
||||
validateStringNotEmptyNotNull(json['title']),
|
||||
type,
|
||||
Property.fromJsonAllowNull(json['getState']),
|
||||
Property.fromJsonAllowNull(json['setState']),
|
||||
validateStringNullToEmpty(json['getState']),
|
||||
validateStringNullToEmpty(json['setState']),
|
||||
validateBooleanAllowNull(json['state']),
|
||||
);
|
||||
case "DeviceShutter":
|
||||
return new DeviceShutter(
|
||||
validateNumberNotNull(json['id']),
|
||||
validateStringNotEmptyNotNull(json['title']),
|
||||
type,
|
||||
Property.fromJsonAllowNull(json['getPercent']),
|
||||
Property.fromJsonAllowNull(json['setPercent']),
|
||||
validateStringNullToEmpty(json['getPercent']),
|
||||
validateStringNullToEmpty(json['setPercent']),
|
||||
validateNumberAllowNull(json['percent']),
|
||||
);
|
||||
}
|
||||
throw new Error("No such type: " + type);
|
||||
@ -50,8 +51,9 @@ export class DeviceSwitch extends Device {
|
||||
id: number,
|
||||
title: string,
|
||||
type: string,
|
||||
readonly getState: Property | null,
|
||||
readonly setState: Property | null,
|
||||
public getState: string,
|
||||
public setState: string,
|
||||
public state: boolean | null,
|
||||
) {
|
||||
super(id, title, type);
|
||||
}
|
||||
@ -64,8 +66,9 @@ export class DeviceShutter extends Device {
|
||||
id: number,
|
||||
title: string,
|
||||
type: string,
|
||||
readonly getPercent: Property | null,
|
||||
readonly setPercent: Property | null,
|
||||
public getPercent: string,
|
||||
public setPercent: string,
|
||||
public percent: number | null,
|
||||
) {
|
||||
super(id, title, type);
|
||||
}
|
||||
|
||||
@ -17,4 +17,28 @@ export class DeviceService {
|
||||
this.api.getList("device/findAll", Device.fromJson, compare, next, error);
|
||||
}
|
||||
|
||||
set(device: Device, key: string, value: any, next: (item: Device) => void, error: (error: any) => void = NO_OP): void {
|
||||
this.api.postReturnItem("device/set/" + device.id + "/" + key, value, Device.fromJson, next, error);
|
||||
}
|
||||
|
||||
setDeviceSwitch(device: Device, key: string, value: any, next: (item: Device) => void, error: (error: any) => void = NO_OP): void {
|
||||
this.api.postReturnItem("device/set/" + device.id + "/DeviceSwitch/" + key, value, Device.fromJson, next, error);
|
||||
}
|
||||
|
||||
setDeviceShutter(device: Device, key: string, value: any, next: (item: Device) => void, error: (error: any) => void = NO_OP): void {
|
||||
this.api.postReturnItem("device/set/" + device.id + "/DeviceShutter/" + key, value, Device.fromJson, next, error);
|
||||
}
|
||||
|
||||
getById(id: number, next: (item: Device) => void, error: (error: any) => void = NO_OP): void {
|
||||
this.api.getItem("device/getById/" + id, Device.fromJson, next, error);
|
||||
}
|
||||
|
||||
create(type: string, next: (item: Device) => void, error: (error: any) => void = NO_OP): void {
|
||||
this.api.postReturnItem("device/create/", type, Device.fromJson, next, error);
|
||||
}
|
||||
|
||||
delete(device: Device, next: () => void, error: (error: any) => void = NO_OP): void {
|
||||
this.api.getItem("device/delete/" + device.id, _ => _, next, error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ export class Schedule {
|
||||
constructor(
|
||||
public id: number,
|
||||
public enabled: boolean,
|
||||
public name: string,
|
||||
public title: string,
|
||||
public propertyName: string,
|
||||
public propertyType: string,
|
||||
public entries: ScheduleEntry[],
|
||||
@ -18,7 +18,7 @@ export class Schedule {
|
||||
return new Schedule(
|
||||
validateNumberNotNull(json['id']),
|
||||
validateBooleanNotNull(json['enabled']),
|
||||
validateStringNotEmptyNotNull(json['name']),
|
||||
validateStringNotEmptyNotNull(json['title']),
|
||||
validateStringNullToEmpty(json['propertyName']),
|
||||
validateStringNullToEmpty(json['propertyType']),
|
||||
validateListOrEmpty(json['entries'], ScheduleEntry.fromJson, ScheduleEntry.compare),
|
||||
@ -34,7 +34,7 @@ export class Schedule {
|
||||
}
|
||||
|
||||
public static compareName(a: Schedule, b: Schedule): number {
|
||||
return a.name.localeCompare(b.name);
|
||||
return a.title.localeCompare(b.title);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -21,8 +21,8 @@ export class ScheduleService {
|
||||
this.api.postReturnItem("schedule/set/" + schedule.id + "/" + key, value, Schedule.fromJson, next, error);
|
||||
}
|
||||
|
||||
findById(id: number, next: (item: Schedule) => void, error: (error: any) => void = NO_OP): void {
|
||||
this.api.getItem("schedule/findById/" + id, Schedule.fromJson, next, error);
|
||||
getById(id: number, next: (item: Schedule) => void, error: (error: any) => void = NO_OP): void {
|
||||
this.api.getItem("schedule/getById/" + id, Schedule.fromJson, next, error);
|
||||
}
|
||||
|
||||
create(next: (item: Schedule) => void, error: (error: any) => void = NO_OP): void {
|
||||
|
||||
@ -3,8 +3,10 @@ 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";
|
||||
import {DeviceComponent} from "./pages/device/device.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{path: 'Device', component: DeviceComponent},
|
||||
{path: 'DeviceList', component: DeviceListComponent},
|
||||
{path: 'Schedule', component: ScheduleComponent},
|
||||
{path: 'ScheduleList', component: ScheduleListComponent},
|
||||
|
||||
@ -12,6 +12,7 @@ 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';
|
||||
import {DeviceComponent} from './pages/device/device.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -22,6 +23,7 @@ import {DeviceListComponent} from './pages/device-list/device-list.component';
|
||||
NumberComponent,
|
||||
SearchComponent,
|
||||
DeviceListComponent,
|
||||
DeviceComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Schedule} from "./api/schedule/Schedule";
|
||||
import {Device} from "./api/device/Device";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -16,6 +17,16 @@ export class DataService {
|
||||
this._schedule = schedule;
|
||||
}
|
||||
|
||||
private _device?: Device;
|
||||
|
||||
get device(): Device | undefined {
|
||||
return this._device;
|
||||
}
|
||||
|
||||
set device(device: Device | undefined) {
|
||||
this._device = device;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,24 @@
|
||||
<ng-container *ngFor="let device of devices">
|
||||
<ng-container *ngFor="let device of devices.sort(Device.compareTitle); trackBy: Device.trackBy">
|
||||
<ng-container [ngSwitch]="device.type">
|
||||
<div class="device" *ngSwitchCase="'DeviceSwitch'" [class.switchOn]="isSwitchStateOn(device)" [class.switchOff]="isSwitchStateOff(device)" [class.switchUnknown]="isSwitchStateUnknown(device)">
|
||||
<div class="device" *ngSwitchCase="'DeviceSwitch'" [ngClass]="getSwitchClassList(device)">
|
||||
<div class="title">
|
||||
{{device.title}}
|
||||
</div>
|
||||
<div class="edit" [routerLink]="['/Device', {id: device.id}]">
|
||||
Bearbeiten
|
||||
</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)"/>
|
||||
<img alt="An" class="control" src="assets/switch-on.svg" (click)="setSwitchState(device, true)"/>
|
||||
<img alt="Aus" 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="device" *ngSwitchCase="'DeviceShutter'" [ngClass]="getShutterClassList(device)">
|
||||
<div class="title">
|
||||
{{device.title}}
|
||||
</div>
|
||||
<div class="edit" [routerLink]="['/Device', {id: device.id}]">
|
||||
Bearbeiten
|
||||
</div>
|
||||
<div class="controls">
|
||||
<div class="control button" (click)="setShutterPercent(device, 0)">
|
||||
<span class="center">Auf</span>
|
||||
@ -33,3 +39,11 @@
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<p>
|
||||
<select [(ngModel)]="createType">
|
||||
<option ngValue="DeviceSwitch">Schalter</option>
|
||||
<option ngValue="DeviceShutter">Rollladen</option>
|
||||
</select>
|
||||
<button (click)="create()">+ Hinzufügen</button>
|
||||
</p>
|
||||
|
||||
@ -4,10 +4,17 @@
|
||||
border-radius: 10px;
|
||||
|
||||
.title {
|
||||
float: left;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.edit {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.controls {
|
||||
clear: both;
|
||||
|
||||
.control {
|
||||
position: relative;
|
||||
float: left;
|
||||
@ -49,7 +56,7 @@
|
||||
background-color: gray;
|
||||
}
|
||||
|
||||
.blindOpen {
|
||||
.shutterOpen {
|
||||
background-color: palegreen;
|
||||
}
|
||||
|
||||
|
||||
@ -10,8 +10,12 @@ import {Device, DeviceShutter, DeviceSwitch} from "../../api/device/Device";
|
||||
})
|
||||
export class DeviceListComponent implements OnInit {
|
||||
|
||||
readonly Device = Device;
|
||||
|
||||
devices: Device[] = [];
|
||||
|
||||
createType: string = "DeviceSwitch";
|
||||
|
||||
constructor(
|
||||
readonly deviceService: DeviceService,
|
||||
readonly propertyService: PropertyService,
|
||||
@ -36,7 +40,7 @@ export class DeviceListComponent implements OnInit {
|
||||
if (!device.setState) {
|
||||
throw new Error("Property 'setState' not set for: " + device);
|
||||
}
|
||||
this.propertyService.set(device.setState.name, value ? 1 : 0);
|
||||
this.propertyService.set(device.setState, value ? 1 : 0);
|
||||
}
|
||||
|
||||
setShutterPercent(d: Device, value: number): void {
|
||||
@ -44,38 +48,30 @@ export class DeviceListComponent implements OnInit {
|
||||
if (!device.setPercent) {
|
||||
throw new Error("Property 'setPercent' not set for: " + device);
|
||||
}
|
||||
this.propertyService.set(device.setPercent.name, value);
|
||||
this.propertyService.set(device.setPercent, value);
|
||||
}
|
||||
|
||||
isSwitchStateOn(device: Device): boolean {
|
||||
return (device as DeviceSwitch).getState?.booleanValue === true;
|
||||
create(): void {
|
||||
this.deviceService.create(this.createType, device => this.devices.push(device));
|
||||
}
|
||||
|
||||
isSwitchStateOff(device: Device): boolean {
|
||||
return (device as DeviceSwitch).getState?.booleanValue === false;
|
||||
getSwitchClassList(device: Device): object {
|
||||
const value: boolean | null | undefined = (device as DeviceSwitch).state;
|
||||
return {
|
||||
switchOn: value === true,
|
||||
switchOff: value === false,
|
||||
switchUnknown: value === null || value === undefined,
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
getShutterClassList(device: Device): object {
|
||||
const value: number | null | undefined = (device as DeviceShutter).percent;
|
||||
return {
|
||||
shutterOpen: value === 0,
|
||||
shutterBetween: value !== null && value !== undefined && value > 0 && value < 100,
|
||||
shutterClosed: value === 100,
|
||||
shutterUnknown: value === null || value === undefined,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
53
src/main/angular/src/app/pages/device/device.component.html
Normal file
53
src/main/angular/src/app/pages/device/device.component.html
Normal file
@ -0,0 +1,53 @@
|
||||
<ng-container *ngIf="device">
|
||||
<h1>{{device.title}}</h1>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="deviceSwitch">
|
||||
<table class="vertical">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<td>
|
||||
<app-edit-field [initial]="deviceSwitch.title" (valueChange)="set('title', $event)"></app-edit-field>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Zustand Lesen</th>
|
||||
<td>
|
||||
<app-search [searchService]="propertyService" [initial]="deviceSwitch.getState" [showKey]="true" (valueChange)="setDeviceSwitch('getState', $event)"></app-search>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Zustand Schreiben</th>
|
||||
<td>
|
||||
<app-search [searchService]="propertyService" [initial]="deviceSwitch.setState" [showKey]="true" (valueChange)="setDeviceSwitch('setState', $event)"></app-search>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="deviceShutter">
|
||||
<table class="vertical">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<td>
|
||||
<app-edit-field [initial]="deviceShutter.title" (valueChange)="set('title', $event)"></app-edit-field>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Position Lesen</th>
|
||||
<td>
|
||||
<app-search [searchService]="propertyService" [initial]="deviceShutter.getPercent" [showKey]="true" (valueChange)="setDeviceShutter('getPercent', $event)"></app-search>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Position Schreiben</th>
|
||||
<td>
|
||||
<app-search [searchService]="propertyService" [initial]="deviceShutter.setPercent" [showKey]="true" (valueChange)="setDeviceShutter('setPercent', $event)"></app-search>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</ng-container>
|
||||
|
||||
<p>
|
||||
<button (click)="delete()">Löschen</button>
|
||||
</p>
|
||||
@ -0,0 +1,25 @@
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
import {DeviceComponent} from './device.component';
|
||||
|
||||
describe('DeviceComponent', () => {
|
||||
let component: DeviceComponent;
|
||||
let fixture: ComponentFixture<DeviceComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [DeviceComponent]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DeviceComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
77
src/main/angular/src/app/pages/device/device.component.ts
Normal file
77
src/main/angular/src/app/pages/device/device.component.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {ActivatedRoute, Router} from "@angular/router";
|
||||
import {DataService} from "../../data.service";
|
||||
import {PropertyService} from "../../api/property/property.service";
|
||||
import {Device, DeviceShutter, DeviceSwitch} from "../../api/device/Device";
|
||||
import {DeviceService} from "../../api/device/device.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-device',
|
||||
templateUrl: './device.component.html',
|
||||
styleUrls: ['./device.component.less']
|
||||
})
|
||||
export class DeviceComponent implements OnInit {
|
||||
|
||||
device!: Device;
|
||||
|
||||
deviceSwitch: DeviceSwitch | undefined;
|
||||
|
||||
deviceShutter: DeviceShutter | undefined;
|
||||
|
||||
constructor(
|
||||
readonly router: Router,
|
||||
readonly activatedRoute: ActivatedRoute,
|
||||
readonly deviceService: DeviceService,
|
||||
readonly dataService: DataService,
|
||||
readonly propertyService: PropertyService,
|
||||
) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.dataService.device = undefined;
|
||||
this.activatedRoute.params.subscribe(params => this.deviceService.getById(params.id, device => this.setDevice(device)));
|
||||
}
|
||||
|
||||
private setDevice(device: Device): void {
|
||||
this.device = device;
|
||||
switch (device.type) {
|
||||
case "DeviceSwitch":
|
||||
this.deviceSwitch = device as DeviceSwitch;
|
||||
break;
|
||||
case "DeviceShutter":
|
||||
this.deviceShutter = device as DeviceShutter;
|
||||
break;
|
||||
}
|
||||
this.dataService.device = device;
|
||||
}
|
||||
|
||||
set(key: string, value: any): void {
|
||||
this.deviceService.set(this.device, key, value, device => this.setDevice(device));
|
||||
}
|
||||
|
||||
setDeviceSwitch(key: string, value: any): void {
|
||||
this.deviceService.setDeviceSwitch(this.device, key, value, device => this.setDevice(device));
|
||||
}
|
||||
|
||||
setDeviceShutter(key: string, value: any): void {
|
||||
this.deviceService.setDeviceShutter(this.device, key, value, device => this.setDevice(device));
|
||||
}
|
||||
|
||||
delete(): void {
|
||||
if (confirm(this.getDeviceTypeTitle() + " \"" + this.device.title + "\" wirklich löschen?")) {
|
||||
this.deviceService.delete(this.device, () => this.router.navigate(["/DeviceList"]));
|
||||
}
|
||||
}
|
||||
|
||||
private getDeviceTypeTitle(): string {
|
||||
switch (this.device.type) {
|
||||
case "DeviceSwitch":
|
||||
return "Schalter";
|
||||
case "DeviceShutter":
|
||||
return "Rollladen";
|
||||
default:
|
||||
return "[TYP ???]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@
|
||||
</td>
|
||||
|
||||
<td [routerLink]="['/Schedule', {id: schedule.id}]">
|
||||
{{schedule.name}}
|
||||
{{schedule.title}}
|
||||
</td>
|
||||
|
||||
<td class="delete" (click)="delete(schedule)">
|
||||
|
||||
@ -50,7 +50,7 @@ export class ScheduleListComponent implements OnInit {
|
||||
}
|
||||
|
||||
delete(schedule: Schedule): void {
|
||||
if (confirm("Zeitplan \"" + schedule.name + "\" wirklich löschen?")) {
|
||||
if (confirm("Zeitplan \"" + schedule.title + "\" wirklich löschen?")) {
|
||||
this.scheduleService.delete(schedule, () => this.remove(schedule));
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
<tr class="header">
|
||||
<ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, value: schedule.enabled, key:'enabled'}"></ng-container>
|
||||
<td colspan="8">
|
||||
<app-edit-field [initial]="schedule.name" (valueChange)="set(null, 'name', $event)"></app-edit-field>
|
||||
<app-edit-field [initial]="schedule.title" (valueChange)="set(null, 'title', $event)"></app-edit-field>
|
||||
</td>
|
||||
<td colspan="5">
|
||||
<app-search [searchService]="propertyService" [initial]="schedule.propertyName" (valueChange)="set(null, 'propertyName', $event)"></app-search>
|
||||
|
||||
@ -34,7 +34,7 @@ export class ScheduleComponent implements OnInit {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.dataService.schedule = undefined;
|
||||
this.activatedRoute.params.subscribe(params => this.scheduleService.findById(params.id, schedule => this.setSchedule(schedule)));
|
||||
this.activatedRoute.params.subscribe(params => this.scheduleService.getById(params.id, schedule => this.setSchedule(schedule)));
|
||||
}
|
||||
|
||||
private setSchedule(schedule: Schedule): void {
|
||||
|
||||
@ -1,9 +1,20 @@
|
||||
<div
|
||||
*ngIf="!searching"
|
||||
(click)="startSearch()"
|
||||
(click)="start()"
|
||||
[class.empty]="!selected"
|
||||
>
|
||||
{{selected?.value ? selected?.value : "-LEER-"}}
|
||||
|
||||
<ng-container *ngIf="selected">
|
||||
{{selected.value}}
|
||||
<ng-container *ngIf="showKey">
|
||||
[{{selected.key}}]
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!selected">
|
||||
-LEER-
|
||||
</ng-container>
|
||||
|
||||
</div>
|
||||
|
||||
<input
|
||||
@ -13,8 +24,23 @@
|
||||
[(ngModel)]="term"
|
||||
(ngModelChange)="changed()"
|
||||
(keydown)="inputKeyPress($event)"
|
||||
(blur)="blur()"
|
||||
>
|
||||
|
||||
<div #resultList *ngIf="searching" class="resultList">
|
||||
<div *ngFor="let result of results" class="result" (click)="select(result)">{{result.value}}</div>
|
||||
<div *ngIf="allowEmpty" class="result" (click)="select(undefined)">
|
||||
-
|
||||
</div>
|
||||
<div *ngIf="selected" class="result selected" (click)="select(undefined)">
|
||||
{{selected.value}}
|
||||
<ng-container *ngIf="showKey">
|
||||
[{{selected.key}}]
|
||||
</ng-container>
|
||||
</div>
|
||||
<div *ngFor="let result of results" class="result" (click)="select(result)">
|
||||
{{result.value}}
|
||||
<ng-container *ngIf="showKey">
|
||||
[{{result.key}}]
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,3 +1,12 @@
|
||||
.empty {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
.selected {
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
|
||||
.resultList {
|
||||
position: absolute;
|
||||
background-color: lightgray;
|
||||
|
||||
@ -26,8 +26,14 @@ export class SearchComponent<T> implements OnInit {
|
||||
@Input()
|
||||
initial!: string;
|
||||
|
||||
@Input()
|
||||
showKey: boolean = false;
|
||||
|
||||
@Input()
|
||||
allowEmpty: boolean = true;
|
||||
|
||||
@Output()
|
||||
valueChange: EventEmitter<string> = new EventEmitter<string>();
|
||||
valueChange: EventEmitter<string | null> = new EventEmitter<string | null>();
|
||||
|
||||
term: string = "";
|
||||
|
||||
@ -41,7 +47,9 @@ export class SearchComponent<T> implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.searchService.get(this.initial, result => this.selected = result, _ => _);
|
||||
if (this.initial) {
|
||||
this.searchService.get(this.initial, result => this.selected = result, _ => _);
|
||||
}
|
||||
}
|
||||
|
||||
changed(): void {
|
||||
@ -56,7 +64,7 @@ export class SearchComponent<T> implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
startSearch(): void {
|
||||
start(): void {
|
||||
this.term = this.initial;
|
||||
if (this.resultList && this.input) {
|
||||
this.resultList.style.left = this.input.style.left;
|
||||
@ -72,7 +80,7 @@ export class SearchComponent<T> implements OnInit {
|
||||
this.doSearch();
|
||||
break;
|
||||
case 'Escape':
|
||||
this.cancelSearch();
|
||||
this.cancel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -86,11 +94,15 @@ export class SearchComponent<T> implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
cancelSearch(): void {
|
||||
setTimeout(() => this.searching = false, 10);
|
||||
blur() {
|
||||
setTimeout(() => this.cancel(), 100);
|
||||
}
|
||||
|
||||
select(result: KeyValuePair): void {
|
||||
cancel(): void {
|
||||
this.searching = false;
|
||||
}
|
||||
|
||||
select(result: KeyValuePair | undefined): void {
|
||||
this.searching = false;
|
||||
this.selected = result;
|
||||
this.valueChange.emit(this.selected?.key);
|
||||
|
||||
@ -2,6 +2,7 @@ package de.ph87.homeautomation;
|
||||
|
||||
import com.luckycatlabs.sunrisesunset.Zenith;
|
||||
import de.ph87.homeautomation.device.DeviceWriteService;
|
||||
import de.ph87.homeautomation.device.devices.DeviceDto;
|
||||
import de.ph87.homeautomation.knx.group.KnxGroupDto;
|
||||
import de.ph87.homeautomation.knx.group.KnxGroupRepository;
|
||||
import de.ph87.homeautomation.knx.group.KnxGroupWriteService;
|
||||
@ -19,6 +20,8 @@ import tuwien.auto.calimero.GroupAddress;
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
import static de.ph87.homeautomation.shared.Helpers.mapIfNotNull;
|
||||
|
||||
@SuppressWarnings({"unchecked", "UnusedReturnValue", "SameParameterValue", "UnusedAssignment", "RedundantSuppression"})
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -49,8 +52,8 @@ public class DemoDataService {
|
||||
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);
|
||||
createDeviceSwitch("Bad Licht Mitte", bad_licht_mitte_status, bad_licht_mitte_schalten);
|
||||
createDeviceShutter("Flur OG Rollladen", null, flur_rollladen_position_anfahren);
|
||||
|
||||
if (scheduleRepository.count() == 0) {
|
||||
final Schedule scheduleEgFlurLicht = createSchedule("EG Flur Licht", eg_flur_licht_schalten);
|
||||
@ -106,10 +109,18 @@ public class DemoDataService {
|
||||
}
|
||||
}
|
||||
|
||||
private DeviceDto createDeviceSwitch(final String title, final PropertyDto getPercent, final PropertyDto setPercent) {
|
||||
return deviceWriteService.createDeviceSwitch(title, mapIfNotNull(getPercent, PropertyDto::getName), mapIfNotNull(setPercent, PropertyDto::getName));
|
||||
}
|
||||
|
||||
private DeviceDto createDeviceShutter(final String title, final PropertyDto getPercent, final PropertyDto setPercent) {
|
||||
return deviceWriteService.createDeviceShutter(title, mapIfNotNull(getPercent, PropertyDto::getName), mapIfNotNull(setPercent, PropertyDto::getName));
|
||||
}
|
||||
|
||||
private Schedule createSchedule(final String s, final PropertyDto propertyDto) {
|
||||
final Schedule schedule = new Schedule();
|
||||
schedule.setEnabled(true);
|
||||
schedule.setName(s);
|
||||
schedule.setTitle(s);
|
||||
schedule.setPropertyName(propertyDto.getName());
|
||||
schedule.setPropertyType(propertyDto.getPropertyType());
|
||||
return schedule;
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
package de.ph87.homeautomation.device;
|
||||
|
||||
import de.ph87.homeautomation.device.devices.Device;
|
||||
import de.ph87.homeautomation.device.devices.DeviceDto;
|
||||
import de.ph87.homeautomation.property.PropertySetException;
|
||||
import de.ph87.homeautomation.device.devices.DeviceShutter;
|
||||
import de.ph87.homeautomation.device.devices.DeviceSwitch;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@ -21,9 +23,49 @@ public class DeviceController {
|
||||
return deviceReadService.findAll();
|
||||
}
|
||||
|
||||
@PostMapping("set")
|
||||
public void set(@RequestBody final DeviceSetDto dto) throws PropertySetException {
|
||||
deviceWriteService.set(dto);
|
||||
@GetMapping("getById/{id}")
|
||||
public DeviceDto getById(@PathVariable final long id) {
|
||||
return deviceReadService.getDtoById(id);
|
||||
}
|
||||
|
||||
@PostMapping("create")
|
||||
public DeviceDto create(@RequestBody final String typeString) {
|
||||
return deviceWriteService.create(typeString);
|
||||
}
|
||||
|
||||
@GetMapping("delete/{id}")
|
||||
public void delete(@PathVariable final long id) {
|
||||
deviceWriteService.delete(id);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/enabled")
|
||||
public DeviceDto setEnabled(@PathVariable final long id, @RequestBody final boolean enabled) {
|
||||
return deviceWriteService.set(id, Device::setEnabled, enabled);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/title")
|
||||
public DeviceDto setName(@PathVariable final long id, @RequestBody final String title) {
|
||||
return deviceWriteService.set(id, Device::setTitle, title);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/DeviceSwitch/setState")
|
||||
public DeviceDto setDeviceSwitchSetState(@PathVariable final long id, @RequestBody(required = false) final String name) {
|
||||
return deviceWriteService.setDeviceSwitch(id, DeviceSwitch::setSetState, name);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/DeviceSwitch/getState")
|
||||
public DeviceDto setDeviceSwitchGetState(@PathVariable final long id, @RequestBody(required = false) final String name) {
|
||||
return deviceWriteService.setDeviceSwitch(id, DeviceSwitch::setGetState, name);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/DeviceShutter/setPercent")
|
||||
public DeviceDto setDeviceShutterSetPercent(@PathVariable final long id, @RequestBody(required = false) final String name) {
|
||||
return deviceWriteService.setDeviceShutter(id, DeviceShutter::setSetPercent, name);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/DeviceShutter/getPercent")
|
||||
public DeviceDto setDeviceShutterGetPercent(@PathVariable final long id, @RequestBody(required = false) final String name) {
|
||||
return deviceWriteService.setDeviceShutter(id, DeviceShutter::setGetPercent, name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package de.ph87.homeautomation.device;
|
||||
|
||||
import de.ph87.homeautomation.device.devices.*;
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import de.ph87.homeautomation.property.PropertyService;
|
||||
import de.ph87.office.web.NotFoundException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -27,19 +27,25 @@ public class DeviceReadService {
|
||||
return deviceRepository.findAll().stream().map(this::toDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private DeviceDto toDto(final Device device) {
|
||||
public DeviceDto toDto(final Device device) {
|
||||
if (device instanceof DeviceSwitch) {
|
||||
final DeviceSwitch deviceSwitch = (DeviceSwitch) device;
|
||||
final PropertyDto getState = mapIfNotNull(deviceSwitch.getGetState(), propertyService::getById);
|
||||
final PropertyDto setState = mapIfNotNull(deviceSwitch.getSetState(), propertyService::getById);
|
||||
return new DeviceSwitchDto(deviceSwitch, getState, setState);
|
||||
final Boolean state = mapIfNotNull(deviceSwitch.getGetState(), propertyService::readBoolean);
|
||||
return new DeviceSwitchDto(deviceSwitch, deviceSwitch.getGetState(), deviceSwitch.getSetState(), state);
|
||||
} 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);
|
||||
final Double percent = mapIfNotNull(deviceShutter.getGetPercent(), propertyService::readNumber);
|
||||
return new DeviceShutterDto(deviceShutter, deviceShutter.getGetPercent(), deviceShutter.getSetPercent(), percent);
|
||||
}
|
||||
throw new RuntimeException("Not implemented: toDto(" + device + ")");
|
||||
}
|
||||
|
||||
public Device getById(final long id) {
|
||||
return deviceRepository.findById(id).orElseThrow(() -> new NotFoundException("Device.id=%d", id));
|
||||
}
|
||||
|
||||
public DeviceDto getDtoById(final long id) {
|
||||
return toDto(getById(id));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -9,4 +9,6 @@ public interface DeviceRepository extends CrudRepository<Device, Long> {
|
||||
|
||||
List<Device> findAll();
|
||||
|
||||
boolean existsByTitle(String title);
|
||||
|
||||
}
|
||||
|
||||
@ -1,18 +1,19 @@
|
||||
package de.ph87.homeautomation.device;
|
||||
|
||||
import de.ph87.homeautomation.device.devices.Device;
|
||||
import de.ph87.homeautomation.device.devices.DeviceDto;
|
||||
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 de.ph87.homeautomation.schedule.ScheduleWriteService;
|
||||
import de.ph87.office.web.BadRequestException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static de.ph87.homeautomation.shared.Helpers.mapIfNotNull;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -24,24 +25,28 @@ public class DeviceWriteService {
|
||||
|
||||
private final PropertyService propertyService;
|
||||
|
||||
public void createDeviceSwitch(final String title, final PropertyDto getState, final PropertyDto setState) {
|
||||
private final DeviceReadService deviceReadService;
|
||||
|
||||
public DeviceDto createDeviceSwitch(final String title, final String getStatePropertyName, final String setStatePropertyName) {
|
||||
final DeviceSwitch deviceSwitch = new DeviceSwitch();
|
||||
deviceSwitch.setTitle(title);
|
||||
deviceSwitch.setGetState(mapIfNotNull(getState, PropertyDto::getName));
|
||||
deviceSwitch.setSetState(mapIfNotNull(setState, PropertyDto::getName));
|
||||
deviceSwitch.setGetState(getStatePropertyName);
|
||||
deviceSwitch.setSetState(setStatePropertyName);
|
||||
deviceRepository.save(deviceSwitch);
|
||||
return deviceReadService.toDto(deviceSwitch);
|
||||
}
|
||||
|
||||
public void createDeviceShutter(final String title, final PropertyDto getPercent, final PropertyDto setPercent) {
|
||||
public DeviceDto createDeviceShutter(final String title, final String getPercentPropertyName, final String setPercentPropertyName) {
|
||||
final DeviceShutter deviceShutter = new DeviceShutter();
|
||||
deviceShutter.setTitle(title);
|
||||
deviceShutter.setGetPercent(mapIfNotNull(getPercent, PropertyDto::getName));
|
||||
deviceShutter.setSetPercent(mapIfNotNull(setPercent, PropertyDto::getName));
|
||||
deviceShutter.setGetPercent(getPercentPropertyName);
|
||||
deviceShutter.setSetPercent(setPercentPropertyName);
|
||||
deviceRepository.save(deviceShutter);
|
||||
return deviceReadService.toDto(deviceShutter);
|
||||
}
|
||||
|
||||
public void set(final DeviceSetDto dto) throws PropertySetException {
|
||||
final Device device = getById(dto.getId());
|
||||
final Device device = deviceReadService.getById(dto.getId());
|
||||
if (device instanceof DeviceSwitch) {
|
||||
setSwitch((DeviceSwitch) device, dto.getProperty(), dto.getValue());
|
||||
} else if (device instanceof DeviceShutter) {
|
||||
@ -63,8 +68,51 @@ public class DeviceWriteService {
|
||||
}
|
||||
}
|
||||
|
||||
private Device getById(final long id) {
|
||||
return deviceRepository.findById(id).orElseThrow(() -> new NotFoundException("Device.id=%d", id));
|
||||
public <T> DeviceDto set(final long id, final BiConsumer<Device, T> setter, final T value) {
|
||||
final Device device = deviceReadService.getById(id);
|
||||
setter.accept(device, value);
|
||||
return deviceReadService.toDto(device);
|
||||
}
|
||||
|
||||
public <T> DeviceDto setDeviceSwitch(final long id, final BiConsumer<DeviceSwitch, T> setter, final T value) {
|
||||
final Device device = deviceReadService.getById(id);
|
||||
if (!(device instanceof DeviceSwitch)) {
|
||||
throw new BadRequestException("Not a DeviceSwitch: %s", device);
|
||||
}
|
||||
setter.accept((DeviceSwitch) device, value);
|
||||
return deviceReadService.toDto(device);
|
||||
}
|
||||
|
||||
public <T> DeviceDto setDeviceShutter(final long id, final BiConsumer<DeviceShutter, T> setter, final T value) {
|
||||
final Device device = deviceReadService.getById(id);
|
||||
if (!(device instanceof DeviceShutter)) {
|
||||
throw new BadRequestException("Not a DeviceShutter: %s", device);
|
||||
}
|
||||
setter.accept((DeviceShutter) device, value);
|
||||
return deviceReadService.toDto(device);
|
||||
}
|
||||
|
||||
public void delete(final long id) {
|
||||
deviceRepository.deleteById(id);
|
||||
}
|
||||
|
||||
public DeviceDto create(final String type) {
|
||||
switch (type) {
|
||||
case "DeviceSwitch":
|
||||
return createDeviceSwitch(generateUnusedTitle(), null, null);
|
||||
case "DeviceShutter":
|
||||
return createDeviceShutter(generateUnusedTitle(), null, null);
|
||||
}
|
||||
throw new RuntimeException("Not implemented type: " + type);
|
||||
}
|
||||
|
||||
private String generateUnusedTitle() {
|
||||
int index = 0;
|
||||
String title = null;
|
||||
while (title == null || deviceRepository.existsByTitle(title)) {
|
||||
title = ScheduleWriteService.NAME_PREFIX + ++index;
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -21,4 +21,6 @@ public abstract class Device {
|
||||
|
||||
private String title;
|
||||
|
||||
private boolean enabled = false;
|
||||
|
||||
}
|
||||
|
||||
@ -1,19 +1,21 @@
|
||||
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 String getPercent;
|
||||
|
||||
public final PropertyDto setPercent;
|
||||
public final String setPercent;
|
||||
|
||||
public DeviceShutterDto(final DeviceShutter device, final PropertyDto getPercent, final PropertyDto setPercent) {
|
||||
public final Double percent;
|
||||
|
||||
public DeviceShutterDto(final DeviceShutter device, final String getPercent, final String setPercent, final Double percent) {
|
||||
super(device);
|
||||
this.getPercent = getPercent;
|
||||
this.setPercent = setPercent;
|
||||
this.percent = percent;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,19 +1,21 @@
|
||||
package de.ph87.homeautomation.device.devices;
|
||||
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class DeviceSwitchDto extends DeviceDto {
|
||||
|
||||
public final PropertyDto getState;
|
||||
public final String getState;
|
||||
|
||||
public final PropertyDto setState;
|
||||
public final String setState;
|
||||
|
||||
public DeviceSwitchDto(final DeviceSwitch device, final PropertyDto getState, final PropertyDto setState) {
|
||||
public final Boolean state;
|
||||
|
||||
public DeviceSwitchDto(final DeviceSwitch device, final String getState, final String setState, final Boolean state) {
|
||||
super(device);
|
||||
this.getState = getState;
|
||||
this.setState = setState;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import de.ph87.homeautomation.property.IProperty;
|
||||
import de.ph87.homeautomation.property.PropertyType;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
@ -15,7 +14,7 @@ import java.time.ZonedDateTime;
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
public class KnxGroup implements IProperty {
|
||||
public class KnxGroup {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
|
||||
@ -62,7 +62,7 @@ public class KnxGroupSetService implements IPropertyOwner {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number readNumber(final String propertyName) {
|
||||
public Double readNumber(final String propertyName) {
|
||||
return knxGroupRepository.findByAddressRaw(parseGroupAddress(propertyName).getRawAddress()).map(KnxGroup::getNumberValue).orElse(null);
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
package de.ph87.homeautomation.property;
|
||||
|
||||
public interface IProperty {
|
||||
|
||||
String getPropertyName();
|
||||
|
||||
}
|
||||
@ -12,7 +12,7 @@ public interface IPropertyOwner {
|
||||
|
||||
Boolean readBoolean(String propertyName);
|
||||
|
||||
Number readNumber(String propertyName);
|
||||
Double readNumber(String propertyName);
|
||||
|
||||
List<PropertyDto> findAllProperties();
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ public class PropertyService {
|
||||
return getOwnerOrThrow(propertyName).readBoolean(propertyName);
|
||||
}
|
||||
|
||||
public Number readNumber(final String propertyName) {
|
||||
public Double readNumber(final String propertyName) {
|
||||
return getOwnerOrThrow(propertyName).readNumber(propertyName);
|
||||
}
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@ public class Schedule {
|
||||
private boolean enabled = false;
|
||||
|
||||
@Column(nullable = false, unique = true)
|
||||
private String name;
|
||||
private String title;
|
||||
|
||||
private String propertyName;
|
||||
|
||||
|
||||
@ -45,15 +45,15 @@ public class ScheduleCalculationService {
|
||||
.filter(entry -> entry.getNextFuzzyTimestamp() != null && entry.getNextFuzzyTimestamp().isAfter(now))
|
||||
.min(Comparator.comparing(ScheduleEntry::getNextFuzzyTimestamp));
|
||||
if (nextEntry.isEmpty()) {
|
||||
log.info("No next schedule for \"{}\"", schedule.getName());
|
||||
log.info("No next schedule for \"{}\"", schedule.getTitle());
|
||||
} else {
|
||||
log.info("Next schedule for \"{}\": {}", schedule.getName(), nextEntry.get().getNextFuzzyTimestamp());
|
||||
log.info("Next schedule for \"{}\": {}", schedule.getTitle(), nextEntry.get().getNextFuzzyTimestamp());
|
||||
}
|
||||
eventPublisher.publishEvent(new ScheduleThreadWakeUpEvent());
|
||||
}
|
||||
|
||||
private void calculateEntry(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) {
|
||||
log.debug("calculateNext \"{}\", {}:", schedule.getName(), entry);
|
||||
log.debug("calculateNext \"{}\", {}:", schedule.getTitle(), entry);
|
||||
if (!schedule.isEnabled() || !entry.isEnabled() || !isAnyWeekdayEnabled(entry)) {
|
||||
entry.setNextClearTimestamp(null);
|
||||
return;
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package de.ph87.homeautomation.schedule;
|
||||
|
||||
import de.ph87.homeautomation.property.PropertyType;
|
||||
import de.ph87.homeautomation.schedule.entry.ScheduleNextExecutionDto;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@ -21,16 +20,11 @@ public class ScheduleController {
|
||||
return scheduleReadService.findAllDtos();
|
||||
}
|
||||
|
||||
@GetMapping("findById/{id}")
|
||||
public ScheduleDto findById(@PathVariable final long id) {
|
||||
@GetMapping("getById/{id}")
|
||||
public ScheduleDto getById(@PathVariable final long id) {
|
||||
return scheduleReadService.getDtoById(id);
|
||||
}
|
||||
|
||||
@GetMapping("findAllNext")
|
||||
public List<ScheduleNextExecutionDto> findAllNext() {
|
||||
return scheduleReadService.findAllNextExecutionDtos();
|
||||
}
|
||||
|
||||
@GetMapping("create")
|
||||
public ScheduleDto create() {
|
||||
return scheduleWriteService.create();
|
||||
@ -48,7 +42,7 @@ public class ScheduleController {
|
||||
|
||||
@PostMapping("set/{id}/name")
|
||||
public ScheduleDto setName(@PathVariable final long id, @RequestBody final String name) {
|
||||
return scheduleWriteService.set(id, Schedule::setName, name);
|
||||
return scheduleWriteService.set(id, Schedule::setTitle, name);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/propertyName")
|
||||
|
||||
@ -14,7 +14,7 @@ public class ScheduleDto {
|
||||
|
||||
public final boolean enabled;
|
||||
|
||||
public final String name;
|
||||
public final String title;
|
||||
|
||||
public final String propertyName;
|
||||
|
||||
@ -25,7 +25,7 @@ public class ScheduleDto {
|
||||
public ScheduleDto(final Schedule schedule) {
|
||||
this.id = schedule.getId();
|
||||
this.enabled = schedule.isEnabled();
|
||||
this.name = schedule.getName();
|
||||
this.title = schedule.getTitle();
|
||||
this.propertyName = schedule.getPropertyName();
|
||||
this.propertyType = schedule.getPropertyType();
|
||||
this.entries = schedule.getEntries().stream().map(ScheduleEntryDto::new).collect(Collectors.toSet());
|
||||
|
||||
@ -41,7 +41,7 @@ public class ScheduleExecutionService {
|
||||
|
||||
private void executeEntry(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) {
|
||||
entry.setLastClearTimestamp(entry.getNextClearTimestamp());
|
||||
log.info("Executing Schedule \"{}\" Entry {}", schedule.getName(), entry);
|
||||
log.info("Executing Schedule \"{}\" Entry {}", schedule.getTitle(), entry);
|
||||
try {
|
||||
propertyService.set(schedule.getPropertyName(), entry.getValue());
|
||||
} catch (PropertySetException e) {
|
||||
|
||||
@ -1,17 +1,13 @@
|
||||
package de.ph87.homeautomation.schedule;
|
||||
|
||||
import de.ph87.homeautomation.schedule.entry.ScheduleEntry;
|
||||
import de.ph87.homeautomation.schedule.entry.ScheduleNextExecutionDto;
|
||||
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 java.time.ZonedDateTime;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@ -36,16 +32,6 @@ public class ScheduleReadService {
|
||||
return findAll().stream().map(scheduleMapper::toDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<ScheduleNextExecutionDto> findAllNextExecutionDtos() {
|
||||
final ZonedDateTime now = ZonedDateTime.now();
|
||||
return scheduleRepository.findAll().stream()
|
||||
.map(schedule -> ScheduleNextExecutionDto.create(schedule, now))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.sorted(Comparator.comparing(ScheduleNextExecutionDto::getNextTimestamp))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Schedule getByEntry(final ScheduleEntry entry) {
|
||||
return scheduleRepository.getByEntriesContaining(entry);
|
||||
}
|
||||
|
||||
@ -11,6 +11,6 @@ public interface ScheduleRepository extends CrudRepository<Schedule, Long> {
|
||||
|
||||
Schedule getByEntriesContaining(ScheduleEntry entry);
|
||||
|
||||
boolean existsByName(String name);
|
||||
boolean existsByTitle(String title);
|
||||
|
||||
}
|
||||
|
||||
@ -24,6 +24,21 @@ public class ScheduleWriteService {
|
||||
|
||||
private final ScheduleRepository scheduleRepository;
|
||||
|
||||
public ScheduleDto create() {
|
||||
final Schedule entry = new Schedule();
|
||||
entry.setTitle(generateUnusedName());
|
||||
return scheduleMapper.toDto(scheduleRepository.save(entry));
|
||||
}
|
||||
|
||||
private String generateUnusedName() {
|
||||
int index = 0;
|
||||
String name = null;
|
||||
while (name == null || scheduleRepository.existsByTitle(name)) {
|
||||
name = ScheduleWriteService.NAME_PREFIX + ++index;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public <T> ScheduleDto set(final long id, final BiConsumer<Schedule, T> setter, final T value) {
|
||||
final Schedule schedule = scheduleReadService.getById(id);
|
||||
setter.accept(schedule, value);
|
||||
@ -31,21 +46,6 @@ public class ScheduleWriteService {
|
||||
return scheduleMapper.toDto(schedule);
|
||||
}
|
||||
|
||||
public ScheduleDto create() {
|
||||
final Schedule entry = new Schedule();
|
||||
entry.setName(generateUnusedName());
|
||||
return scheduleMapper.toDto(scheduleRepository.save(entry));
|
||||
}
|
||||
|
||||
private String generateUnusedName() {
|
||||
int index = 0;
|
||||
String name = null;
|
||||
while (name == null || scheduleRepository.existsByName(name)) {
|
||||
name = ScheduleWriteService.NAME_PREFIX + ++index;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public void delete(final long id) {
|
||||
scheduleRepository.deleteById(id);
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ public class ScheduleNextExecutionDto {
|
||||
public final double numberValue;
|
||||
|
||||
private ScheduleNextExecutionDto(final Schedule schedule, final ScheduleEntry entry) {
|
||||
this.name = schedule.getName();
|
||||
this.name = schedule.getTitle();
|
||||
this.nextTimestamp = entry.getNextFuzzyTimestamp();
|
||||
this.numberValue = entry.getValue();
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user