Implemented Logic + FIX Generic DTO transfer

This commit is contained in:
Patrick Haßel 2021-12-20 11:35:18 +01:00
parent 0ad433fea9
commit 31b8238ccc
34 changed files with 528 additions and 208 deletions

View File

@ -1,4 +1,4 @@
import {validateBooleanNotNull, validateDateAllowNull, validateNumberAllowNull, validateNumberNotNull, validateStringEmptyToNull, validateStringNotEmptyNotNull} from "../validators"; import {validateBooleanNotNull, validateDateAllowNull, validateListOrEmpty, validateNumberAllowNull, validateNumberNotNull, validateStringEmptyToNull, validateStringNotEmptyNotNull} from "../validators";
import {prefix} from "../../helpers"; import {prefix} from "../../helpers";
export abstract class Channel { export abstract class Channel {
@ -7,6 +7,8 @@ export abstract class Channel {
readonly id: number, readonly id: number,
readonly title: string, readonly title: string,
readonly type: string, readonly type: string,
readonly value: number | null,
readonly timestamp: Date | null,
) { ) {
// nothing // nothing
} }
@ -26,6 +28,8 @@ export abstract class Channel {
validateNumberNotNull(json['id']), validateNumberNotNull(json['id']),
validateStringNotEmptyNotNull(json['title']), validateStringNotEmptyNotNull(json['title']),
type, type,
validateNumberAllowNull(json['value']),
validateDateAllowNull(json['timestamp']),
validateNumberNotNull(json['addressRaw']), validateNumberNotNull(json['addressRaw']),
validateStringNotEmptyNotNull(json['addressStr']), validateStringNotEmptyNotNull(json['addressStr']),
validateNumberNotNull(json['dptMain']), validateNumberNotNull(json['dptMain']),
@ -33,8 +37,16 @@ export abstract class Channel {
validateStringEmptyToNull(json['description']), validateStringEmptyToNull(json['description']),
validateNumberNotNull(json['puid']), validateNumberNotNull(json['puid']),
validateBooleanNotNull(json['ets']), validateBooleanNotNull(json['ets']),
);
case "Logic":
return new Logic(
validateNumberNotNull(json['id']),
validateStringNotEmptyNotNull(json['title']),
type,
validateNumberAllowNull(json['value']), validateNumberAllowNull(json['value']),
validateDateAllowNull(json['timestamp']), validateDateAllowNull(json['timestamp']),
validateStringNotEmptyNotNull(json['operator']),
validateListOrEmpty(json['propertyIds'], validateNumberNotNull),
); );
} }
throw new Error("No such type: " + type); throw new Error("No such type: " + type);
@ -55,26 +67,26 @@ export abstract class Channel {
export class KnxGroup extends Channel { export class KnxGroup extends Channel {
public addresMain: number; readonly addresMain: number;
public addresMid: number; readonly addresMid: number;
public addresSub: number; readonly addresSub: number;
public dpt: string; readonly dpt: string;
constructor( constructor(
id: number, id: number,
title: string, title: string,
type: string, type: string,
public addressRaw: number, value: number | null,
public addressStr: string, timestamp: Date | null,
public dptMain: number, readonly addressRaw: number,
public dptSub: number, readonly addressStr: string,
public description: string | null, readonly dptMain: number,
public puid: number, readonly dptSub: number,
public ets: boolean, readonly description: string | null,
public value: number | null, readonly puid: number,
public timestamp: Date | null, readonly ets: boolean,
) { ) {
super(id, title, type); super(id, title, type, value, timestamp);
const addressParts = this.addressStr.split("/"); const addressParts = this.addressStr.split("/");
this.addresMain = parseInt(addressParts[0]); this.addresMain = parseInt(addressParts[0]);
this.addresMid = parseInt(addressParts[1]); this.addresMid = parseInt(addressParts[1]);
@ -83,3 +95,20 @@ export class KnxGroup extends Channel {
} }
} }
export class Logic extends Channel {
constructor(
id: number,
title: string,
type: string,
value: number | null,
timestamp: Date | null,
readonly operator: string,
readonly propertyIds: number[],
) {
super(id, title, type, value, timestamp);
// nothing
}
}

View File

@ -28,7 +28,7 @@ export abstract class Device {
type, type,
Property.fromJsonAllowNull(json['stateProperty']), Property.fromJsonAllowNull(json['stateProperty']),
Property.fromJsonAllowNull(json['sceneProperty']), Property.fromJsonAllowNull(json['sceneProperty']),
validateListOrEmpty(json['sceneNumbers'], parseInt), validateListOrEmpty(json['sceneNumbers'], validateNumberNotNull),
); );
case "DeviceShutter": case "DeviceShutter":
return new DeviceShutter( return new DeviceShutter(

View File

@ -14,8 +14,11 @@
<td class="middle number">{{asKnxGroup(channel).addresMid}}&nbsp;/&nbsp;</td> <td class="middle number">{{asKnxGroup(channel).addresMid}}&nbsp;/&nbsp;</td>
<td class="last number">{{asKnxGroup(channel).addresSub}}</td> <td class="last number">{{asKnxGroup(channel).addresSub}}</td>
<td class="number">{{asKnxGroup(channel).dpt}}</td> <td class="number">{{asKnxGroup(channel).dpt}}</td>
<td class="number">{{asKnxGroup(channel).value}}</td>
<td>{{asKnxGroup(channel).timestamp | date:'yyyy-MM-dd HH:mm:ss'}}</td>
</ng-container> </ng-container>
<ng-container *ngIf="channel.type === 'Logic'">
<td colspan="4">{{asLogic(channel).operator}}</td>
</ng-container>
<td class="number">{{channel.value}}</td>
<td>{{channel.timestamp | date:'yyyy-MM-dd HH:mm:ss'}}</td>
</tr> </tr>
</table> </table>

View File

@ -1,6 +1,6 @@
import {Component, OnInit} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {ChannelService} from "../../api/channel/channel.service"; import {ChannelService} from "../../api/channel/channel.service";
import {Channel, KnxGroup} from "../../api/channel/Channel"; import {Channel, KnxGroup, Logic} from "../../api/channel/Channel";
import {Update} from "../../api/Update"; import {Update} from "../../api/Update";
@Component({ @Component({
@ -27,6 +27,10 @@ export class ChannelListComponent implements OnInit {
return channel as KnxGroup; return channel as KnxGroup;
} }
asLogic(channel: Channel): Logic {
return channel as Logic;
}
private updateChannel(update: Update<Channel>): void { private updateChannel(update: Update<Channel>): void {
const index: number = this.channels.findIndex(c => c.id === update.payload.id); const index: number = this.channels.findIndex(c => c.id === update.payload.id);
if (index >= 0) { if (index >= 0) {

View File

@ -4,12 +4,16 @@ import com.luckycatlabs.sunrisesunset.Zenith;
import de.ph87.homeautomation.channel.Channel; import de.ph87.homeautomation.channel.Channel;
import de.ph87.homeautomation.device.DeviceRepository; import de.ph87.homeautomation.device.DeviceRepository;
import de.ph87.homeautomation.device.DeviceWriteService; import de.ph87.homeautomation.device.DeviceWriteService;
import de.ph87.homeautomation.device.devices.DeviceDto;
import de.ph87.homeautomation.knx.group.KnxGroup; import de.ph87.homeautomation.knx.group.KnxGroup;
import de.ph87.homeautomation.knx.group.KnxGroupReadService; import de.ph87.homeautomation.knx.group.KnxGroupReadService;
import de.ph87.homeautomation.logic.Logic;
import de.ph87.homeautomation.logic.LogicOperator;
import de.ph87.homeautomation.logic.LogicRepository;
import de.ph87.homeautomation.logic.LogicWriter;
import de.ph87.homeautomation.property.Property; import de.ph87.homeautomation.property.Property;
import de.ph87.homeautomation.property.PropertyRepository; import de.ph87.homeautomation.property.PropertyRepository;
import de.ph87.homeautomation.property.PropertyType; import de.ph87.homeautomation.property.PropertyType;
import de.ph87.homeautomation.scene.SceneDto;
import de.ph87.homeautomation.scene.SceneRepository; import de.ph87.homeautomation.scene.SceneRepository;
import de.ph87.homeautomation.scene.SceneWriteService; import de.ph87.homeautomation.scene.SceneWriteService;
import de.ph87.homeautomation.schedule.Schedule; import de.ph87.homeautomation.schedule.Schedule;
@ -22,6 +26,8 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.HashSet;
@SuppressWarnings({"unchecked", "UnusedReturnValue", "SameParameterValue", "UnusedAssignment", "RedundantSuppression"}) @SuppressWarnings({"unchecked", "UnusedReturnValue", "SameParameterValue", "UnusedAssignment", "RedundantSuppression"})
@Slf4j @Slf4j
@ -48,105 +54,114 @@ public class DemoDataService {
private final SceneWriteService sceneWriteService; private final SceneWriteService sceneWriteService;
private final LogicWriter logicWriter;
private final LogicRepository logicRepository;
public void insertDemoData() { public void insertDemoData() {
final Property erdgeschoss = createProperty("Erdgeschoss", PropertyType.BOOLEAN, knx(0, 4, 2), null); // 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 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 = 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 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 fernseher = createProperty("Fernseher", PropertyType.BOOLEAN, knx(0, 0, 20), knx(0, 0, 4)); // final Property flur_eg_licht = createProperty("Flur EG Licht", PropertyType.BOOLEAN, knx(0, 4, 8), knx(0, 5, 14));
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 wohnzimmer_rollladen = createProperty("Wohnzimmer Rollladen", PropertyType.SHUTTER, null, knx(0, 4, 24));
final Property terrasse = createProperty("Terrasse Licht", PropertyType.BOOLEAN, knx(0, 4, 1), knx(0, 4, 0)); // 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 Property ambiente_eg = createProperty("Ambiente EG", PropertyType.BOOLEAN, knx(0, 3, 81), knx(0, 3, 80)); // final SceneDto alles_aus = sceneWriteService.create(1, "Alles AUS");
final Property ambiente_og = createProperty("Ambiente OG", PropertyType.BOOLEAN, knx(0, 6, 2), knx(0, 6, 3)); // 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);
final Property bad_licht = createProperty("Bad Licht", PropertyType.BOOLEAN, knx(0, 5, 19), knx(0, 3, 73)); // deviceWriteService.createDeviceSwitch(flur_eg_licht);
final Property flur_eg_licht = createProperty("Flur EG Licht", PropertyType.BOOLEAN, knx(0, 4, 8), knx(0, 5, 14)); //
// 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 wohnzimmer_rollladen = createProperty("Wohnzimmer Rollladen", PropertyType.SHUTTER, null, knx(0, 4, 24)); final Property propertyBadLicht = createProperty("Bad Licht", PropertyType.BOOLEAN, knx(0, 5, 19), knx(0, 3, 73));
final Property schlafzimmer_rollladen = createProperty("Schlafzimmer Rollladen", PropertyType.SHUTTER, null, knx(0, 3, 3)); final DeviceDto deviceBadLicht = deviceWriteService.createDeviceSwitch(propertyBadLicht);
final Property flur_og_rollladen = createProperty("Flur OG Rollladen", PropertyType.SHUTTER, null, knx(0, 5, 13)); final Logic logicStatusOg = getOrCreateLogic("Status OG", LogicOperator.OR, propertyBadLicht);
final Property propertyStatusOg = createProperty(logicStatusOg.getName(), PropertyType.BOOLEAN, logicStatusOg, null);
final Property helligkeit = createProperty("Helligkeit", PropertyType.LUX, knx(0, 5, 6), null); final DeviceDto deviceStatusOg = deviceWriteService.createDeviceSwitch(propertyStatusOg);
final Property szene_haus = createProperty("Szene Haus ", PropertyType.SCENE, null, knx(0, 0, 21));
if (sceneRepository.count() == 0) {
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");
if (deviceRepository.count() == 0) {
deviceWriteService.createDeviceStateScene(erdgeschoss, erdgeschoss_szene, alles_aus);
deviceWriteService.createDeviceStateScene(obergeschoss, obergeschoss_szene, alles_aus);
deviceWriteService.createDeviceSwitch(fernseher);
deviceWriteService.createDeviceSwitch(verstaerker);
deviceWriteService.createDeviceSwitch(aussendekoration);
deviceWriteService.createDeviceSwitch(terrasse);
deviceWriteService.createDeviceSwitch(ambiente_eg);
deviceWriteService.createDeviceSwitch(ambiente_og);
deviceWriteService.createDeviceSwitch(bad_licht);
deviceWriteService.createDeviceSwitch(flur_eg_licht);
deviceWriteService.createDeviceShutter(wohnzimmer_rollladen);
deviceWriteService.createDeviceShutter(schlafzimmer_rollladen);
deviceWriteService.createDeviceShutter(flur_og_rollladen);
}
} }
if (scheduleRepository.count() == 0) { private Logic getOrCreateLogic(final String name, final LogicOperator operator, final Property... properties) {
final Schedule scheduleEgFlurLicht = createSchedule(true, "EG Flur Licht", flur_eg_licht); return logicRepository.findByName(name).orElseGet(() -> {
createTime(scheduleEgFlurLicht, true, 1, 0, 0, MIN30, true); final Logic logic = new Logic(name, operator, new HashSet<>(Arrays.asList(properties)));
createTime(scheduleEgFlurLicht, true, 2, 0, 0, MIN30, false); return logicRepository.save(logic);
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);
}
} }
private KnxGroup knx(final int main, final int mid, final int sub) { private KnxGroup knx(final int main, final int mid, final int sub) {

View File

@ -17,7 +17,7 @@ public class ChannelController implements ISearchController {
private final ChannelService channelService; private final ChannelService channelService;
@GetMapping("findAll") @GetMapping("findAll")
public List<ChannelDto> findAll() { public List<? extends ChannelDto> findAll() {
return channelService.findAllDto(); return channelService.findAllDto();
} }

View File

@ -4,6 +4,7 @@ import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import java.io.Serializable; import java.io.Serializable;
import java.time.ZonedDateTime;
@Getter @Getter
@ToString @ToString
@ -15,10 +16,16 @@ public abstract class ChannelDto implements Serializable {
private final String type; private final String type;
private final Double value;
private final ZonedDateTime timestamp;
protected ChannelDto(final Channel channel) { protected ChannelDto(final Channel channel) {
this.id = channel.getId(); this.id = channel.getId();
this.title = channel.getName(); this.title = channel.getName();
this.type = channel.getClass().getSimpleName(); this.type = channel.getClass().getSimpleName();
this.value = channel.getValue();
this.timestamp = channel.getTimestamp();
} }
} }

View File

@ -48,15 +48,15 @@ public class ChannelService {
return getByChannel(channel).toDto(channel); return getByChannel(channel).toDto(channel);
} }
public List<ChannelDto> findAllDto() { public List<? extends ChannelDto> findAllDto() {
return channelOwners.stream().map(IChannelOwner::findAllDto).reduce(new ArrayList<>(), Helpers::merge); return channelOwners.stream().map(IChannelOwner::findAllDto).reduce(new ArrayList<>(), Helpers::merge);
} }
public List<ChannelDto> findAllDtoLike(final String term) { public List<? extends ChannelDto> findAllDtoLike(final String term) {
return channelOwners.stream().map(owner -> owner.findAllDtoLike(term)).reduce(new ArrayList<>(), Helpers::merge); return channelOwners.stream().map(owner -> owner.findAllDtoLike(term)).reduce(new ArrayList<>(), Helpers::merge);
} }
public Optional<ChannelDto> findDtoById(final long id) { public Optional<? extends ChannelDto> findDtoById(final long id) {
return channelRepository.findById(id).map(this::toDto); return channelRepository.findById(id).map(this::toDto);
} }

View File

@ -4,14 +4,14 @@ import java.util.List;
public interface IChannelOwner { public interface IChannelOwner {
void read(final Channel channel); void requestUpdate(final Channel channel);
void write(final Channel channel, final double value); void write(final Channel channel, final double value);
ChannelDto toDto(final Channel channel); ChannelDto toDto(final Channel channel);
List<ChannelDto> findAllDto(); List<? extends ChannelDto> findAllDto();
List<ChannelDto> findAllDtoLike(final String like); List<? extends ChannelDto> findAllDtoLike(final String like);
} }

View File

@ -123,7 +123,7 @@ public class DeviceWriteService {
} }
private DeviceDto publish(final DeviceDto dto, final boolean existing) { private DeviceDto publish(final DeviceDto dto, final boolean existing) {
webSocketService.send(dto, existing); webSocketService.send(DeviceDto.class, dto, existing);
return dto; return dto;
} }

View File

@ -1,7 +1,6 @@
package de.ph87.homeautomation.knx.group; package de.ph87.homeautomation.knx.group;
import de.ph87.homeautomation.channel.Channel; import de.ph87.homeautomation.channel.Channel;
import de.ph87.homeautomation.channel.ChannelDto;
import de.ph87.homeautomation.channel.IChannelOwner; import de.ph87.homeautomation.channel.IChannelOwner;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -22,7 +21,7 @@ public class KnxGroupChannelOwnerService implements IChannelOwner {
private final KnxGroupReadService knxGroupReadService; private final KnxGroupReadService knxGroupReadService;
@Override @Override
public void read(final Channel channel) { public void requestUpdate(final Channel channel) {
knxGroupWriteService.requestRead((KnxGroup) channel); knxGroupWriteService.requestRead((KnxGroup) channel);
} }
@ -32,17 +31,17 @@ public class KnxGroupChannelOwnerService implements IChannelOwner {
} }
@Override @Override
public ChannelDto toDto(final Channel channel) { public KnxGroupDto toDto(final Channel channel) {
return new KnxGroupDto((KnxGroup) channel); return new KnxGroupDto((KnxGroup) channel);
} }
@Override @Override
public List<ChannelDto> findAllDto() { public List<KnxGroupDto> findAllDto() {
return knxGroupReadService.findAll().stream().map(this::toDto).collect(Collectors.toList()); return knxGroupReadService.findAll().stream().map(this::toDto).collect(Collectors.toList());
} }
@Override @Override
public List<ChannelDto> findAllDtoLike(final String like) { public List<KnxGroupDto> findAllDtoLike(final String like) {
return knxGroupReadService.findAllLike(like).stream().map(this::toDto).collect(Collectors.toList()); return knxGroupReadService.findAllLike(like).stream().map(this::toDto).collect(Collectors.toList());
} }

View File

@ -4,8 +4,6 @@ import de.ph87.homeautomation.channel.ChannelDto;
import lombok.Getter; import lombok.Getter;
import lombok.ToString; import lombok.ToString;
import java.time.ZonedDateTime;
@Getter @Getter
@ToString(callSuper = true) @ToString(callSuper = true)
public class KnxGroupDto extends ChannelDto { public class KnxGroupDto extends ChannelDto {
@ -26,10 +24,6 @@ public class KnxGroupDto extends ChannelDto {
public final KnxTelegram lastTelegram; public final KnxTelegram lastTelegram;
public final Double value;
public final ZonedDateTime timestamp;
public final KnxGroupLinkInfo read; public final KnxGroupLinkInfo read;
public final byte[] sendValue; public final byte[] sendValue;
@ -46,8 +40,6 @@ public class KnxGroupDto extends ChannelDto {
this.puid = knxGroup.getPuid(); this.puid = knxGroup.getPuid();
this.ets = knxGroup.isEts(); this.ets = knxGroup.isEts();
this.lastTelegram = knxGroup.getLastTelegram(); this.lastTelegram = knxGroup.getLastTelegram();
this.value = knxGroup.getValue();
this.timestamp = knxGroup.getTimestamp();
this.read = knxGroup.getRead(); this.read = knxGroup.getRead();
this.sendValue = knxGroup.getSendValue(); this.sendValue = knxGroup.getSendValue();
this.send = knxGroup.getSend(); this.send = knxGroup.getSend();

View File

@ -1,6 +1,5 @@
package de.ph87.homeautomation.knx.group; package de.ph87.homeautomation.knx.group;
import de.ph87.homeautomation.channel.ChannelChangedEvent;
import de.ph87.homeautomation.channel.ChannelDto; import de.ph87.homeautomation.channel.ChannelDto;
import de.ph87.homeautomation.web.WebSocketService; import de.ph87.homeautomation.web.WebSocketService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -28,10 +27,10 @@ public class KnxGroupWriteService {
private final ApplicationEventPublisher applicationEventPublisher; private final ApplicationEventPublisher applicationEventPublisher;
private final WebSocketService webSocketService;
private final KnxGroupMapper knxGroupMapper; private final KnxGroupMapper knxGroupMapper;
private final WebSocketService webSocketService;
public void requestRead(final KnxGroup knxGroup) { public void requestRead(final KnxGroup knxGroup) {
knxGroup.getRead().setNextTimestamp(ZonedDateTime.now()); knxGroup.getRead().setNextTimestamp(ZonedDateTime.now());
log.debug("Requesting read for KnxGroup: {}", knxGroup); log.debug("Requesting read for KnxGroup: {}", knxGroup);
@ -94,7 +93,6 @@ public class KnxGroupWriteService {
knxGroup.setTimestamp(ZonedDateTime.now()); knxGroup.setTimestamp(ZonedDateTime.now());
log.debug("KnxGroup updated: {}", knxGroup); log.debug("KnxGroup updated: {}", knxGroup);
publish(knxGroup); publish(knxGroup);
applicationEventPublisher.publishEvent(new ChannelChangedEvent(knxGroup));
} else { } else {
log.error("Failed to get value from DptXlator {} for KnxGroup {}", translator, knxGroup); log.error("Failed to get value from DptXlator {} for KnxGroup {}", translator, knxGroup);
} }
@ -119,9 +117,11 @@ public class KnxGroupWriteService {
return Optional.empty(); return Optional.empty();
} }
@SuppressWarnings("UnusedReturnValue")
private KnxGroupDto publish(final KnxGroup knxGroup) { private KnxGroupDto publish(final KnxGroup knxGroup) {
final KnxGroupDto dto = knxGroupMapper.toDto(knxGroup); final KnxGroupDto dto = knxGroupMapper.toDto(knxGroup);
webSocketService.send(ChannelDto.class.getSimpleName(), dto, true); applicationEventPublisher.publishEvent(dto);
webSocketService.send(ChannelDto.class, dto, true);
return dto; return dto;
} }

View File

@ -0,0 +1,49 @@
package de.ph87.homeautomation.logic;
import de.ph87.homeautomation.channel.Channel;
import de.ph87.homeautomation.channel.IChannelOwner;
import de.ph87.homeautomation.property.Property;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.*;
import java.time.ZonedDateTime;
import java.util.HashSet;
import java.util.Set;
@Getter
@Setter
@ToString
@Entity
@NoArgsConstructor
public class Logic extends Channel {
@Column(nullable = false, unique = true)
private String name;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private LogicOperator operator;
@ManyToMany
@ToString.Exclude
private Set<Property> properties = new HashSet<>();
private Double value;
private ZonedDateTime timestamp;
public Logic(final String name, final LogicOperator operator, final HashSet<Property> properties) {
this.name = name;
this.operator = operator;
this.properties = properties;
}
@Override
public Class<? extends IChannelOwner> getChannelOwnerClass() {
return LogicChannelOwner.class;
}
}

View File

@ -0,0 +1,47 @@
package de.ph87.homeautomation.logic;
import de.ph87.homeautomation.channel.Channel;
import de.ph87.homeautomation.channel.IChannelOwner;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class LogicChannelOwner implements IChannelOwner {
private final LogicReader logicReader;
private final LogicWriter logicWriter;
@Override
public void requestUpdate(final Channel channel) {
logicWriter.update((Logic) channel);
}
@Override
public void write(final Channel channel, final double value) {
throw new RuntimeException();
}
@Override
public LogicDto toDto(final Channel channel) {
return logicReader.toDto((Logic) channel);
}
@Override
public List<LogicDto> findAllDto() {
return logicReader.findAllDto();
}
@Override
public List<LogicDto> findAllDtoLike(final String like) {
return logicReader.findAllDtoLike(like);
}
}

View File

@ -0,0 +1,27 @@
package de.ph87.homeautomation.logic;
import de.ph87.homeautomation.channel.ChannelDto;
import de.ph87.homeautomation.property.Property;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.util.Set;
import java.util.stream.Collectors;
@Getter
@Setter
@ToString
public class LogicDto extends ChannelDto {
private LogicOperator operator;
private Set<Long> propertyIds;
public LogicDto(final Logic logic) {
super(logic);
this.operator = logic.getOperator();
this.propertyIds = logic.getProperties().stream().map(Property::getId).collect(Collectors.toSet());
}
}

View File

@ -0,0 +1,5 @@
package de.ph87.homeautomation.logic;
public enum LogicOperator {
OR, AND, XOR
}

View File

@ -0,0 +1,35 @@
package de.ph87.homeautomation.logic;
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.stream.Collectors;
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class LogicReader {
private final LogicRepository logicRepository;
public List<LogicDto> findAllDto() {
return logicRepository.findAll().stream().map(this::toDto).collect(Collectors.toList());
}
public LogicDto toDto(final Logic logic) {
return new LogicDto(logic);
}
public List<LogicDto> findAllDtoLike(final String like) {
return logicRepository.findAllByNameContainsIgnoreCase(like).stream().map(this::toDto).collect(Collectors.toList());
}
public List<Logic> findAllByPropertyId(final long id) {
return logicRepository.findAllByPropertyName(id);
}
}

View File

@ -0,0 +1,20 @@
package de.ph87.homeautomation.logic;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import java.util.List;
import java.util.Optional;
public interface LogicRepository extends CrudRepository<Logic, Long> {
List<Logic> findAll();
List<Logic> findAllByNameContainsIgnoreCase(String like);
@Query("select l from Logic l join l.properties p where p.id = :id")
List<Logic> findAllByPropertyName(long id);
Optional<Logic> findByName(String name);
}

View File

@ -0,0 +1,71 @@
package de.ph87.homeautomation.logic;
import de.ph87.homeautomation.channel.ChannelDto;
import de.ph87.homeautomation.property.Property;
import de.ph87.homeautomation.property.PropertyDto;
import de.ph87.homeautomation.web.WebSocketService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import java.time.ZonedDateTime;
import java.util.Objects;
import static de.ph87.homeautomation.shared.Helpers.getCurrentTransactionName;
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class LogicWriter {
private final LogicReader logicReader;
private final ApplicationEventPublisher applicationEventPublisher;
private final WebSocketService webSocketService;
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
// @Transactional(propagation = Propagation.REQUIRES_NEW)
public void onPropertyChanged(final PropertyDto dto) {
log.debug("Listen [{}]: {}", getCurrentTransactionName(), dto.getTitle());
logicReader.findAllByPropertyId(dto.getId()).forEach(this::update);
}
public void update(final Logic logic) {
final Double value = evaluate(logic);
if (!Objects.equals(logic.getValue(), value)) {
logic.setValue(value);
logic.setTimestamp(ZonedDateTime.now());
log.info("Logic changed: {}", logic);
publish(logic, true);
}
}
private Double evaluate(final Logic logic) {
if (logic.getProperties().stream().map(Property::getValue).anyMatch(Objects::isNull)) {
return null;
}
switch (logic.getOperator()) {
case OR:
return logic.getProperties().stream().map(Property::getValue).anyMatch(v -> v > 0) ? 1.0 : 0.0;
case AND:
return logic.getProperties().stream().map(Property::getValue).allMatch(v -> v > 0) ? 1.0 : 0.0;
case XOR:
return (double) (logic.getProperties().stream().map(Property::getValue).map(v -> v > 0).count() % 2);
}
throw new RuntimeException();
}
private void publish(final Logic logic, final boolean existing) {
final LogicDto dto = logicReader.toDto(logic);
log.debug("Publish [{}]: {}", getCurrentTransactionName(), dto.getTitle());
applicationEventPublisher.publishEvent(dto);
webSocketService.send(ChannelDto.class, dto, existing);
}
}

View File

@ -1,36 +0,0 @@
package de.ph87.homeautomation.property;
import de.ph87.homeautomation.channel.ChannelService;
import de.ph87.homeautomation.channel.IChannelOwner;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Optional;
@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class PropertyChannelService {
private final ChannelService channelService;
private final PropertyReadService propertyReadService;
@EventListener(ApplicationStartedEvent.class)
public void readAllPropertyChannels() {
propertyReadService.findAllByReadChannelNotNull().forEach(property -> {
final Optional<IChannelOwner> ownerOptional = channelService.findByChannel(property.getReadChannel());
if (ownerOptional.isPresent()) {
ownerOptional.get().read(property.getReadChannel());
} else {
log.error("No Owner for Property: {}", property);
}
});
}
}

View File

@ -42,17 +42,17 @@ public class PropertyController implements ISearchController {
@PostMapping("set/{id}/value") @PostMapping("set/{id}/value")
public PropertyDto setValue(@PathVariable final long id, @RequestBody final double value) { public PropertyDto setValue(@PathVariable final long id, @RequestBody final double value) {
return propertyWriteService.set(id, propertyWriteService::write, value); return propertyWriteService.set(id, propertyWriteService::writeToChannel, value);
} }
@PostMapping("set/{id}/readChannel") @PostMapping("set/{id}/readChannel")
public PropertyDto setReadChannel(@PathVariable final long id, @RequestBody(required = false) final Long channelId) { public PropertyDto setReadChannel(@PathVariable final long id, @RequestBody(required = false) final Long channelId) {
return propertyWriteService.set(id, Property::setReadChannel, channelService.getById(channelId)); return propertyWriteService.set(id, (p, v) -> p.setReadChannel(channelService.getById(v)), channelId);
} }
@PostMapping("set/{id}/writeChannel") @PostMapping("set/{id}/writeChannel")
public PropertyDto setWriteChannel(@PathVariable final long id, @RequestBody(required = false) final Long channelId) { public PropertyDto setWriteChannel(@PathVariable final long id, @RequestBody(required = false) final Long channelId) {
return propertyWriteService.set(id, Property::setWriteChannel, channelService.getById(channelId)); return propertyWriteService.set(id, (p, v) -> p.setWriteChannel(channelService.getById(v)), channelId);
} }
@Override @Override

View File

@ -0,0 +1,21 @@
package de.ph87.homeautomation.property;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class PropertyEventListener {
private final PropertyWriteService propertyWriteService;
@EventListener(ApplicationStartedEvent.class)
public void onApplicationStarted() {
propertyWriteService.updateAllProperties();
}
}

View File

@ -15,7 +15,11 @@ public class PropertyMapper {
private final ChannelService channelService; private final ChannelService channelService;
public PropertyDto toDto(final Property property) { public PropertyDto toDto(final Property property) {
return new PropertyDto(property, channelService.toDtoAllowNull(property.getReadChannel()), channelService.toDtoAllowNull(property.getWriteChannel())); return new PropertyDto(
property,
channelService.toDtoAllowNull(property.getReadChannel()),
channelService.toDtoAllowNull(property.getWriteChannel())
);
} }
} }

View File

@ -1,17 +1,23 @@
package de.ph87.homeautomation.property; package de.ph87.homeautomation.property;
import de.ph87.homeautomation.channel.ChannelChangedEvent; import de.ph87.homeautomation.channel.ChannelDto;
import de.ph87.homeautomation.channel.ChannelService; import de.ph87.homeautomation.channel.ChannelService;
import de.ph87.homeautomation.channel.IChannelOwner;
import de.ph87.homeautomation.web.WebSocketService; import de.ph87.homeautomation.web.WebSocketService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionPhase; import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener; import org.springframework.transaction.event.TransactionalEventListener;
import java.util.List;
import java.util.Optional;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import static de.ph87.homeautomation.shared.Helpers.getCurrentTransactionName;
@Slf4j @Slf4j
@Service @Service
@Transactional @Transactional
@ -26,25 +32,42 @@ public class PropertyWriteService {
private final PropertyMapper propertyMapper; private final PropertyMapper propertyMapper;
private final WebSocketService webSocketService;
private final PropertyRepository propertyRepository; private final PropertyRepository propertyRepository;
public void write(final Property property, final double value) { private final WebSocketService webSocketService;
channelService.write(property, value);
private final ApplicationEventPublisher applicationEventPublisher;
public void updateAllProperties() {
propertyReadService.findAllByReadChannelNotNull().forEach(property -> {
final Optional<IChannelOwner> ownerOptional = channelService.findByChannel(property.getReadChannel());
if (ownerOptional.isPresent()) {
ownerOptional.get().requestUpdate(property.getReadChannel());
} else {
log.error("No Owner for Property: {}", property);
}
});
} }
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) @TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
public void channelChangedEventListener(final ChannelChangedEvent event) { // @Transactional(propagation = Propagation.REQUIRES_NEW)
propertyReadService.findAllByReadChannel_Id(event.getChannelId()) public void onChannelChanged(final ChannelDto dto) {
.forEach(property -> { log.debug("onChannelChanged [{}]: {}", getCurrentTransactionName(), dto.getTitle());
final List<Property> properties = propertyReadService.findAllByReadChannel_Id(dto.getId());
if (!properties.isEmpty()) {
properties.forEach(property -> {
property.setValue(property.getReadChannel().getValue()); property.setValue(property.getReadChannel().getValue());
property.setTimestamp(property.getReadChannel().getTimestamp()); property.setTimestamp(property.getReadChannel().getTimestamp());
log.debug("Updated Property from Channel: {}", property); log.debug("Updated Property \"{}\" by Channel \"{}\"", property.getTitle(), property.getReadChannel().getName());
publish(property, true); publish(property, true);
} }
); );
} }
}
public void writeToChannel(final Property property, final double value) {
channelService.write(property, value);
}
public PropertyDto create() { public PropertyDto create() {
final Property property = new Property(); final Property property = new Property();
@ -76,7 +99,9 @@ public class PropertyWriteService {
private PropertyDto publish(final Property property, final boolean existing) { private PropertyDto publish(final Property property, final boolean existing) {
final PropertyDto dto = propertyMapper.toDto(property); final PropertyDto dto = propertyMapper.toDto(property);
webSocketService.send(dto, existing); log.debug("Publish [{}]: {}", getCurrentTransactionName(), dto.getTitle());
applicationEventPublisher.publishEvent(dto);
webSocketService.send(PropertyDto.class, dto, existing);
return dto; return dto;
} }

View File

@ -44,7 +44,7 @@ public class SceneWriteService {
private SceneDto publish(final Scene scene, final boolean existing) { private SceneDto publish(final Scene scene, final boolean existing) {
final SceneDto dto = sceneMapper.toDto(scene); final SceneDto dto = sceneMapper.toDto(scene);
webSocketService.send(dto, existing); webSocketService.send(SceneDto.class, dto, existing);
return dto; return dto;
} }

View File

@ -31,7 +31,7 @@ public class ScheduleCalculationService {
private final ScheduleReadService scheduleReadService; private final ScheduleReadService scheduleReadService;
private final ApplicationEventPublisher eventPublisher; private final ApplicationEventPublisher applicationEventPublisher;
@EventListener(ApplicationStartedEvent.class) @EventListener(ApplicationStartedEvent.class)
public void calculateAllNext() { public void calculateAllNext() {
@ -49,7 +49,7 @@ public class ScheduleCalculationService {
} else { } else {
log.info("Next schedule for \"{}\": {}", schedule.getTitle(), nextEntry.get().getNextFuzzyTimestamp()); log.info("Next schedule for \"{}\": {}", schedule.getTitle(), nextEntry.get().getNextFuzzyTimestamp());
} }
eventPublisher.publishEvent(new ScheduleThreadWakeUpEvent()); applicationEventPublisher.publishEvent(new ScheduleThreadWakeUpEvent());
} }
private void calculateEntry(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) { private void calculateEntry(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) {

View File

@ -6,8 +6,6 @@ import org.springframework.web.bind.annotation.*;
import java.util.List; import java.util.List;
import static de.ph87.homeautomation.shared.Helpers.mapOrNull;
@RestController @RestController
@RequestMapping("schedule") @RequestMapping("schedule")
@RequiredArgsConstructor @RequiredArgsConstructor
@ -51,7 +49,7 @@ public class ScheduleController {
@PostMapping("set/{id}/property") @PostMapping("set/{id}/property")
public ScheduleDto setPropertyName(@PathVariable final long id, @RequestBody(required = false) final Long propertyId) { public ScheduleDto setPropertyName(@PathVariable final long id, @RequestBody(required = false) final Long propertyId) {
return scheduleWriteService.set(id, Schedule::setProperty, mapOrNull(propertyId, propertyReadService::getById)); return scheduleWriteService.set(id, (s, v) -> s.setProperty(v == null ? null : propertyReadService.getById(v)), propertyId);
} }
} }

View File

@ -41,7 +41,7 @@ public class ScheduleExecutionService {
private void executeEntry(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) { private void executeEntry(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) {
entry.setLastClearTimestamp(entry.getNextClearTimestamp()); entry.setLastClearTimestamp(entry.getNextClearTimestamp());
log.info("Executing Schedule \"{}\" Entry {}", schedule.getTitle(), entry); log.info("Executing Schedule \"{}\" Entry {}", schedule.getTitle(), entry);
propertyWriteService.write(schedule.getProperty(), entry.getValue()); propertyWriteService.writeToChannel(schedule.getProperty(), entry.getValue());
scheduleCalculationService.calculateSchedule(schedule, now); scheduleCalculationService.calculateSchedule(schedule, now);
} }

View File

@ -4,7 +4,6 @@ import de.ph87.homeautomation.schedule.entry.ScheduleEntryReadService;
import de.ph87.homeautomation.shared.AbstractThreadService; import de.ph87.homeautomation.shared.AbstractThreadService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.event.TransactionalEventListener; import org.springframework.transaction.event.TransactionalEventListener;
@ -46,9 +45,8 @@ public class ScheduleThreadService extends AbstractThreadService {
// nothing // nothing
} }
@EventListener(ScheduleThreadWakeUpEvent.class)
@TransactionalEventListener @TransactionalEventListener
public void wakeUp() { public void wakeUp(final ScheduleThreadWakeUpEvent event) {
_wakeUp(); _wakeUp();
} }

View File

@ -57,7 +57,7 @@ public class ScheduleWriteService {
private ScheduleDto publish(final Schedule schedule, final boolean existing) { private ScheduleDto publish(final Schedule schedule, final boolean existing) {
final ScheduleDto dto = scheduleMapper.toDto(schedule); final ScheduleDto dto = scheduleMapper.toDto(schedule);
webSocketService.send(dto, existing); webSocketService.send(ScheduleDto.class, dto, existing);
return dto; return dto;
} }

View File

@ -54,7 +54,7 @@ public class ScheduleEntryWriteService {
private ScheduleEntryDto publish(final ScheduleEntry entry, final boolean existing) { private ScheduleEntryDto publish(final ScheduleEntry entry, final boolean existing) {
final ScheduleEntryDto dto = scheduleEntryMapper.toDto(entry); final ScheduleEntryDto dto = scheduleEntryMapper.toDto(entry);
webSocketService.send(dto, existing); webSocketService.send(ScheduleEntryDto.class, dto, existing);
return dto; return dto;
} }

View File

@ -1,5 +1,7 @@
package de.ph87.homeautomation.shared; package de.ph87.homeautomation.shared;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
@ -62,4 +64,13 @@ public class Helpers {
return c; return c;
} }
public static String getCurrentTransactionName() {
final String fullName = TransactionSynchronizationManager.getCurrentTransactionName();
if (fullName == null) {
return null;
}
final String[] parts = fullName.split("\\.");
return parts[parts.length - 2] + "." + parts[parts.length - 1];
}
} }

View File

@ -17,12 +17,8 @@ public class WebSocketService {
private final SimpMessageSendingOperations simpMessageSendingOperations; private final SimpMessageSendingOperations simpMessageSendingOperations;
public void send(@NonNull final Serializable payload, final boolean existing) { public void send(@NonNull final Class<? extends Serializable> asClass, @NonNull final Serializable payload, final boolean existing) {
send(payload.getClass().getSimpleName(), payload, existing); final Message message = new Message(asClass.getSimpleName(), payload, existing);
}
public void send(@NonNull final String type, @NonNull final Serializable payload, final boolean existing) {
final Message message = new Message(type, payload, existing);
log.debug("Sending message via websocket: {}", message); log.debug("Sending message via websocket: {}", message);
simpMessageSendingOperations.convertAndSend(WebSocketConfig.DESTINATION_PREFIX, message); simpMessageSendingOperations.convertAndSend(WebSocketConfig.DESTINATION_PREFIX, message);
} }