integrating Bulk into ScheduleEntry

This commit is contained in:
Patrick Haßel 2022-10-03 14:08:54 +02:00
parent 7691243f87
commit 3f0fa3ca3f
38 changed files with 737 additions and 197 deletions

View File

@ -1,6 +1,6 @@
#logging.level.de.ph87.homeautomation=DEBUG
#-
spring.datasource.url=jdbc:h2:./Homeautomation;AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.url=jdbc:h2:./Homeautomation;AUTO_SERVER=TRUE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password

View File

@ -0,0 +1,33 @@
import {validateBooleanNotNull, validateListOrEmpty, validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators";
import {BulkEntry} from "./BulkEntry";
export class Bulk {
private constructor(
public id: number,
public version: number,
public name: string,
public enabled: boolean,
public entries: BulkEntry[],
) {
// nothing
}
static fromJson(json: any): Bulk {
return new Bulk(
validateNumberNotNull(json['id']),
validateNumberNotNull(json['version']),
validateStringNotEmptyNotNull(json['name']),
validateBooleanNotNull(json['enabled']),
validateListOrEmpty(json['entries'], BulkEntry.fromJson),
);
}
static fromJsonOrNull(json: any): Bulk | null {
if (json === null) {
return null;
}
return this.fromJson(json);
}
}

View File

@ -0,0 +1,20 @@
import {Property} from "../property/Property";
import {validateNumberNotNull} from "../validators";
export class BulkEntry {
private constructor(
readonly property: Property,
readonly value: number,
) {
// nothing
}
static fromJson(json: any): BulkEntry {
return new BulkEntry(
Property.fromJson(json['property']),
validateNumberNotNull(json['value']),
);
}
}

View File

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

View File

@ -45,5 +45,4 @@ export class Property {
}
return a.title.localeCompare(b.title);
}
}

View File

@ -1,6 +1,5 @@
import {validateBooleanNotNull, validateListOrEmpty, validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators";
import {ScheduleEntry} from "./entry/ScheduleEntry";
import {Property} from "../property/Property";
export class Schedule {
@ -8,7 +7,6 @@ export class Schedule {
public id: number,
public enabled: boolean,
public title: string,
public property: Property | null,
public entries: ScheduleEntry[],
) {
// nothing
@ -19,7 +17,6 @@ export class Schedule {
validateNumberNotNull(json['id']),
validateBooleanNotNull(json['enabled']),
validateStringNotEmptyNotNull(json['title']),
Property.fromJsonAllowNull(json['property']),
validateListOrEmpty(json['entries'], ScheduleEntry.fromJson, ScheduleEntry.compare),
);
}

View File

@ -1,5 +1,7 @@
import {validateBooleanNotNull, validateDateAllowNull, validateNumberNotNull, validateStringNotEmptyNotNull} from "../../validators";
import {Timestamp} from "../../Timestamp";
import {Property} from "../../property/Property";
import {Bulk} from "../../bulk/Bulk";
function getDaySeconds(date: Date): number {
return date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds();
@ -26,7 +28,9 @@ export class ScheduleEntry {
public lastClearTimestamp: Timestamp | null,
public nextClearTimestamp: Timestamp | null,
public nextFuzzyTimestamp: Timestamp | null,
public property: Property | null,
public value: number,
public bulk: Bulk | null,
) {
// nothing
}
@ -51,7 +55,9 @@ export class ScheduleEntry {
Timestamp.fromDateOrNull(validateDateAllowNull(json['lastClearTimestamp'])),
Timestamp.fromDateOrNull(validateDateAllowNull(json['nextClearTimestamp'])),
Timestamp.fromDateOrNull(validateDateAllowNull(json['nextFuzzyTimestamp'])),
Property.fromJsonAllowNull(json['property']),
validateNumberNotNull(json['value']),
Bulk.fromJsonOrNull(json['bulk']),
);
}

View File

@ -10,15 +10,9 @@
<table>
<tr class="header">
<ng-container *ngTemplateOutlet="boolean;context:{schedule: schedule, value: schedule.enabled, key:'enabled'}"></ng-container>
<td colspan="8">
<td colspan="24">
<app-edit-field [initial]="schedule.title" (valueChange)="set(null, 'title', $event)"></app-edit-field>
</td>
<td colspan="5">
<app-search [searchService]="propertyService" [initial]="schedule.property?.id" (valueChange)="set(null, 'property', $event)"></app-search>
</td>
<td colspan="9">
{{schedule.property?.type}}
</td>
</tr>
<tr [class.disabled]="!schedule.enabled">
<th>&nbsp;</th>
@ -34,7 +28,8 @@
<th colspan="3">Uhrzeit</th>
<th>Unschärfe</th>
<th colspan="6">Nächste Ausführung</th>
<th>Wert</th>
<th colspan="2">Eingeschaft setzen</th>
<th>Massenausführung</th>
<th>&nbsp;</th>
</tr>
<tr *ngFor="let entry of schedule.entries" [class.disabled]="entry.nextClearTimestamp === null">
@ -132,38 +127,50 @@
<td class="empty last"></td>
</ng-container>
<td *ngIf="schedule.property?.type === 'BOOLEAN'" [class.true]="entry.value" [class.false]="!entry.value" (click)="set(entry, 'value', entry.value > 0 ? 0 : 1)">
{{entry.value ? "An" : "Aus"}}
<td>
<app-search [searchService]="propertyService" [initial]="entry.property?.id" (valueChange)="set(entry, 'property', $event)"></app-search>
</td>
<td *ngIf="schedule.property?.type === 'SHUTTER'" [class.true]="entry.value === 0" [class.false]="entry.value === 100" [class.tristate]="0 < entry.value && entry.value < 100">
<select [(ngModel)]="entry.value" (ngModelChange)="set(entry, 'value', entry.value)">
<option [ngValue]="0">100% Offen</option>
<option [ngValue]="35">&nbsp;50%</option>
<option [ngValue]="55">&nbsp;75%</option>
<option [ngValue]="75">&nbsp;90% Sonnenschutz</option>
<option [ngValue]="85">100% Schlitze</option>
<option [ngValue]="100">100% Geschlossen</option>
</select>
</td>
<td *ngIf="schedule.property?.type === 'BRIGHTNESS_PERCENT'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
<select [(ngModel)]="entry.value" (ngModelChange)="set(entry, 'value', entry.value)">
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
</select>
</td>
<td *ngIf="schedule.property?.type === 'COLOR_TEMPERATURE'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
<select [(ngModel)]="entry.value" (ngModelChange)="set(entry, 'value', entry.value)">
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
</select>
</td>
<td *ngIf="schedule.property?.type === 'LUX'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
<select [(ngModel)]="entry.value" (ngModelChange)="set(entry, 'value', entry.value)">
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
</select>
</td>
<td *ngIf="schedule.property?.type === 'SCENE'">
<select [(ngModel)]="entry.value" (ngModelChange)="set(entry, 'value', entry.value)">
<option *ngFor="let scene of scenes" [ngValue]="scene.number">#{{scene.number | number:'2.0-0'}} {{scene.title}}</option>
</select>
<ng-container [ngSwitch]="entry.property?.type">
<td *ngSwitchCase="'BOOLEAN'" [class.true]="entry.value" [class.false]="!entry.value" (click)="set(entry, 'value', entry.value > 0 ? 0 : 1)">
{{entry.value ? "An" : "Aus"}}
</td>
<td *ngSwitchCase="'SHUTTER'" [class.true]="entry.value === 0" [class.false]="entry.value === 100" [class.tristate]="0 < entry.value && entry.value < 100">
<select [(ngModel)]="entry.value" (ngModelChange)="set(entry, 'value', entry.value)">
<option [ngValue]="0">100% Offen</option>
<option [ngValue]="35">&nbsp;50%</option>
<option [ngValue]="55">&nbsp;75%</option>
<option [ngValue]="75">&nbsp;90% Sonnenschutz</option>
<option [ngValue]="85">100% Schlitze</option>
<option [ngValue]="100">100% Geschlossen</option>
</select>
</td>
<td *ngSwitchCase="'BRIGHTNESS_PERCENT'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
<select [(ngModel)]="entry.value" (ngModelChange)="set(entry, 'value', entry.value)">
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
</select>
</td>
<td *ngSwitchCase="'COLOR_TEMPERATURE'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
<select [(ngModel)]="entry.value" (ngModelChange)="set(entry, 'value', entry.value)">
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
</select>
</td>
<td *ngSwitchCase="'LUX'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
<select [(ngModel)]="entry.value" (ngModelChange)="set(entry, 'value', entry.value)">
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
</select>
</td>
<td *ngSwitchCase="'SCENE'">
<select [(ngModel)]="entry.value" (ngModelChange)="set(entry, 'value', entry.value)">
<option *ngFor="let scene of scenes" [ngValue]="scene.number">#{{scene.number | number:'2.0-0'}} {{scene.title}}</option>
</select>
</td>
<td *ngSwitchDefault class="empty">
&nbsp;
</td>
</ng-container>
<td>
<app-search [searchService]="bulkService" [initial]="entry.bulk?.id" (valueChange)="set(entry, 'bulk', $event)"></app-search>
</td>
<td class="delete" (click)="delete(entry)">

View File

@ -9,6 +9,7 @@ import {DataService} from "../../data.service";
import {PropertyService} from "../../api/property/property.service";
import {Scene} from "../../api/scene/Scene";
import {SceneService} from "../../api/scene/scene.service";
import {BulkService} from "../../api/bulk/bulkService";
@Component({
selector: 'app-schedule',
@ -18,8 +19,11 @@ import {SceneService} from "../../api/scene/scene.service";
export class ScheduleComponent implements OnInit {
readonly faCheckCircle = faCheckCircle;
readonly faCircle = faCircle;
readonly faTimes = faTimesCircle;
readonly Schedule = Schedule;
schedule!: Schedule;
@ -31,6 +35,7 @@ export class ScheduleComponent implements OnInit {
readonly scheduleService: ScheduleService,
readonly scheduleEntryService: ScheduleEntryService,
readonly propertyService: PropertyService,
readonly bulkService: BulkService,
readonly sceneService: SceneService,
readonly dataService: DataService,
) {

View File

@ -1,9 +1,11 @@
package de.ph87.homeautomation;
import com.luckycatlabs.sunrisesunset.Zenith;
import de.ph87.homeautomation.bulk.Bulk;
import de.ph87.homeautomation.bulk.BulkCreateDto;
import de.ph87.homeautomation.bulk.BulkEntryCreateDto;
import de.ph87.homeautomation.bulk.BulkWriter;
import de.ph87.homeautomation.channel.Channel;
import de.ph87.homeautomation.device.DeviceWriteService;
import de.ph87.homeautomation.device.devices.DeviceDto;
import de.ph87.homeautomation.knx.group.KnxGroup;
import de.ph87.homeautomation.knx.group.KnxGroupReadService;
import de.ph87.homeautomation.logic.Logic;
@ -12,7 +14,6 @@ import de.ph87.homeautomation.logic.LogicRepository;
import de.ph87.homeautomation.property.Property;
import de.ph87.homeautomation.property.PropertyRepository;
import de.ph87.homeautomation.property.PropertyType;
import de.ph87.homeautomation.scene.SceneDto;
import de.ph87.homeautomation.scene.SceneWriteService;
import de.ph87.homeautomation.schedule.Schedule;
import de.ph87.homeautomation.schedule.ScheduleRepository;
@ -26,6 +27,8 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
@SuppressWarnings({"unchecked", "UnusedReturnValue", "SameParameterValue", "UnusedAssignment", "RedundantSuppression"})
@Slf4j
@ -34,127 +37,42 @@ import java.util.HashSet;
@RequiredArgsConstructor
public class DemoDataService {
private static final int MIN30 = 30 * 60;
private static final Zenith BETWEEN_OFFICIAL_AND_CIVIL = new Zenith(93.0);
private final ScheduleRepository scheduleRepository;
private final DeviceWriteService deviceWriteService;
private final PropertyRepository propertyRepository;
private final KnxGroupReadService knxGroupReadService;
private final SceneWriteService sceneWriteService;
private final LogicRepository logicRepository;
private final BulkWriter bulkWriter;
private final Config config;
private final ScheduleRepository scheduleRepository;
public void insertDemoData() {
if (!config.isInsertDemoData()) {
return;
}
final Property propertyDirect = createProperty("propertyDirect", PropertyType.BOOLEAN, null, null);
final Property propertyBulkBoolean = createProperty("propertyBulkBoolean", PropertyType.BOOLEAN, null, null);
final Property propertyBulkShutter = createProperty("propertyBulkShutter", PropertyType.SHUTTER, null, null);
final Property propertyBulkBrightness = createProperty("propertyBulkBrightness", PropertyType.BRIGHTNESS_PERCENT, null, null);
final Property propertyBulkColorTemperature = createProperty("propertyBulkColorTemperature", PropertyType.COLOR_TEMPERATURE, null, null);
final List<BulkEntryCreateDto> entries = Arrays.asList(
new BulkEntryCreateDto(propertyBulkBoolean.getId(), 1, 0),
new BulkEntryCreateDto(propertyBulkShutter.getId(), 35, 0),
new BulkEntryCreateDto(propertyBulkBrightness.getId(), 40, 0),
new BulkEntryCreateDto(propertyBulkColorTemperature.getId(), 55, 0)
);
final Bulk bulk = createBulk("bulk", true, entries.toArray(new BulkEntryCreateDto[0]));
final Schedule schedule = createSchedule(true, "schedule");
createTime(schedule, true, 12, 0, 0, 0, propertyDirect, 1, bulk);
}
final Property erdgeschoss = createProperty("Erdgeschoss", PropertyType.BOOLEAN, knx(0, 4, 2), null);
final Property erdgeschoss_szene = createProperty("Erdgeschoss Szene", PropertyType.SCENE, null, knx(0, 0, 1));
final Property obergeschoss = createProperty("Obergeschoss", PropertyType.BOOLEAN, knx(0, 6, 6), null);
final Property obergeschoss_szene = createProperty("Obergeschoss Szene", PropertyType.SCENE, null, knx(0, 3, 2));
final Property fernseher = createProperty("Fernseher", PropertyType.BOOLEAN, knx(0, 0, 20), knx(0, 0, 4));
final Property verstaerker = createProperty("Verstärker", PropertyType.BOOLEAN, knx(0, 3, 57), knx(0, 3, 56));
final Property aussendekoration = createProperty("Außendekoration", PropertyType.BOOLEAN, knx(0, 4, 12), knx(0, 4, 11));
final Property terrasse = createProperty("Terrasse Licht", PropertyType.BOOLEAN, knx(0, 4, 1), knx(0, 4, 0));
final Property ambiente_eg = createProperty("Ambiente EG", PropertyType.BOOLEAN, knx(0, 3, 81), knx(0, 3, 80));
final Property ambiente_og = createProperty("Ambiente OG", PropertyType.BOOLEAN, knx(0, 6, 2), knx(0, 6, 3));
final Property flur_eg_licht = createProperty("Flur EG Licht", PropertyType.BOOLEAN, knx(0, 4, 8), knx(0, 5, 14));
final Property wohnzimmer_rollladen = createProperty("Wohnzimmer Rollladen", PropertyType.SHUTTER, null, knx(0, 4, 24));
final Property schlafzimmer_rollladen = createProperty("Schlafzimmer Rollladen", PropertyType.SHUTTER, null, knx(0, 3, 3));
final Property flur_og_rollladen = createProperty("Flur OG Rollladen", PropertyType.SHUTTER, null, knx(0, 5, 13));
final Property helligkeit = createProperty("Helligkeit", PropertyType.LUX, knx(0, 5, 6), null);
final Property szene_haus = createProperty("Szene Haus ", PropertyType.SCENE, null, knx(0, 0, 21));
final SceneDto alles_aus = sceneWriteService.create(1, "Alles AUS");
final SceneDto nachtlicht = sceneWriteService.create(2, "Nachtlicht");
final SceneDto aussendekoration_aus = sceneWriteService.create(30, "Außendekoration AUS");
final SceneDto aussendekoration_an = sceneWriteService.create(31, "Außendekoration AN");
deviceWriteService.createDeviceStateScene(erdgeschoss, erdgeschoss_szene, alles_aus);
deviceWriteService.createDeviceStateScene(obergeschoss, obergeschoss_szene, alles_aus);
deviceWriteService.createDeviceSwitch(fernseher);
deviceWriteService.createDeviceSwitch(verstaerker);
deviceWriteService.createDeviceSwitch(aussendekoration);
deviceWriteService.createDeviceSwitch(terrasse);
deviceWriteService.createDeviceSwitch(ambiente_eg);
deviceWriteService.createDeviceSwitch(ambiente_og);
deviceWriteService.createDeviceSwitch(flur_eg_licht);
deviceWriteService.createDeviceShutter(wohnzimmer_rollladen);
deviceWriteService.createDeviceShutter(schlafzimmer_rollladen);
deviceWriteService.createDeviceShutter(flur_og_rollladen);
final Schedule scheduleEgFlurLicht = createSchedule(true, "EG Flur Licht", flur_eg_licht);
createTime(scheduleEgFlurLicht, true, 1, 0, 0, MIN30, true);
createTime(scheduleEgFlurLicht, true, 2, 0, 0, MIN30, false);
createTime(scheduleEgFlurLicht, true, 7, 30, 0, MIN30, true);
createTime(scheduleEgFlurLicht, true, 8, 30, 0, MIN30, false);
createTime(scheduleEgFlurLicht, true, 13, 30, 0, MIN30, true);
createTime(scheduleEgFlurLicht, true, 14, 30, 0, MIN30, false);
createTime(scheduleEgFlurLicht, true, 19, 0, 0, MIN30, true);
createTime(scheduleEgFlurLicht, true, 20, 0, 0, MIN30, false);
scheduleRepository.save(scheduleEgFlurLicht);
final Schedule scheduleEgAmbiente = createSchedule(false, "Ambiente EG", ambiente_eg);
createTime(scheduleEgAmbiente, true, 7, 15, 0, MIN30, true);
createTime(scheduleEgAmbiente, true, 9, 30, 0, MIN30, false);
createSunset(scheduleEgAmbiente, true, Zenith.OFFICIAL, MIN30, true);
createSunset(scheduleEgAmbiente, true, Zenith.ASTRONOMICAL, MIN30, false);
scheduleRepository.save(scheduleEgAmbiente);
final Schedule scheduleOgAmbiente = createSchedule(false, "Ambiente OG", ambiente_og);
createTime(scheduleOgAmbiente, true, 7, 15, 0, MIN30, true);
createTime(scheduleOgAmbiente, true, 9, 30, 0, MIN30, false);
createSunset(scheduleOgAmbiente, true, Zenith.OFFICIAL, MIN30, true);
createSunset(scheduleOgAmbiente, true, Zenith.ASTRONOMICAL, MIN30, false);
scheduleRepository.save(scheduleOgAmbiente);
final Schedule scheduleWohnzimmerRollladen = createSchedule(true, "Rollläden Wohnzimmer", wohnzimmer_rollladen);
createSunrise(scheduleWohnzimmerRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 0);
createSunset(scheduleWohnzimmerRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100);
scheduleRepository.save(scheduleWohnzimmerRollladen);
final Schedule scheduleSchlafzimmerRollladen = createSchedule(true, "Rollläden Schlafzimmer", schlafzimmer_rollladen);
createTime(scheduleSchlafzimmerRollladen, true, 7, 0, 0, 0, 0);
createSunset(scheduleSchlafzimmerRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100);
scheduleRepository.save(scheduleSchlafzimmerRollladen);
final Schedule scheduleFlurRollladen = createSchedule(true, "Rollladen Flur", flur_og_rollladen);
createSunrise(scheduleFlurRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 0);
createSunset(scheduleFlurRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100);
scheduleRepository.save(scheduleFlurRollladen);
final Schedule scheduleSzeneHaus = createSchedule(true, "Dekoration", szene_haus);
createTime(scheduleSzeneHaus, true, 6, 0, 0, 0, 31);
createTime(scheduleSzeneHaus, true, 8, 30, 0, 0, 30);
createSunset(scheduleSzeneHaus, true, Zenith.OFFICIAL, 0, 31);
createTime(scheduleSzeneHaus, true, 22, 0, 0, 0, 30);
scheduleRepository.save(scheduleSzeneHaus);
final Property propertyBadLicht = createProperty("Bad Licht", PropertyType.BOOLEAN, knx(0, 5, 19), knx(0, 3, 73));
final DeviceDto deviceBadLicht = deviceWriteService.createDeviceSwitch(propertyBadLicht);
// final Logic logicStatusOg = getOrCreateLogic("Status OG", LogicOperator.OR, propertyBadLicht);
// final Property propertyStatusOg = createProperty(logicStatusOg.getName(), PropertyType.BOOLEAN, logicStatusOg, null);
// final DeviceDto deviceStatusOg = deviceWriteService.createDeviceSwitch(propertyStatusOg);
private Bulk createBulk(final String name, final boolean enabled, final BulkEntryCreateDto... entries) {
return bulkWriter.create(new BulkCreateDto(name, enabled, Arrays.stream(entries).collect(Collectors.toList())));
}
private Logic getOrCreateLogic(final String name, final LogicOperator operator, final Property... properties) {
@ -175,32 +93,31 @@ public class DemoDataService {
return property;
}
private Schedule createSchedule(final boolean enabled, final String title, final Property property) {
private Schedule createSchedule(final boolean enabled, final String title) {
final Schedule schedule = new Schedule();
schedule.setEnabled(enabled);
schedule.setTitle(title);
schedule.setProperty(property);
return schedule;
return scheduleRepository.save(schedule);
}
private ScheduleEntry createRelative(final Schedule schedule, final boolean enabled, final int inSeconds, final int fuzzySeconds, final Object value) {
private ScheduleEntry createRelative(final Schedule schedule, final boolean enabled, final int inSeconds, final int fuzzySeconds, final Property property, final Object value, final Bulk bulk) {
final ZonedDateTime now = ZonedDateTime.now().plusSeconds(inSeconds).withNano(0);
return createTime(schedule, enabled, now.getHour(), now.getMinute(), now.getSecond(), fuzzySeconds, value);
return createTime(schedule, enabled, now.getHour(), now.getMinute(), now.getSecond(), fuzzySeconds, property, value, bulk);
}
private ScheduleEntry createTime(final Schedule schedule, final boolean enabled, final int hour, final int minute, final int second, final int fuzzySeconds, final Object value) {
return newScheduleEntry(schedule, enabled, ScheduleEntryType.TIME, null, hour, minute, second, fuzzySeconds, value);
private ScheduleEntry createTime(final Schedule schedule, final boolean enabled, final int hour, final int minute, final int second, final int fuzzySeconds, final Property property, final Object value, final Bulk bulk) {
return newScheduleEntry(schedule, enabled, ScheduleEntryType.TIME, null, hour, minute, second, fuzzySeconds, property, value, bulk);
}
private ScheduleEntry createSunrise(final Schedule schedule, final boolean enabled, final Zenith zenith, final int fuzzySeconds, final Object value) {
return newScheduleEntry(schedule, enabled, ScheduleEntryType.SUNRISE, zenith, 0, 0, 0, fuzzySeconds, value);
private ScheduleEntry createSunrise(final Schedule schedule, final boolean enabled, final Zenith zenith, final int fuzzySeconds, final Property property, final Object value, final Bulk bulk) {
return newScheduleEntry(schedule, enabled, ScheduleEntryType.SUNRISE, zenith, 0, 0, 0, fuzzySeconds, property, value, bulk);
}
private ScheduleEntry createSunset(final Schedule schedule, final boolean enabled, final Zenith zenith, final int fuzzySeconds, final Object value) {
return newScheduleEntry(schedule, enabled, ScheduleEntryType.SUNSET, zenith, 0, 0, 0, fuzzySeconds, value);
private ScheduleEntry createSunset(final Schedule schedule, final boolean enabled, final Zenith zenith, final int fuzzySeconds, final Property property, final Object value, final Bulk bulk) {
return newScheduleEntry(schedule, enabled, ScheduleEntryType.SUNSET, zenith, 0, 0, 0, fuzzySeconds, property, value, bulk);
}
private ScheduleEntry newScheduleEntry(final Schedule schedule, final boolean enabled, final ScheduleEntryType type, final Zenith zenith, final int hour, final int minute, final int second, final int fuzzySeconds, final Object value) {
private ScheduleEntry newScheduleEntry(final Schedule schedule, final boolean enabled, final ScheduleEntryType type, final Zenith zenith, final int hour, final int minute, final int second, final int fuzzySeconds, final Property property, final Object value, final Bulk bulk) {
final ScheduleEntry entry = new ScheduleEntry();
entry.setEnabled(enabled);
entry.setType(type);
@ -211,6 +128,7 @@ public class DemoDataService {
entry.setMinute(minute);
entry.setSecond(second);
entry.setFuzzySeconds(fuzzySeconds);
entry.setProperty(property);
if (value instanceof Boolean) {
entry.setValue((boolean) value ? 1.0 : 0.0);
} else if (value instanceof Double) {
@ -220,6 +138,7 @@ public class DemoDataService {
} else {
throw new RuntimeException();
}
entry.setBulk(bulk);
schedule.getEntries().add(entry);
return entry;
}

View File

@ -0,0 +1,42 @@
package de.ph87.homeautomation.bulk;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Getter
@ToString
@NoArgsConstructor
public class Bulk {
@Id
@GeneratedValue
private long id;
@Version
private long version;
@Setter
private boolean enabled = false;
@Setter
@Column(nullable = false, unique = true)
private String name;
@ElementCollection
@ToString.Exclude
private List<BulkEntry> entries = new ArrayList<>();
public Bulk(final BulkCreateDto dto, final List<BulkEntry> entries) {
this.enabled = dto.isEnabled();
this.name = dto.getName();
this.entries = new ArrayList<>(entries);
}
}

View File

@ -0,0 +1,86 @@
package de.ph87.homeautomation.bulk;
import de.ph87.homeautomation.property.Property;
import de.ph87.homeautomation.property.PropertyReadService;
import de.ph87.homeautomation.shared.ISearchController;
import de.ph87.homeautomation.shared.SearchResult;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("bulk")
@RequiredArgsConstructor
public class BulkController implements ISearchController {
private final BulkWriter bulkWriter;
private final BulkReader bulkReader;
private final PropertyReadService propertyReadService;
@PostMapping("create")
public BulkDto create(@RequestBody final BulkCreateDto dto) {
return bulkWriter.createDto(dto);
}
@PostMapping("filter")
public Page<BulkDto> filter(@RequestBody final BulkFilter filter) {
return bulkReader.filter(filter);
}
@DeleteMapping("delete")
public void delete(@RequestBody final long id) {
bulkWriter.delete(id);
}
@PostMapping("name/{id}")
public BulkDto name(@PathVariable final long id, @RequestBody final String name) {
return bulkWriter.set(id, bulk -> bulk.setName(name));
}
@PostMapping("enabled/{id}")
public BulkDto enabled(@PathVariable final long id, @RequestBody final boolean enabled) {
return bulkWriter.set(id, bulk -> bulk.setEnabled(enabled));
}
@PostMapping("entryAdd/{id}")
public BulkDto entryAdd(@PathVariable final long id, @RequestBody final BulkEntryCreateDto dto) {
return bulkWriter.set(id, bulk -> {
final Property property = propertyReadService.getById(dto.getPropertyId());
bulk.getEntries().add(dto.getIndex(), new BulkEntry(dto, property));
});
}
@PostMapping("entryMove/{id}/{indexFrom}/{indexTo}")
public BulkDto entryMove(@PathVariable final long id, @PathVariable final int indexFrom, @PathVariable final int indexTo) {
return bulkWriter.set(id, bulk -> bulk.getEntries().add(indexTo, bulk.getEntries().remove(indexFrom)));
}
@PostMapping("entryRemove/{id}/{index}")
public BulkDto entryRemove(@PathVariable final long id, @PathVariable final int index) {
return bulkWriter.set(id, bulk -> bulk.getEntries().remove(index));
}
@Override
@GetMapping("getById/{id}")
@Deprecated(since = "Use 'filter' instead", forRemoval = true)
public SearchResult getById(@PathVariable final long id) {
return toSearchResult(bulkReader.getDtoById(id));
}
@Override
@PostMapping("searchLike")
@Deprecated(since = "Use 'filter' instead", forRemoval = true)
public List<SearchResult> searchLike(@RequestBody final String term) {
return bulkReader.findAllDtoLike("%" + term + "%").stream().map(this::toSearchResult).collect(Collectors.toList());
}
private SearchResult toSearchResult(final BulkDto bulkDto) {
return new SearchResult(bulkDto.getId(), bulkDto.getName());
}
}

View File

@ -0,0 +1,16 @@
package de.ph87.homeautomation.bulk;
import lombok.Data;
import java.util.List;
@Data
public class BulkCreateDto {
private final String name;
private final boolean enabled;
private final List<BulkEntryCreateDto> entries;
}

View File

@ -0,0 +1,28 @@
package de.ph87.homeautomation.bulk;
import lombok.Data;
import java.util.List;
@Data
public class BulkDto {
private final long id;
private final long version;
private final boolean enabled;
private final String name;
private final List<BulkEntryDto> entries;
public BulkDto(final Bulk bulk, final List<BulkEntryDto> entries) {
this.id = bulk.getId();
this.version = bulk.getVersion();
this.enabled = bulk.isEnabled();
this.name = bulk.getName();
this.entries = entries;
}
}

View File

@ -0,0 +1,29 @@
package de.ph87.homeautomation.bulk;
import de.ph87.homeautomation.property.Property;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.ManyToOne;
@Embeddable
@Getter
@ToString
@NoArgsConstructor
public class BulkEntry {
@ManyToOne(optional = false)
private Property property;
@Column(name = "value_")
private double value;
public BulkEntry(final BulkEntryCreateDto dto, final Property property) {
this.property = property;
this.value = dto.getValue();
}
}

View File

@ -0,0 +1,14 @@
package de.ph87.homeautomation.bulk;
import lombok.Data;
@Data
public class BulkEntryCreateDto {
private final long propertyId;
private final double value;
private final int index;
}

View File

@ -0,0 +1,18 @@
package de.ph87.homeautomation.bulk;
import de.ph87.homeautomation.property.PropertyDto;
import lombok.Data;
@Data
public class BulkEntryDto {
private final PropertyDto property;
private final double value;
public BulkEntryDto(final BulkEntry bulkEntry, final PropertyDto property) {
this.property = property;
this.value = bulkEntry.getValue();
}
}

View File

@ -0,0 +1,23 @@
package de.ph87.homeautomation.bulk;
import de.ph87.homeautomation.property.PropertyWriteService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class BulkExecutor {
private final PropertyWriteService propertyWriteService;
public void execute(final Bulk bulk) {
log.debug("Executing Bulk: {}", bulk);
bulk.getEntries().forEach(entry -> propertyWriteService.writeToChannel(entry.getProperty(), entry.getValue()));
log.debug("Finished executing Bulk: {}", bulk);
}
}

View File

@ -0,0 +1,30 @@
package de.ph87.homeautomation.bulk;
import de.ph87.homeautomation.common.Filter;
import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
public class BulkFilter extends Filter<Bulk> {
private Long id;
private String name;
@Override
public Specification<Bulk> getSpecification() {
return (root, query, criteriaBuilder) -> {
final List<Predicate> predicates = new ArrayList<>();
if (id != null) {
predicates.add(criteriaBuilder.equal(root.get("id"), id));
}
if (name != null) {
predicates.add(criteriaBuilder.like(root.get("name"), "%" + name + "%"));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
};
}
}

View File

@ -0,0 +1,36 @@
package de.ph87.homeautomation.bulk;
import de.ph87.homeautomation.property.PropertyDto;
import de.ph87.homeautomation.property.PropertyMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
@Service
@Transactional
@RequiredArgsConstructor
public class BulkMapper {
private final PropertyMapper propertyMapper;
public BulkDto toDto(final Bulk bulk) {
final List<BulkEntryDto> entries = bulk.getEntries().stream().map(this::toDto).collect(Collectors.toList());
return new BulkDto(bulk, entries);
}
private BulkEntryDto toDto(final BulkEntry bulkEntry) {
final PropertyDto property = propertyMapper.toDto(bulkEntry.getProperty());
return new BulkEntryDto(bulkEntry, property);
}
public BulkDto toDtoOrNull(final Bulk bulk) {
if (bulk == null) {
return null;
}
return toDto(bulk);
}
}

View File

@ -0,0 +1,40 @@
package de.ph87.homeautomation.bulk;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class BulkReader {
private final BulkRepository bulkRepository;
private final BulkMapper bulkMapper;
public Bulk getById(final long id) {
return bulkRepository.findById(id).orElseThrow(RuntimeException::new);
}
public Page<BulkDto> filter(final BulkFilter filter) {
return bulkRepository.findAll(filter.getSpecification(), filter.getPageable()).map(bulkMapper::toDto);
}
@Deprecated(since = "Use 'filter' instead", forRemoval = true)
public BulkDto getDtoById(final long id) {
return bulkMapper.toDto(getById(id));
}
@Deprecated(since = "Use 'filter' instead", forRemoval = true)
public List<BulkDto> findAllDtoLike(final String term) {
return bulkRepository.findAllByNameLike(term).stream().map(bulkMapper::toDto).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,13 @@
package de.ph87.homeautomation.bulk;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
public interface BulkRepository extends JpaRepository<Bulk, Long>, JpaSpecificationExecutor<Bulk> {
@Deprecated(since = "Use 'filter' instead", forRemoval = true)
List<Bulk> findAllByNameLike(String term);
}

View File

@ -0,0 +1,51 @@
package de.ph87.homeautomation.bulk;
import de.ph87.homeautomation.property.PropertyReadService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class BulkWriter {
private final BulkRepository bulkRepository;
private final BulkReader bulkReader;
private final BulkMapper bulkMapper;
private final PropertyReadService propertyReadService;
public Bulk create(final BulkCreateDto dto) {
final List<BulkEntry> entries = dto.getEntries().stream().map(e -> new BulkEntry(e, propertyReadService.getById(e.getPropertyId()))).collect(Collectors.toList());
final Bulk bulk = bulkRepository.save(new Bulk(dto, entries));
log.info("Bulk created: {}", bulk);
return bulk;
}
public void delete(final long id) {
final Bulk bulk = bulkReader.getById(id);
bulkRepository.delete(bulk);
log.info("Bulk deleted: {}", bulk);
}
public BulkDto set(final long id, final Consumer<Bulk> consumer) {
final Bulk bulk = bulkReader.getById(id);
consumer.accept(bulk);
log.info("Changed Bulk: {}", bulk);
return bulkMapper.toDto(bulk);
}
public BulkDto createDto(final BulkCreateDto dto) {
return bulkMapper.toDto(create(dto));
}
}

View File

@ -0,0 +1,29 @@
package de.ph87.homeautomation.common;
import lombok.Data;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import java.util.ArrayList;
import java.util.List;
@Data
public class Filter<T> {
private int page = 0;
private int size = 50;
private List<Sort.Order> orders = new ArrayList<>();
public Pageable getPageable() {
return PageRequest.of(page, size, Sort.by(orders));
}
public Specification<T> getSpecification() {
return (root, query, criteriaBuilder) -> criteriaBuilder.conjunction();
}
}

View File

@ -40,6 +40,7 @@ public class KnxGroup extends Channel {
@Embedded
private KnxTelegram lastTelegram;
@Column(name = "value_")
private Double value;
private ZonedDateTime timestamp;

View File

@ -31,6 +31,7 @@ public class Logic extends Channel {
@ToString.Exclude
private Set<Property> properties = new HashSet<>();
@Column(name = "value_")
private Double value;
private ZonedDateTime timestamp;

View File

@ -27,6 +27,7 @@ public final class Property {
private ZonedDateTime timestamp;
@Column(name = "value_")
private Double value;
@ManyToOne

View File

@ -22,4 +22,11 @@ public class PropertyMapper {
);
}
public PropertyDto toDtoOrNull(final Property property) {
if (property == null) {
return null;
}
return toDto(property);
}
}

View File

@ -1,6 +1,5 @@
package de.ph87.homeautomation.schedule;
import de.ph87.homeautomation.property.Property;
import de.ph87.homeautomation.schedule.entry.ScheduleEntry;
import lombok.AccessLevel;
import lombok.Getter;
@ -27,9 +26,6 @@ public class Schedule {
@Column(nullable = false, unique = true)
private String title;
@ManyToOne
private Property property;
@ToString.Exclude
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private Set<ScheduleEntry> entries = new HashSet<>();

View File

@ -47,9 +47,4 @@ public class ScheduleController {
return scheduleWriteService.set(id, Schedule::setTitle, title);
}
@PostMapping("set/{id}/property")
public ScheduleDto setPropertyName(@PathVariable final long id, @RequestBody(required = false) final Long propertyId) {
return scheduleWriteService.set(id, (s, v) -> s.setProperty(v == null ? null : propertyReadService.getById(v)), propertyId);
}
}

View File

@ -1,12 +1,10 @@
package de.ph87.homeautomation.schedule;
import de.ph87.homeautomation.property.PropertyDto;
import de.ph87.homeautomation.schedule.entry.ScheduleEntryDto;
import lombok.Getter;
import java.io.Serializable;
import java.util.Set;
import java.util.stream.Collectors;
@Getter
public class ScheduleDto implements Serializable {
@ -17,16 +15,13 @@ public class ScheduleDto implements Serializable {
public final String title;
public final PropertyDto property;
public final Set<ScheduleEntryDto> entries;
public ScheduleDto(final Schedule schedule, final PropertyDto propertyDto) {
public ScheduleDto(final Schedule schedule, final Set<ScheduleEntryDto> entries) {
this.id = schedule.getId();
this.enabled = schedule.isEnabled();
this.title = schedule.getTitle();
this.property = propertyDto;
this.entries = schedule.getEntries().stream().map(ScheduleEntryDto::new).collect(Collectors.toSet());
this.entries = entries;
}
}

View File

@ -1,5 +1,6 @@
package de.ph87.homeautomation.schedule;
import de.ph87.homeautomation.bulk.BulkExecutor;
import de.ph87.homeautomation.property.PropertyWriteService;
import de.ph87.homeautomation.schedule.entry.ScheduleEntry;
import lombok.RequiredArgsConstructor;
@ -22,16 +23,14 @@ public class ScheduleExecutionService {
private final PropertyWriteService propertyWriteService;
private final BulkExecutor bulkExecutor;
public void executeAllLastDue() {
final ZonedDateTime now = ZonedDateTime.now();
scheduleReadService.findAll().forEach(schedule -> executeLastDue(schedule, now));
}
private void executeLastDue(final Schedule schedule, final ZonedDateTime now) {
if (schedule.getProperty() == null) {
log.error("Cannot execute Schedule {}: No property set!", schedule);
return;
}
schedule.getEntries().stream()
.filter(entry -> entry.getNextFuzzyTimestamp() != null && !entry.getNextFuzzyTimestamp().isAfter(now))
.max(Comparator.comparing(ScheduleEntry::getNextFuzzyTimestamp))
@ -39,9 +38,14 @@ public class ScheduleExecutionService {
}
private void executeEntry(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) {
if (entry.getProperty() == null) {
log.error("Cannot execute Schedule {}: No property set!", schedule);
return;
}
entry.setLastClearTimestamp(entry.getNextClearTimestamp());
log.info("Executing Schedule \"{}\" Entry {}", schedule.getTitle(), entry);
propertyWriteService.writeToChannel(schedule.getProperty(), entry.getValue());
propertyWriteService.writeToChannel(entry.getProperty(), entry.getValue());
bulkExecutor.execute(entry.getBulk());
scheduleCalculationService.calculateSchedule(schedule, now);
}

View File

@ -1,12 +1,14 @@
package de.ph87.homeautomation.schedule;
import de.ph87.homeautomation.property.PropertyMapper;
import de.ph87.homeautomation.schedule.entry.ScheduleEntryDto;
import de.ph87.homeautomation.schedule.entry.ScheduleEntryMapper;
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.mapOrNull;
import java.util.Set;
import java.util.stream.Collectors;
@Slf4j
@Service
@ -14,10 +16,11 @@ import static de.ph87.homeautomation.shared.Helpers.mapOrNull;
@RequiredArgsConstructor
public class ScheduleMapper {
private final PropertyMapper propertyMapper;
private final ScheduleEntryMapper scheduleEntryMapper;
public ScheduleDto toDto(final Schedule schedule) {
return new ScheduleDto(schedule, mapOrNull(schedule.getProperty(), propertyMapper::toDto));
final Set<ScheduleEntryDto> entries = schedule.getEntries().stream().map(scheduleEntryMapper::toDto).collect(Collectors.toSet());
return new ScheduleDto(schedule, entries);
}
}

View File

@ -1,14 +1,13 @@
package de.ph87.homeautomation.schedule.entry;
import com.luckycatlabs.sunrisesunset.Zenith;
import de.ph87.homeautomation.bulk.Bulk;
import de.ph87.homeautomation.property.Property;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.*;
import java.time.ZonedDateTime;
import java.util.Random;
@ -45,15 +44,25 @@ public class ScheduleEntry {
private double zenith = Zenith.CIVIL.degrees().doubleValue();
@Column(name = "hour_")
private int hour = 0;
@Column(name = "minute_")
private int minute = 0;
@Column(name = "second_")
private int second = 0;
private int fuzzySeconds = 0;
private double value = 0;
@ManyToOne
private Property property;
@Column(name = "value_")
private double value;
@ManyToOne
private Bulk bulk;
private ZonedDateTime nextClearTimestamp;

View File

@ -1,5 +1,7 @@
package de.ph87.homeautomation.schedule.entry;
import de.ph87.homeautomation.bulk.BulkReader;
import de.ph87.homeautomation.property.PropertyReadService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
@ -10,6 +12,10 @@ public class ScheduleEntryController {
private final ScheduleEntryWriteService scheduleEntryWriteService;
private final BulkReader bulkReader;
private final PropertyReadService propertyReadService;
@GetMapping("create/{scheduleId}")
public ScheduleEntryDto create(@PathVariable final long scheduleId) {
return scheduleEntryWriteService.create(scheduleId);
@ -90,9 +96,19 @@ public class ScheduleEntryController {
return scheduleEntryWriteService.set(id, ScheduleEntry::setFuzzySeconds, value);
}
@PostMapping("set/{id}/property")
public ScheduleEntryDto property(@PathVariable final long id, @RequestBody(required = false) final Long propertyId) {
return scheduleEntryWriteService.set(id, entry -> entry.setProperty(propertyId == null ? null : propertyReadService.getById(propertyId)));
}
@PostMapping("set/{id}/value")
public ScheduleEntryDto setValue(@PathVariable final long id, @RequestBody final double value) {
return scheduleEntryWriteService.set(id, ScheduleEntry::setValue, value);
}
@PostMapping("set/{id}/bulk")
public ScheduleEntryDto bulk(@PathVariable final long id, @RequestBody(required = false) final Long bulkId) {
return scheduleEntryWriteService.set(id, entry -> entry.setBulk(bulkId == null ? null : bulkReader.getById(bulkId)));
}
}

View File

@ -1,5 +1,7 @@
package de.ph87.homeautomation.schedule.entry;
import de.ph87.homeautomation.bulk.BulkDto;
import de.ph87.homeautomation.property.PropertyDto;
import lombok.Getter;
import java.io.Serializable;
@ -44,9 +46,13 @@ public class ScheduleEntryDto implements Serializable {
public final ZonedDateTime nextFuzzyTimestamp;
public final PropertyDto property;
public final double value;
public ScheduleEntryDto(final ScheduleEntry entry) {
public final BulkDto bulk;
public ScheduleEntryDto(final ScheduleEntry entry, final PropertyDto property, final BulkDto bulk) {
this.id = entry.getId();
this.enabled = entry.isEnabled();
this.monday = entry.isMonday();
@ -65,7 +71,9 @@ public class ScheduleEntryDto implements Serializable {
this.nextClearTimestamp = entry.getNextClearTimestamp();
this.lastClearTimestamp = entry.getLastClearTimestamp();
this.nextFuzzyTimestamp = entry.getNextFuzzyTimestamp();
this.property = property;
this.value = entry.getValue();
this.bulk = bulk;
}
}

View File

@ -1,5 +1,9 @@
package de.ph87.homeautomation.schedule.entry;
import de.ph87.homeautomation.bulk.BulkDto;
import de.ph87.homeautomation.bulk.BulkMapper;
import de.ph87.homeautomation.property.PropertyDto;
import de.ph87.homeautomation.property.PropertyMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@ -11,8 +15,14 @@ import org.springframework.transaction.annotation.Transactional;
@RequiredArgsConstructor
public class ScheduleEntryMapper {
private final BulkMapper bulkMapper;
private final PropertyMapper propertyMapper;
public ScheduleEntryDto toDto(final ScheduleEntry scheduleEntry) {
return new ScheduleEntryDto(scheduleEntry);
final PropertyDto property = propertyMapper.toDtoOrNull(scheduleEntry.getProperty());
final BulkDto bulk = bulkMapper.toDtoOrNull(scheduleEntry.getBulk());
return new ScheduleEntryDto(scheduleEntry, property, bulk);
}
}

View File

@ -11,6 +11,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.time.ZonedDateTime;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@Slf4j
@Service
@ -30,6 +31,7 @@ public class ScheduleEntryWriteService {
private final WebSocketService webSocketService;
@Deprecated(since = "Use alternative 'set' instead.", forRemoval = true)
public <T> ScheduleEntryDto set(final long id, final BiConsumer<ScheduleEntry, T> setter, final T value) {
final ScheduleEntry entry = scheduleEntryReadService.getById(id);
setter.accept(entry, value);
@ -38,6 +40,14 @@ public class ScheduleEntryWriteService {
return publish(entry, true);
}
public ScheduleEntryDto set(final long id, final Consumer<ScheduleEntry> setter) {
final ScheduleEntry entry = scheduleEntryReadService.getById(id);
setter.accept(entry);
final Schedule schedule = scheduleReadService.getByEntry(entry);
scheduleCalculationService.calculateSchedule(schedule, ZonedDateTime.now());
return publish(entry, true);
}
public ScheduleEntryDto create(final long scheduleId) {
final Schedule schedule = scheduleReadService.getById(scheduleId);
final ScheduleEntry entry = new ScheduleEntry();