REFACTOR: Property, Channel
This commit is contained in:
parent
875388e07c
commit
39d682b017
7
pom.xml
7
pom.xml
@ -48,9 +48,14 @@
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.20</version>
|
||||
<version>1.18.22</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.jsoup</groupId>
|
||||
<artifactId>jsoup</artifactId>
|
||||
<version>1.14.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.calimero</groupId>
|
||||
<artifactId>calimero-core</artifactId>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import {validateBooleanAllowNull, validateNumberAllowNull, validateNumberNotNull, validateStringNotEmptyNotNull, validateStringNullToEmpty} from "../validators";
|
||||
import {validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators";
|
||||
import {Property} from "../property/property.service";
|
||||
|
||||
export abstract class Device {
|
||||
@ -19,18 +19,14 @@ export abstract class Device {
|
||||
validateNumberNotNull(json['id']),
|
||||
validateStringNotEmptyNotNull(json['title']),
|
||||
type,
|
||||
validateStringNullToEmpty(json['getState']),
|
||||
validateStringNullToEmpty(json['setState']),
|
||||
validateBooleanAllowNull(json['state']),
|
||||
Property.fromJsonAllowNull(json['stateProperty']),
|
||||
);
|
||||
case "DeviceShutter":
|
||||
return new DeviceShutter(
|
||||
validateNumberNotNull(json['id']),
|
||||
validateStringNotEmptyNotNull(json['title']),
|
||||
type,
|
||||
validateStringNullToEmpty(json['getPercent']),
|
||||
validateStringNullToEmpty(json['setPercent']),
|
||||
validateNumberAllowNull(json['percent']),
|
||||
Property.fromJsonAllowNull(json['positionProperty']),
|
||||
);
|
||||
}
|
||||
throw new Error("No such type: " + type);
|
||||
@ -54,16 +50,14 @@ export class DeviceSwitch extends Device {
|
||||
id: number,
|
||||
title: string,
|
||||
type: string,
|
||||
public getState: string,
|
||||
public setState: string,
|
||||
public state: boolean | null,
|
||||
public stateProperty: Property | null,
|
||||
) {
|
||||
super(id, title, type);
|
||||
}
|
||||
|
||||
updateProperty(property: Property): void {
|
||||
if (this.getState === property.name) {
|
||||
this.state = property.booleanValue;
|
||||
if (this.stateProperty?.name === property.name) {
|
||||
this.stateProperty = property;
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,16 +69,14 @@ export class DeviceShutter extends Device {
|
||||
id: number,
|
||||
title: string,
|
||||
type: string,
|
||||
public getPercent: string,
|
||||
public setPercent: string,
|
||||
public percent: number | null,
|
||||
public positionProperty: Property | null,
|
||||
) {
|
||||
super(id, title, type);
|
||||
}
|
||||
|
||||
updateProperty(property: Property): void {
|
||||
if (this.getPercent === property.name) {
|
||||
this.percent = property.numberValue;
|
||||
if (this.positionProperty?.name === property.name) {
|
||||
this.positionProperty = property;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {ApiService, NO_OP} from "../api.service";
|
||||
import {validateBooleanAllowNull, validateDateAllowNull, validateNumberAllowNull, validateStringNotEmptyNotNull} from "../validators";
|
||||
import {validateDateAllowNull, validateNumberAllowNull, validateStringNotEmptyNotNull} from "../validators";
|
||||
import {ISearchService} from "../ISearchService";
|
||||
import {KeyValuePair} from "../KeyValuePair";
|
||||
import {Update} from "../Update";
|
||||
@ -10,10 +10,8 @@ export class Property {
|
||||
constructor(
|
||||
public name: string,
|
||||
public title: string,
|
||||
public propertyType: string,
|
||||
public booleanValue: boolean | null,
|
||||
public numberValue: number | null,
|
||||
public timestamp: Date | null,
|
||||
public value: number | null,
|
||||
public valueTimestamp: Date | null,
|
||||
) {
|
||||
// nothing
|
||||
}
|
||||
@ -29,10 +27,8 @@ export class Property {
|
||||
return new Property(
|
||||
validateStringNotEmptyNotNull(json['name']),
|
||||
validateStringNotEmptyNotNull(json['title']),
|
||||
validateStringNotEmptyNotNull(json['propertyType']),
|
||||
validateBooleanAllowNull(json['booleanValue']),
|
||||
validateNumberAllowNull(json['numberValue']),
|
||||
validateDateAllowNull(json['timestamp']),
|
||||
validateNumberAllowNull(json['value']),
|
||||
validateDateAllowNull(json['valueTimestamp']),
|
||||
);
|
||||
}
|
||||
|
||||
@ -69,8 +65,8 @@ export class PropertyService implements ISearchService {
|
||||
this.api.postReturnList("property/searchLike", term, KeyValuePair.fromJson, next, error);
|
||||
}
|
||||
|
||||
set(name: string, value: number, next: () => void = NO_OP, error: (error: any) => void = NO_OP): void {
|
||||
this.api.postReturnNone("property/set", {name: name, value: value}, next, error)
|
||||
set(property: Property, value: number, next: () => void = NO_OP, error: (error: any) => void = NO_OP): void {
|
||||
this.api.postReturnNone("property/set", {name: property.name, value: value}, next, error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -20,19 +20,19 @@
|
||||
<fa-icon [icon]="faEdit"></fa-icon>
|
||||
</div>
|
||||
<div class="controls">
|
||||
<div class="control button" (click)="setShutterPercent(device, 0)">
|
||||
<div class="control button" (click)="setShutterPosition(device, 0)">
|
||||
<span class="center">Auf</span>
|
||||
</div>
|
||||
<div class="control button" (click)="setShutterPercent(device, 40)">
|
||||
<div class="control button" (click)="setShutterPosition(device, 40)">
|
||||
<span class="center">50%</span>
|
||||
</div>
|
||||
<div class="control button" (click)="setShutterPercent(device, 75)">
|
||||
<div class="control button" (click)="setShutterPosition(device, 75)">
|
||||
<span class="center">90%</span>
|
||||
</div>
|
||||
<div class="control button" (click)="setShutterPercent(device, 85)">
|
||||
<div class="control button" (click)="setShutterPosition(device, 85)">
|
||||
<span class="center">Schlitze</span>
|
||||
</div>
|
||||
<div class="control button" (click)="setShutterPercent(device, 100)">
|
||||
<div class="control button" (click)="setShutterPosition(device, 100)">
|
||||
<span class="center">Zu</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -41,18 +41,18 @@ export class DeviceListComponent implements OnInit {
|
||||
|
||||
setSwitchState(d: Device, value: boolean): void {
|
||||
const device: DeviceSwitch = d as DeviceSwitch;
|
||||
if (!device.setState) {
|
||||
if (!device.stateProperty) {
|
||||
throw new Error("Property 'setState' not set for: " + device);
|
||||
}
|
||||
this.propertyService.set(device.setState, value ? 1 : 0);
|
||||
this.propertyService.set(device.stateProperty, value ? 1 : 0);
|
||||
}
|
||||
|
||||
setShutterPercent(d: Device, value: number): void {
|
||||
setShutterPosition(d: Device, value: number): void {
|
||||
const device: DeviceShutter = d as DeviceShutter;
|
||||
if (!device.setPercent) {
|
||||
throw new Error("Property 'setPercent' not set for: " + device);
|
||||
if (!device.positionProperty) {
|
||||
throw new Error("Property 'setPosition' not set for: " + device);
|
||||
}
|
||||
this.propertyService.set(device.setPercent, value);
|
||||
this.propertyService.set(device.positionProperty, value);
|
||||
}
|
||||
|
||||
create(): void {
|
||||
@ -75,16 +75,16 @@ export class DeviceListComponent implements OnInit {
|
||||
}
|
||||
|
||||
getSwitchClassList(device: Device): object {
|
||||
const value: boolean | null | undefined = (device as DeviceSwitch).state;
|
||||
const value: number | null | undefined = (device as DeviceSwitch).stateProperty?.value;
|
||||
return {
|
||||
switchOn: value === true,
|
||||
switchOff: value === false,
|
||||
switchOn: value === 1,
|
||||
switchOff: value === 0,
|
||||
switchUnknown: value === null || value === undefined,
|
||||
};
|
||||
}
|
||||
|
||||
getShutterClassList(device: Device): object {
|
||||
const value: number | null | undefined = (device as DeviceShutter).percent;
|
||||
const value: number | null | undefined = (device as DeviceShutter).positionProperty?.value;
|
||||
return {
|
||||
shutterOpen: value === 0,
|
||||
shutterBetween: value !== null && value !== undefined && value > 0 && value < 100,
|
||||
|
||||
@ -11,15 +11,9 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Zustand Lesen</th>
|
||||
<th>Eigenschaft</th>
|
||||
<td>
|
||||
<app-search [searchService]="propertyService" [initial]="deviceSwitch.getState" [showKey]="true" (valueChange)="setDeviceSwitch('getState', $event)"></app-search>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Zustand Schreiben</th>
|
||||
<td>
|
||||
<app-search [searchService]="propertyService" [initial]="deviceSwitch.setState" [showKey]="true" (valueChange)="setDeviceSwitch('setState', $event)"></app-search>
|
||||
<app-search [searchService]="propertyService" [initial]="deviceSwitch.stateProperty?.name" [showKey]="true" (valueChange)="setDeviceSwitch('stateProperty', $event)"></app-search>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -34,15 +28,9 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Position Lesen</th>
|
||||
<th>Eigenschaft</th>
|
||||
<td>
|
||||
<app-search [searchService]="propertyService" [initial]="deviceShutter.getPercent" [showKey]="true" (valueChange)="setDeviceShutter('getPercent', $event)"></app-search>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Position Schreiben</th>
|
||||
<td>
|
||||
<app-search [searchService]="propertyService" [initial]="deviceShutter.setPercent" [showKey]="true" (valueChange)="setDeviceShutter('setPercent', $event)"></app-search>
|
||||
<app-search [searchService]="propertyService" [initial]="deviceShutter.positionProperty?.name" [showKey]="true" (valueChange)="setDeviceShutter('positionProperty', $event)"></app-search>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
</td>
|
||||
<td colspan="9">
|
||||
<select [(ngModel)]="schedule.propertyType" (ngModelChange)="set(null,'propertyType', schedule.propertyType)">
|
||||
<option value="ON_OFF">An / Aus</option>
|
||||
<option value="SWITCH">An / Aus</option>
|
||||
<option value="PERCENT">Prozent</option>
|
||||
<option value="SHUTTER">Rollladen</option>
|
||||
<option value="SCENE">Szene</option>
|
||||
@ -137,7 +137,7 @@
|
||||
<td class="empty last"></td>
|
||||
</ng-container>
|
||||
|
||||
<td *ngIf="schedule.propertyType === 'ON_OFF'" [class.true]="entry.value" [class.false]="!entry.value" (click)="set(entry, 'value', entry.value > 0 ? 0 : 1)">
|
||||
<td *ngIf="schedule.propertyType === 'SWITCH'" [class.true]="entry.value" [class.false]="!entry.value" (click)="set(entry, 'value', entry.value > 0 ? 0 : 1)">
|
||||
{{entry.value ? "An" : "Aus"}}
|
||||
</td>
|
||||
<td *ngIf="schedule.propertyType === 'PERCENT'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
|
||||
|
||||
@ -24,7 +24,7 @@ export class SearchComponent<T> implements OnInit {
|
||||
searchService!: ISearchService;
|
||||
|
||||
@Input()
|
||||
initial!: string;
|
||||
initial?: string;
|
||||
|
||||
@Input()
|
||||
showKey: boolean = false;
|
||||
@ -65,7 +65,7 @@ export class SearchComponent<T> implements OnInit {
|
||||
}
|
||||
|
||||
start(): void {
|
||||
this.term = this.initial;
|
||||
this.term = this.initial || "";
|
||||
if (this.resultList && this.input) {
|
||||
this.resultList.style.left = this.input.style.left;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package de.ph87.homeautomation;
|
||||
|
||||
import de.ph87.homeautomation.knx.group.KnxGroupImportService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
@ -12,12 +13,15 @@ public class BackendApplication {
|
||||
|
||||
private final DemoDataService demoDataService;
|
||||
|
||||
private final KnxGroupImportService knxGroupImportService;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(BackendApplication.class);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
knxGroupImportService.importGroups();
|
||||
demoDataService.insertDemoData();
|
||||
}
|
||||
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
package de.ph87.homeautomation;
|
||||
|
||||
import com.luckycatlabs.sunrisesunset.Zenith;
|
||||
import de.ph87.homeautomation.channel.Channel;
|
||||
import de.ph87.homeautomation.device.DeviceRepository;
|
||||
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.KnxGroupRepository;
|
||||
import de.ph87.homeautomation.knx.group.KnxGroupWriteService;
|
||||
import de.ph87.homeautomation.knx.group.KnxGroupReadService;
|
||||
import de.ph87.homeautomation.property.Property;
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import de.ph87.homeautomation.property.PropertyRepository;
|
||||
import de.ph87.homeautomation.schedule.Schedule;
|
||||
import de.ph87.homeautomation.schedule.SchedulePropertyType;
|
||||
import de.ph87.homeautomation.schedule.ScheduleRepository;
|
||||
import de.ph87.homeautomation.schedule.entry.ScheduleEntry;
|
||||
import de.ph87.homeautomation.schedule.entry.ScheduleEntryType;
|
||||
@ -17,7 +17,6 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import tuwien.auto.calimero.GroupAddress;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@ -32,52 +31,39 @@ public class DemoDataService {
|
||||
|
||||
private static final Zenith BETWEEN_OFFICIAL_AND_CIVIL = new Zenith(93.0);
|
||||
|
||||
private final KnxGroupWriteService knxGroupWriteService;
|
||||
|
||||
private final ScheduleRepository scheduleRepository;
|
||||
|
||||
private final KnxGroupRepository knxGroupRepository;
|
||||
|
||||
private final DeviceWriteService deviceWriteService;
|
||||
|
||||
private final DeviceRepository deviceRepository;
|
||||
|
||||
private final PropertyRepository propertyRepository;
|
||||
|
||||
private final KnxGroupReadService knxGroupReadService;
|
||||
|
||||
public void insertDemoData() {
|
||||
final KnxGroup eg_flur_licht_schalten = createKnxGroupIfNotExists("EG Flur Licht Schalten", 0, 5, 14, "1.001", false, false);
|
||||
|
||||
final KnxGroup ambiente_eg_status = createKnxGroupIfNotExists("Ambiente EG Status", 0, 3, 81, "1.001", true, false);
|
||||
final KnxGroup ambiente_eg_schalten = createKnxGroupIfNotExists("Ambiente EG Schalten", 0, 3, 80, "1.001", false, false);
|
||||
|
||||
final KnxGroup ambiente_og_status = createKnxGroupIfNotExists("Ambiente OG Status", 0, 6, 2, "1.001", true, false);
|
||||
final KnxGroup ambiente_og_schalten = createKnxGroupIfNotExists("Ambiente OG Schalten", 0, 6, 3, "1.001", false, false);
|
||||
|
||||
final KnxGroup wohnzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Wohnzimmer Rollladen Position Anfahren", 0, 4, 24, "5.001", false, false);
|
||||
|
||||
final KnxGroup schlafzimmer_rollladen_position_anfahren = createKnxGroupIfNotExists("Schlafzimmer Rollladen Position Anfahren", 0, 3, 3, "5.001", false, false);
|
||||
|
||||
final KnxGroup flur_og_rollladen_position_anfahren = createKnxGroupIfNotExists("Flur Rollladen Position Anfahren", 0, 5, 13, "5.001", false, false);
|
||||
|
||||
final KnxGroup bad_licht_status = createKnxGroupIfNotExists("Bad Licht Status", 0, 5, 19, "1.001", true, false);
|
||||
final KnxGroup bad_licht_schalten = createKnxGroupIfNotExists("Bad Licht Schalten", 0, 3, 73, "1.001", false, false);
|
||||
|
||||
final KnxGroup bad_licht_mitte_status = createKnxGroupIfNotExists("Bad Licht Mitte Status", 0, 3, 30, "1.001", true, false);
|
||||
final KnxGroup bad_licht_mitte_schalten = createKnxGroupIfNotExists("Bad Licht Mitte Schalten", 0, 3, 29, "1.001", false, false);
|
||||
|
||||
final KnxGroup helligkeit = createKnxGroupIfNotExists("Helligkeit", 0, 5, 6, "9.004", false, true);
|
||||
|
||||
final KnxGroup szene_haus = createKnxGroupIfNotExists("Szene Haus", 0, 0, 21, "17.004", false, true);
|
||||
final Property ambiente_eg = createProperty("ambiente.eg", "Ambiente EG", knx(0, 3, 81), knx(0, 3, 80));
|
||||
final Property ambiente_og = createProperty("ambiente.og", "Ambiente OG", knx(0, 6, 2), knx(0, 6, 3));
|
||||
final Property bad_licht = createProperty("bad.licht", "Bad Licht", knx(0, 5, 19), knx(0, 3, 73));
|
||||
final Property bad_licht_mitte = createProperty("bad.licht.mitte", "Bad Licht Mitte", knx(0, 3, 30), knx(0, 3, 29));
|
||||
final Property flur_eg_licht = createProperty("flur.eg.licht", "Flur EG Licht", knx(0, 4, 8), knx(0, 5, 14));
|
||||
final Property wohnzimmer_rollladen = createProperty("wohnzimmer.rollladen", "Wohnzimmer Rollladen", null, knx(0, 4, 24));
|
||||
final Property schlafzimmer_rollladen = createProperty("schlafzimmer_rollladen", "Schlafzimmer Rollladen", null, knx(0, 3, 3));
|
||||
final Property flur_og_rollladen = createProperty("flur_og_rollladen", "Flur OG Rollladen", null, knx(0, 5, 13));
|
||||
final Property helligkeit = createProperty("helligkeit", "Helligkeit", knx(0, 5, 6), null);
|
||||
final Property szene_haus = createProperty("szene_haus", "Szene Haus ", null, knx(0, 0, 21));
|
||||
|
||||
if (deviceRepository.count() == 0) {
|
||||
createDeviceSwitch("Ambiente EG", ambiente_eg_status, ambiente_eg_schalten);
|
||||
createDeviceSwitch("Ambiente OG", ambiente_og_status, ambiente_og_schalten);
|
||||
createDeviceSwitch("Bad Licht", bad_licht_status, bad_licht_schalten);
|
||||
createDeviceShutter("Wohnzimmer Rollladen", null, wohnzimmer_rollladen_position_anfahren);
|
||||
createDeviceShutter("Schlafzimmer Rollladen", null, schlafzimmer_rollladen_position_anfahren);
|
||||
createDeviceShutter("Flur Rollladen", null, flur_og_rollladen_position_anfahren);
|
||||
deviceWriteService.createDeviceSwitch("Ambiente EG", ambiente_eg);
|
||||
deviceWriteService.createDeviceSwitch("Ambiente OG", ambiente_og);
|
||||
deviceWriteService.createDeviceSwitch("Bad Licht", bad_licht);
|
||||
deviceWriteService.createDeviceShutter("Wohnzimmer Rollladen", wohnzimmer_rollladen);
|
||||
deviceWriteService.createDeviceShutter("Schlafzimmer Rollladen", schlafzimmer_rollladen);
|
||||
deviceWriteService.createDeviceShutter("Flur Rollladen", flur_og_rollladen);
|
||||
}
|
||||
|
||||
if (scheduleRepository.count() == 0) {
|
||||
final Schedule scheduleEgFlurLicht = createSchedule(true, "EG Flur Licht", eg_flur_licht_schalten);
|
||||
final Schedule scheduleEgFlurLicht = createSchedule(true, "EG Flur Licht", flur_eg_licht, SchedulePropertyType.SWITCH);
|
||||
createTime(scheduleEgFlurLicht, true, 1, 0, 0, MIN30, true);
|
||||
createTime(scheduleEgFlurLicht, true, 2, 0, 0, MIN30, false);
|
||||
createTime(scheduleEgFlurLicht, true, 7, 30, 0, MIN30, true);
|
||||
@ -88,36 +74,36 @@ public class DemoDataService {
|
||||
createTime(scheduleEgFlurLicht, true, 20, 0, 0, MIN30, false);
|
||||
scheduleRepository.save(scheduleEgFlurLicht);
|
||||
|
||||
final Schedule scheduleEgAmbiente = createSchedule(false, "Ambiente EG", ambiente_eg_schalten);
|
||||
final Schedule scheduleEgAmbiente = createSchedule(false, "Ambiente EG", ambiente_eg, SchedulePropertyType.SWITCH);
|
||||
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_schalten);
|
||||
final Schedule scheduleOgAmbiente = createSchedule(false, "Ambiente OG", ambiente_og, SchedulePropertyType.SWITCH);
|
||||
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_position_anfahren);
|
||||
final Schedule scheduleWohnzimmerRollladen = createSchedule(true, "Rollläden Wohnzimmer", wohnzimmer_rollladen, SchedulePropertyType.SHUTTER);
|
||||
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_position_anfahren);
|
||||
final Schedule scheduleSchlafzimmerRollladen = createSchedule(true, "Rollläden Schlafzimmer", schlafzimmer_rollladen, SchedulePropertyType.SHUTTER);
|
||||
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_position_anfahren);
|
||||
final Schedule scheduleFlurRollladen = createSchedule(true, "Rollladen Flur", flur_og_rollladen, SchedulePropertyType.SHUTTER);
|
||||
createSunrise(scheduleFlurRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 0);
|
||||
createSunset(scheduleFlurRollladen, true, BETWEEN_OFFICIAL_AND_CIVIL, 0, 100);
|
||||
scheduleRepository.save(scheduleFlurRollladen);
|
||||
|
||||
final Schedule scheduleBadLichtMitte = createSchedule(false, "Bad Licht Mitte", bad_licht_mitte_schalten);
|
||||
final Schedule scheduleBadLichtMitte = createSchedule(false, "Bad Licht Mitte", bad_licht_mitte, SchedulePropertyType.SWITCH);
|
||||
createTime(scheduleBadLichtMitte, true, 10, 30, 0, MIN30, true);
|
||||
createTime(scheduleBadLichtMitte, true, 11, 30, 0, MIN30, false);
|
||||
createTime(scheduleBadLichtMitte, true, 15, 30, 0, MIN30, true);
|
||||
@ -128,7 +114,7 @@ public class DemoDataService {
|
||||
createTime(scheduleBadLichtMitte, true, 1, 0, 0, MIN30, false);
|
||||
scheduleRepository.save(scheduleBadLichtMitte);
|
||||
|
||||
final Schedule scheduleSzeneHaus = createSchedule(true, "Dekoration", szene_haus);
|
||||
final Schedule scheduleSzeneHaus = createSchedule(true, "Dekoration", szene_haus, SchedulePropertyType.SCENE);
|
||||
createTime(scheduleSzeneHaus, true, 6, 0, 0, 0, 31);
|
||||
createTime(scheduleSzeneHaus, true, 8, 30, 0, 0, 30);
|
||||
createSunset(scheduleSzeneHaus, true, Zenith.OFFICIAL, 0, 31);
|
||||
@ -137,28 +123,27 @@ public class DemoDataService {
|
||||
}
|
||||
}
|
||||
|
||||
private DeviceDto createDeviceSwitch(final String title, final Property getPercent, final Property setPercent) {
|
||||
return deviceWriteService.createDeviceSwitch(title, getPercent, setPercent);
|
||||
private KnxGroup knx(final int main, final int mid, final int sub) {
|
||||
return knxGroupReadService.getByAddress(main, mid, sub);
|
||||
}
|
||||
|
||||
private DeviceDto createDeviceShutter(final String title, final Property getPercent, final Property setPercent) {
|
||||
return deviceWriteService.createDeviceShutter(title, getPercent, setPercent);
|
||||
private Property createProperty(final String name, final String title, final Channel readChannel, final Channel writeChannel) {
|
||||
final Property property = propertyRepository.findByName(name).orElseGet(() -> propertyRepository.save(new Property(name)));
|
||||
property.setTitle(title);
|
||||
property.setReadChannel(readChannel);
|
||||
property.setWriteChannel(writeChannel);
|
||||
return property;
|
||||
}
|
||||
|
||||
private Schedule createSchedule(final boolean enabled, final String title, final PropertyDto propertyDto) {
|
||||
private Schedule createSchedule(final boolean enabled, final String title, final Property property, final SchedulePropertyType propertyType) {
|
||||
final Schedule schedule = new Schedule();
|
||||
schedule.setEnabled(enabled);
|
||||
schedule.setTitle(title);
|
||||
schedule.setPropertyName(propertyDto.getName());
|
||||
schedule.setPropertyType(propertyDto.getPropertyType());
|
||||
schedule.setProperty(property);
|
||||
schedule.setPropertyType(propertyType);
|
||||
return schedule;
|
||||
}
|
||||
|
||||
private KnxGroup createKnxGroupIfNotExists(final String name, final int main, final int mid, final int sub, final String dpt, final boolean readable, final boolean multiGroup) {
|
||||
final GroupAddress address = new GroupAddress(main, mid, sub);
|
||||
return knxGroupRepository.findByAddressRaw(address.getRawAddress()).orElseGet(() -> knxGroupWriteService.create(name, address, dpt, readable, multiGroup));
|
||||
}
|
||||
|
||||
private ScheduleEntry createRelative(final Schedule schedule, final boolean enabled, final int inSeconds, final int fuzzySeconds, final Object value) {
|
||||
final ZonedDateTime now = ZonedDateTime.now().plusSeconds(inSeconds).withNano(0);
|
||||
return createTime(schedule, enabled, now.getHour(), now.getMinute(), now.getSecond(), fuzzySeconds, value);
|
||||
|
||||
27
src/main/java/de/ph87/homeautomation/channel/Channel.java
Normal file
27
src/main/java/de/ph87/homeautomation/channel/Channel.java
Normal file
@ -0,0 +1,27 @@
|
||||
package de.ph87.homeautomation.channel;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@Entity
|
||||
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||
public abstract class Channel {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@Setter(AccessLevel.NONE)
|
||||
private Long id;
|
||||
|
||||
public abstract Class<? extends IChannelOwner> getChannelOwnerClass();
|
||||
|
||||
public abstract Double getValue();
|
||||
|
||||
public abstract ZonedDateTime getValueTimestamp();
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
package de.ph87.homeautomation.channel;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class ChannelChangedEvent {
|
||||
|
||||
private final long channelId;
|
||||
|
||||
public ChannelChangedEvent(final Channel channel) {
|
||||
this.channelId = channel.getId();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package de.ph87.homeautomation.channel;
|
||||
|
||||
import de.ph87.homeautomation.property.Property;
|
||||
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.Optional;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
public class ChannelService {
|
||||
|
||||
private final List<IChannelOwner> channelOwners;
|
||||
|
||||
public Optional<IChannelOwner> findByChannel(final Channel channel) {
|
||||
return channelOwners.stream().filter(owner -> channel.getChannelOwnerClass().isInstance(owner)).findFirst();
|
||||
}
|
||||
|
||||
public IChannelOwner getByChannel(final Channel channel) {
|
||||
return findByChannel(channel).orElseThrow(RuntimeException::new);
|
||||
}
|
||||
|
||||
public void write(final Property property, final double value) {
|
||||
final Channel channel = property.getWriteChannel();
|
||||
if (channel == null) {
|
||||
return;
|
||||
}
|
||||
getByChannel(channel).write(property, value);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
package de.ph87.homeautomation.channel;
|
||||
|
||||
import de.ph87.homeautomation.property.Property;
|
||||
|
||||
public interface IChannelOwner {
|
||||
|
||||
void write(final Property property, final double value);
|
||||
|
||||
}
|
||||
@ -2,13 +2,14 @@ package de.ph87.homeautomation.device;
|
||||
|
||||
import de.ph87.homeautomation.device.devices.Device;
|
||||
import de.ph87.homeautomation.device.devices.DeviceDto;
|
||||
import de.ph87.homeautomation.device.devices.DeviceShutter;
|
||||
import de.ph87.homeautomation.device.devices.DeviceSwitch;
|
||||
import de.ph87.homeautomation.property.PropertyReadService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static de.ph87.homeautomation.shared.Helpers.mapIfNotNull;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("device")
|
||||
@RequiredArgsConstructor
|
||||
@ -18,6 +19,8 @@ public class DeviceController {
|
||||
|
||||
private final DeviceWriteService deviceWriteService;
|
||||
|
||||
private final PropertyReadService propertyReadService;
|
||||
|
||||
@GetMapping("findAll")
|
||||
public List<DeviceDto> findAll() {
|
||||
return deviceReadService.findAll();
|
||||
@ -48,24 +51,14 @@ public class DeviceController {
|
||||
return deviceWriteService.set(id, Device::setTitle, title);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/DeviceSwitch/setState")
|
||||
public DeviceDto setDeviceSwitchSetState(@PathVariable final long id, @RequestBody(required = false) final String name) {
|
||||
return deviceWriteService.setDeviceSwitch(id, DeviceSwitch::setSetState, name);
|
||||
@PostMapping("set/{id}/DeviceSwitch/stateProperty")
|
||||
public DeviceDto setDeviceSwitchStateProperty(@PathVariable final long id, @RequestBody(required = false) final String name) {
|
||||
return deviceWriteService.setDeviceSwitch(id, (device, v) -> device.setStateProperty(mapIfNotNull(v, propertyReadService::getByName)), name);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/DeviceSwitch/getState")
|
||||
public DeviceDto setDeviceSwitchGetState(@PathVariable final long id, @RequestBody(required = false) final String name) {
|
||||
return deviceWriteService.setDeviceSwitch(id, DeviceSwitch::setGetState, name);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/DeviceShutter/setPercent")
|
||||
public DeviceDto setDeviceShutterSetPercent(@PathVariable final long id, @RequestBody(required = false) final String name) {
|
||||
return deviceWriteService.setDeviceShutter(id, DeviceShutter::setSetPercent, name);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/DeviceShutter/getPercent")
|
||||
public DeviceDto setDeviceShutterGetPercent(@PathVariable final long id, @RequestBody(required = false) final String name) {
|
||||
return deviceWriteService.setDeviceShutter(id, DeviceShutter::setGetPercent, name);
|
||||
@PostMapping("set/{id}/DeviceShutter/positionProperty")
|
||||
public DeviceDto setDeviceShutterPositionProperty(@PathVariable final long id, @RequestBody(required = false) final String name) {
|
||||
return deviceWriteService.setDeviceShutter(id, (device, v) -> device.setPositionProperty(mapIfNotNull(v, propertyReadService::getByName)), name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package de.ph87.homeautomation.device;
|
||||
|
||||
import de.ph87.homeautomation.device.devices.*;
|
||||
import de.ph87.homeautomation.property.Property;
|
||||
import de.ph87.homeautomation.property.PropertyMapper;
|
||||
import de.ph87.homeautomation.web.NotFoundException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -21,6 +21,8 @@ public class DeviceReadService {
|
||||
|
||||
private final DeviceRepository deviceRepository;
|
||||
|
||||
private final PropertyMapper propertyMapper;
|
||||
|
||||
public List<DeviceDto> findAll() {
|
||||
return deviceRepository.findAll().stream().map(this::toDto).collect(Collectors.toList());
|
||||
}
|
||||
@ -28,14 +30,12 @@ public class DeviceReadService {
|
||||
public DeviceDto toDto(final Device device) {
|
||||
if (device instanceof DeviceSwitch) {
|
||||
final DeviceSwitch deviceSwitch = (DeviceSwitch) device;
|
||||
final Boolean state = mapIfNotNull(deviceSwitch.getGetState(), Property::getBoolean);
|
||||
return new DeviceSwitchDto(deviceSwitch, mapIfNotNull(deviceSwitch.getGetState(), Property::getName), mapIfNotNull(deviceSwitch.getSetState(), Property::getName), state);
|
||||
return new DeviceSwitchDto(deviceSwitch, mapIfNotNull(deviceSwitch.getStateProperty(), propertyMapper::toDto));
|
||||
} else if (device instanceof DeviceShutter) {
|
||||
final DeviceShutter deviceShutter = (DeviceShutter) device;
|
||||
final Double percent = mapIfNotNull(deviceShutter.getGetPercent(), Property::getPercent);
|
||||
return new DeviceShutterDto(deviceShutter, mapIfNotNull(deviceShutter.getGetPercent(), Property::getName), mapIfNotNull(deviceShutter.getSetPercent(), Property::getName), percent);
|
||||
return new DeviceShutterDto(deviceShutter, mapIfNotNull(deviceShutter.getPositionProperty(), propertyMapper::toDto));
|
||||
}
|
||||
throw new RuntimeException("Not implemented: toDto(" + device + ")");
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
public Device getById(final long id) {
|
||||
|
||||
@ -5,7 +5,7 @@ import de.ph87.homeautomation.device.devices.DeviceDto;
|
||||
import de.ph87.homeautomation.device.devices.DeviceShutter;
|
||||
import de.ph87.homeautomation.device.devices.DeviceSwitch;
|
||||
import de.ph87.homeautomation.property.Property;
|
||||
import de.ph87.homeautomation.property.PropertyService;
|
||||
import de.ph87.homeautomation.property.PropertyWriteService;
|
||||
import de.ph87.homeautomation.schedule.ScheduleWriteService;
|
||||
import de.ph87.homeautomation.web.BadRequestException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -23,51 +23,26 @@ public class DeviceWriteService {
|
||||
|
||||
private final DeviceRepository deviceRepository;
|
||||
|
||||
private final PropertyService propertyService;
|
||||
private final PropertyWriteService propertyWriteService;
|
||||
|
||||
private final DeviceReadService deviceReadService;
|
||||
|
||||
public DeviceDto createDeviceSwitch(final String title, final Property getStatePropertyName, final Property setStatePropertyName) {
|
||||
public DeviceDto createDeviceSwitch(final String title, final Property stateProperty) {
|
||||
final DeviceSwitch deviceSwitch = new DeviceSwitch();
|
||||
deviceSwitch.setTitle(title);
|
||||
deviceSwitch.setGetState(getStatePropertyName);
|
||||
deviceSwitch.setSetState(setStatePropertyName);
|
||||
deviceSwitch.setStateProperty(stateProperty);
|
||||
deviceRepository.save(deviceSwitch);
|
||||
return deviceReadService.toDto(deviceSwitch);
|
||||
}
|
||||
|
||||
public DeviceDto createDeviceShutter(final String title, final Property getPercentPropertyName, final Property setPercentPropertyName) {
|
||||
public DeviceDto createDeviceShutter(final String title, final Property positionProperty) {
|
||||
final DeviceShutter deviceShutter = new DeviceShutter();
|
||||
deviceShutter.setTitle(title);
|
||||
deviceShutter.setGetPercent(getPercentPropertyName);
|
||||
deviceShutter.setSetPercent(setPercentPropertyName);
|
||||
deviceShutter.setPositionProperty(positionProperty);
|
||||
deviceRepository.save(deviceShutter);
|
||||
return deviceReadService.toDto(deviceShutter);
|
||||
}
|
||||
|
||||
public void set(final DeviceSetDto dto) {
|
||||
final Device device = deviceReadService.getById(dto.getId());
|
||||
if (device instanceof DeviceSwitch) {
|
||||
setSwitch((DeviceSwitch) device, dto.getProperty(), dto.getValue());
|
||||
} else if (device instanceof DeviceShutter) {
|
||||
setShutter((DeviceShutter) device, dto.getProperty(), dto.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void setSwitch(final DeviceSwitch device, final String property, final double value) {
|
||||
switch (property) {
|
||||
case "switch":
|
||||
propertyService.set(device.getSetState(), value);
|
||||
}
|
||||
}
|
||||
|
||||
private void setShutter(final DeviceShutter device, final String property, final double value) {
|
||||
switch (property) {
|
||||
case "percent":
|
||||
propertyService.set(device.getSetPercent(), value);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> DeviceDto set(final long id, final BiConsumer<Device, T> setter, final T value) {
|
||||
final Device device = deviceReadService.getById(id);
|
||||
setter.accept(device, value);
|
||||
@ -99,9 +74,9 @@ public class DeviceWriteService {
|
||||
public DeviceDto create(final String type) {
|
||||
switch (type) {
|
||||
case "DeviceSwitch":
|
||||
return createDeviceSwitch(generateUnusedTitle(), null, null);
|
||||
return createDeviceSwitch(generateUnusedTitle(), null);
|
||||
case "DeviceShutter":
|
||||
return createDeviceShutter(generateUnusedTitle(), null, null);
|
||||
return createDeviceShutter(generateUnusedTitle(), null);
|
||||
}
|
||||
throw new RuntimeException("Not implemented type: " + type);
|
||||
}
|
||||
|
||||
@ -15,9 +15,6 @@ import javax.persistence.ManyToOne;
|
||||
public class DeviceShutter extends Device {
|
||||
|
||||
@ManyToOne
|
||||
private Property getPercent;
|
||||
|
||||
@ManyToOne
|
||||
private Property setPercent;
|
||||
private Property positionProperty;
|
||||
|
||||
}
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
package de.ph87.homeautomation.device.devices;
|
||||
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class DeviceShutterDto extends DeviceDto {
|
||||
|
||||
public final String getPercent;
|
||||
public final PropertyDto positionProperty;
|
||||
|
||||
public final String setPercent;
|
||||
|
||||
public final Double percent;
|
||||
|
||||
public DeviceShutterDto(final DeviceShutter device, final String getPercent, final String setPercent, final Double percent) {
|
||||
public DeviceShutterDto(final DeviceShutter device, final PropertyDto positionProperty) {
|
||||
super(device);
|
||||
this.getPercent = getPercent;
|
||||
this.setPercent = setPercent;
|
||||
this.percent = percent;
|
||||
this.positionProperty = positionProperty;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -15,9 +15,6 @@ import javax.persistence.ManyToOne;
|
||||
public class DeviceSwitch extends Device {
|
||||
|
||||
@ManyToOne
|
||||
private Property setState;
|
||||
|
||||
@ManyToOne
|
||||
private Property getState;
|
||||
private Property stateProperty;
|
||||
|
||||
}
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
package de.ph87.homeautomation.device.devices;
|
||||
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class DeviceSwitchDto extends DeviceDto {
|
||||
|
||||
public final String getState;
|
||||
public final PropertyDto stateProperty;
|
||||
|
||||
public final String setState;
|
||||
|
||||
public final Boolean state;
|
||||
|
||||
public DeviceSwitchDto(final DeviceSwitch device, final String getState, final String setState, final Boolean state) {
|
||||
public DeviceSwitchDto(final DeviceSwitch device, final PropertyDto stateProperty) {
|
||||
super(device);
|
||||
this.getState = getState;
|
||||
this.setState = setState;
|
||||
this.state = state;
|
||||
this.stateProperty = stateProperty;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -131,14 +131,14 @@ public class KnxThreadService extends AbstractThreadService implements NetworkLi
|
||||
@Override
|
||||
public void groupReadResponse(final ProcessEvent processEvent) {
|
||||
synchronized (databaseAccessLock) {
|
||||
knxGroupWriteService.updateIfExists(processEvent.getDestination().getRawAddress(), processEvent.getASDU(), processEvent.getSourceAddr());
|
||||
knxGroupWriteService.setReceivedData(processEvent.getDestination(), processEvent.getASDU(), processEvent.getSourceAddr());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void groupWrite(final ProcessEvent processEvent) {
|
||||
synchronized (databaseAccessLock) {
|
||||
knxGroupWriteService.updateIfExists(processEvent.getDestination().getRawAddress(), processEvent.getASDU(), processEvent.getSourceAddr());
|
||||
knxGroupWriteService.setReceivedData(processEvent.getDestination(), processEvent.getASDU(), processEvent.getSourceAddr());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,24 +1,21 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import de.ph87.homeautomation.channel.Channel;
|
||||
import de.ph87.homeautomation.channel.IChannelOwner;
|
||||
import lombok.*;
|
||||
import tuwien.auto.calimero.GroupAddress;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
public class KnxGroup {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@Setter(AccessLevel.NONE)
|
||||
private Long id;
|
||||
@NoArgsConstructor
|
||||
public class KnxGroup extends Channel {
|
||||
|
||||
@Setter(AccessLevel.NONE)
|
||||
@Column(nullable = false, unique = true)
|
||||
@ -28,45 +25,37 @@ public class KnxGroup {
|
||||
@Column(nullable = false, unique = true)
|
||||
private String addressStr;
|
||||
|
||||
@Setter(AccessLevel.NONE)
|
||||
@Column(nullable = false, unique = true)
|
||||
private String propertyName;
|
||||
private int dptMain;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String dpt;
|
||||
private int dptSub;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String title;
|
||||
private String name;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private PropertyType propertyType;
|
||||
private String description;
|
||||
|
||||
private byte[] value;
|
||||
private int puid;
|
||||
|
||||
private int lastDeviceAddressRaw;
|
||||
private boolean ets;
|
||||
|
||||
private String lastDeviceAddressString;
|
||||
@Embedded
|
||||
private KnxTelegram lastTelegram;
|
||||
|
||||
private Boolean booleanValue;
|
||||
|
||||
private Double numberValue;
|
||||
private Double value;
|
||||
|
||||
private ZonedDateTime valueTimestamp;
|
||||
|
||||
private byte[] sendValue;
|
||||
|
||||
private int readInterval;
|
||||
|
||||
@Column(nullable = false)
|
||||
private boolean multiGroup;
|
||||
|
||||
@Embedded
|
||||
private KnxGroupLinkInfo read = new KnxGroupLinkInfo();
|
||||
|
||||
private byte[] sendValue;
|
||||
|
||||
@Embedded
|
||||
private KnxGroupLinkInfo send = new KnxGroupLinkInfo();
|
||||
|
||||
public KnxGroup(final GroupAddress address) {
|
||||
setAddress(address);
|
||||
}
|
||||
|
||||
public void setAddress(final int rawAddress) {
|
||||
setAddress(new GroupAddress(rawAddress));
|
||||
}
|
||||
@ -74,11 +63,19 @@ public class KnxGroup {
|
||||
public void setAddress(final GroupAddress groupAddress) {
|
||||
this.addressRaw = groupAddress.getRawAddress();
|
||||
this.addressStr = groupAddress.toString();
|
||||
this.propertyName = "knx.group." + groupAddress.getMainGroup() + "." + groupAddress.getMiddleGroup() + "." + groupAddress.getSubGroup8();
|
||||
}
|
||||
|
||||
public GroupAddress getAddress() {
|
||||
return new GroupAddress(addressRaw);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IChannelOwner> getChannelOwnerClass() {
|
||||
return KnxGroupChannelOwnerService.class;
|
||||
}
|
||||
|
||||
public String getDpt() {
|
||||
return String.format("%d.%03d", dptMain, dptSub);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import de.ph87.homeautomation.channel.IChannelOwner;
|
||||
import de.ph87.homeautomation.property.Property;
|
||||
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 KnxGroupChannelOwnerService implements IChannelOwner {
|
||||
|
||||
private final KnxGroupWriteService knxGroupWriteService;
|
||||
|
||||
@Override
|
||||
public void write(final Property property, final double value) {
|
||||
if (!(property.getWriteChannel() instanceof KnxGroup)) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
final KnxGroup knxGroup = (KnxGroup) property.getWriteChannel();
|
||||
knxGroupWriteService.setSendValue(knxGroup, value);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class KnxGroupDto {
|
||||
|
||||
public final long id;
|
||||
|
||||
public final PropertyDto property;
|
||||
|
||||
public final int addressRaw;
|
||||
|
||||
public final String addressStr;
|
||||
|
||||
public final String dpt;
|
||||
|
||||
public KnxGroupDto(final KnxGroup knxGroup) {
|
||||
this.property = new PropertyDto(knxGroup.getPropertyName(), knxGroup.getTitle(), knxGroup.getPropertyType(), knxGroup.getBooleanValue(), knxGroup.getNumberValue(), knxGroup.getValueTimestamp());
|
||||
this.id = knxGroup.getId();
|
||||
this.addressRaw = knxGroup.getAddressRaw();
|
||||
this.addressStr = knxGroup.getAddressStr();
|
||||
this.dpt = knxGroup.getDpt();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
public class KnxGroupFormatException extends Exception {
|
||||
|
||||
public KnxGroupFormatException(final KnxGroup knxGroup, final double value, final String reason) {
|
||||
super(String.format("Cannot use value %f (%s) to set KnxGroup: %s", value, reason, knxGroup));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import tuwien.auto.calimero.GroupAddress;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
public class KnxGroupImportService {
|
||||
|
||||
private final KnxGroupRepository knxGroupRepository;
|
||||
|
||||
public void importGroups() {
|
||||
knxGroupRepository.findAll().forEach(knxGroup -> knxGroup.setEts(false));
|
||||
try {
|
||||
Jsoup.parse(new File("/home/patrick/Zuhause-ETS5/G"), "UTF-8").select("GA").forEach(this::importGroup);
|
||||
} catch (IOException e) {
|
||||
log.error("Failed to import KnxGroups: {}", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void importGroup(final Element ga) {
|
||||
final GroupAddress address = new GroupAddress(Integer.parseInt(ga.attr("Address")));
|
||||
final KnxGroup knxGroup = knxGroupRepository.findByAddressRaw(address.getRawAddress()).orElseGet(() -> knxGroupRepository.save(new KnxGroup(address)));
|
||||
setDpt(knxGroup, ga.attr("DatapointType"));
|
||||
knxGroup.setName(ga.attr("Name"));
|
||||
knxGroup.setDescription(ga.attr("Description"));
|
||||
knxGroup.setPuid(Integer.parseInt(ga.attr("Puid")));
|
||||
knxGroup.setEts(true);
|
||||
}
|
||||
|
||||
private void setDpt(final KnxGroup knxGroup, final String dptString) {
|
||||
final Matcher matcher = Pattern.compile("^DPST-(?<main>\\d+)-(?<sub>\\d+)$").matcher(dptString);
|
||||
if (!matcher.matches()) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
knxGroup.setDptMain(Integer.parseInt(matcher.group("main")));
|
||||
knxGroup.setDptSub(Integer.parseInt(matcher.group("sub")));
|
||||
}
|
||||
|
||||
}
|
||||
@ -43,7 +43,7 @@ public class KnxGroupLinkService {
|
||||
private boolean send(final ProcessCommunicatorImpl processCommunicator, final KnxGroup knxGroup) throws KNXException {
|
||||
try {
|
||||
log.debug("Sending KnxGroup: {}", knxGroup);
|
||||
processCommunicator.write(knxGroup.getAddress(), TranslatorTypes.createTranslator(knxGroup.getDpt(), knxGroup.getSendValue()));
|
||||
processCommunicator.write(knxGroup.getAddress(), TranslatorTypes.createTranslator(knxGroup.getDptMain(), knxGroup.getDptSub(), knxGroup.getSendValue()));
|
||||
knxGroup.getSend().setErrorCount(0);
|
||||
knxGroup.getSend().setErrorMessage(null);
|
||||
knxGroup.getSend().setNextTimestamp(null);
|
||||
@ -64,11 +64,7 @@ public class KnxGroupLinkService {
|
||||
processCommunicator.read(createStateDP(knxGroup));
|
||||
knxGroup.getRead().setErrorCount(0);
|
||||
knxGroup.getRead().setErrorMessage(null);
|
||||
if (knxGroup.getReadInterval() > 0) {
|
||||
knxGroup.getRead().setNextTimestamp(align(knxGroup.getReadInterval()));
|
||||
} else {
|
||||
knxGroup.getRead().setNextTimestamp(null);
|
||||
}
|
||||
return true;
|
||||
} catch (KNXFormatException e) {
|
||||
log.error(e.toString());
|
||||
@ -88,8 +84,7 @@ public class KnxGroupLinkService {
|
||||
|
||||
private StateDP createStateDP(final KnxGroup knxGroup) {
|
||||
final GroupAddress groupAddress = knxGroup.getAddress();
|
||||
final int mainNumber = Integer.parseInt(knxGroup.getDpt().split("\\.", 2)[0]);
|
||||
return new StateDP(groupAddress, groupAddress.toString(), mainNumber, knxGroup.getDpt());
|
||||
return new StateDP(groupAddress, groupAddress.toString(), knxGroup.getDptMain(), knxGroup.getDpt());
|
||||
}
|
||||
|
||||
public ZonedDateTime getNextTimestamp() {
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
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 KnxGroupMapperService {
|
||||
|
||||
public PropertyDto toPropertyDto(final KnxGroup knxGroup) {
|
||||
return new PropertyDto(knxGroup.getPropertyName(), knxGroup.getTitle(), knxGroup.getPropertyType(), knxGroup.getBooleanValue(), knxGroup.getNumberValue(), knxGroup.getValueTimestamp());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,90 +0,0 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import de.ph87.homeautomation.property.IPropertyOwner;
|
||||
import de.ph87.homeautomation.property.PropertyDto;
|
||||
import de.ph87.homeautomation.property.PropertySetException;
|
||||
import lombok.Getter;
|
||||
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 tuwien.auto.calimero.GroupAddress;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.ph87.homeautomation.shared.Helpers.quoteOrNull;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
public class KnxGroupOwnerService implements IPropertyOwner {
|
||||
|
||||
@Getter
|
||||
private final Pattern propertyNamePattern = Pattern.compile("^knx\\.group\\.(\\d+)\\.(\\d+)\\.(\\d+)$");
|
||||
|
||||
private final KnxGroupWriteService knxGroupWriteService;
|
||||
|
||||
private final KnxGroupRepository knxGroupRepository;
|
||||
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
private final KnxGroupMapperService knxGroupMapperService;
|
||||
|
||||
@Override
|
||||
public void setProperty(final String propertyName, final double value) throws PropertySetException {
|
||||
final GroupAddress groupAddress = parseGroupAddress(propertyName);
|
||||
try {
|
||||
if (knxGroupWriteService.setSendValue(groupAddress, value)) {
|
||||
eventPublisher.publishEvent(new KnxThreadWakeUpEvent());
|
||||
} else {
|
||||
log.error("No such KnxGroup.address = {}", groupAddress);
|
||||
}
|
||||
} catch (KnxGroupFormatException e) {
|
||||
throw new PropertySetException(propertyName, value, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean readBoolean(final String propertyName) {
|
||||
return knxGroupRepository.findByAddressRaw(parseGroupAddress(propertyName).getRawAddress()).map(KnxGroup::getBooleanValue).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Double readNumber(final String propertyName) {
|
||||
return knxGroupRepository.findByAddressRaw(parseGroupAddress(propertyName).getRawAddress()).map(KnxGroup::getNumberValue).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyDto> findAllProperties() {
|
||||
return knxGroupRepository.findAll().stream().map(knxGroupMapperService::toPropertyDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PropertyDto> findAllPropertiesLike(final String like) {
|
||||
return knxGroupRepository.findAllByPropertyNameLikeIgnoreCaseOrTitleLikeIgnoreCase(like, like).stream().map(knxGroupMapperService::toPropertyDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<PropertyDto> findPropertyDtoByPropertyName(final String propertyName) {
|
||||
return findKnxGroupByPropertyName(propertyName).map(knxGroupMapperService::toPropertyDto);
|
||||
}
|
||||
|
||||
private Optional<KnxGroup> findKnxGroupByPropertyName(final String propertyName) {
|
||||
return knxGroupRepository.findByPropertyName(propertyName);
|
||||
}
|
||||
|
||||
private GroupAddress parseGroupAddress(final String propertyName) {
|
||||
final Matcher matcher = propertyNamePattern.matcher(propertyName);
|
||||
if (matcher.matches()) {
|
||||
return new GroupAddress(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), Integer.parseInt(matcher.group(3)));
|
||||
}
|
||||
throw new RuntimeException("Cannot parse GroupAddress from propertyName: " + quoteOrNull(propertyName));
|
||||
}
|
||||
|
||||
}
|
||||
@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import tuwien.auto.calimero.GroupAddress;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -11,4 +12,10 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
@RequiredArgsConstructor
|
||||
public class KnxGroupReadService {
|
||||
|
||||
private final KnxGroupRepository knxGroupRepository;
|
||||
|
||||
public KnxGroup getByAddress(final int main, final int mid, final int sub) {
|
||||
return knxGroupRepository.findByAddressRaw(new GroupAddress(main, mid, sub).getRawAddress()).orElseThrow(RuntimeException::new);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface KnxGroupRepository extends CrudRepository<KnxGroup, Long> {
|
||||
public interface KnxGroupRepository extends CrudRepository<KnxGroup, String> {
|
||||
|
||||
Optional<KnxGroup> findByAddressRaw(int rawAddress);
|
||||
|
||||
@ -16,14 +16,8 @@ public interface KnxGroupRepository extends CrudRepository<KnxGroup, Long> {
|
||||
|
||||
Optional<KnxGroup> findFirstByRead_NextTimestampLessThanEqualOrderByRead_NextTimestampAsc(ZonedDateTime timestamp);
|
||||
|
||||
List<KnxGroup> findAllByRead_AbleTrue();
|
||||
|
||||
Optional<KnxGroup> findFirstByRead_NextTimestampNotNullOrderByRead_NextTimestampAsc();
|
||||
|
||||
boolean existsByAddressRaw(int rawAddress);
|
||||
|
||||
List<KnxGroup> findAllByPropertyNameLikeIgnoreCaseOrTitleLikeIgnoreCase(String propertyNameLike, final String titleLike);
|
||||
|
||||
Optional<KnxGroup> findByPropertyName(String propertyName);
|
||||
|
||||
}
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import de.ph87.homeautomation.channel.ChannelChangedEvent;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import tuwien.auto.calimero.GroupAddress;
|
||||
import tuwien.auto.calimero.IndividualAddress;
|
||||
@ -16,12 +14,11 @@ import tuwien.auto.calimero.dptxlator.*;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
public class KnxGroupWriteService {
|
||||
|
||||
@ -29,82 +26,9 @@ public class KnxGroupWriteService {
|
||||
|
||||
private final ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
private final KnxGroupMapperService knxGroupMapperService;
|
||||
|
||||
@EventListener(ApplicationStartedEvent.class)
|
||||
public void markAllForRead() {
|
||||
knxGroupRepository.findAllByRead_AbleTrue().forEach(knxGroup -> knxGroup.getRead().setNextTimestamp(ZonedDateTime.now()));
|
||||
eventPublisher.publishEvent(new KnxThreadWakeUpEvent());
|
||||
}
|
||||
|
||||
public void updateIfExists(final int rawAddress, final byte[] data, final IndividualAddress knxDeviceAddress) {
|
||||
final Optional<KnxGroup> knxGroupOptional = knxGroupRepository.findByAddressRaw(rawAddress);
|
||||
if (knxGroupOptional.isEmpty()) {
|
||||
log.debug("No KnxGroup with address={}", new GroupAddress(rawAddress));
|
||||
}
|
||||
knxGroupOptional.ifPresent(knxGroup -> {
|
||||
knxGroup.setValue(data);
|
||||
knxGroup.setLastDeviceAddressRaw(knxDeviceAddress.getRawAddress());
|
||||
knxGroup.setLastDeviceAddressString(knxDeviceAddress.toString());
|
||||
knxGroup.setValueTimestamp(ZonedDateTime.now());
|
||||
knxGroup.setBooleanValue(null);
|
||||
knxGroup.setNumberValue(null);
|
||||
public void setSendValue(final KnxGroup knxGroup, final double value) {
|
||||
findTranslator(knxGroup).ifPresent(translator -> {
|
||||
try {
|
||||
final DPTXlator translator = findTranslator(knxGroup);
|
||||
translator.setData(data);
|
||||
translate(DPTXlatorBoolean.class, translator, value -> setBooleanValue(knxGroup, value), DPTXlatorBoolean::getValueBoolean);
|
||||
translate(DPTXlator8BitUnsigned.class, translator, knxGroup::setNumberValue, DPTXlator8BitUnsigned::getNumericValue);
|
||||
translate(DPTXlator2ByteFloat.class, translator, knxGroup::setNumberValue, DPTXlator2ByteFloat::getNumericValue);
|
||||
translate(DPTXlator2ByteUnsigned.class, translator, knxGroup::setNumberValue, DPTXlator2ByteUnsigned::getNumericValue);
|
||||
translate(DPTXlator4ByteFloat.class, translator, knxGroup::setNumberValue, DPTXlator4ByteFloat::getNumericValue);
|
||||
translate(DPTXlator4ByteSigned.class, translator, knxGroup::setNumberValue, DPTXlator4ByteSigned::getNumericValue);
|
||||
translate(DPTXlator4ByteUnsigned.class, translator, knxGroup::setNumberValue, DPTXlator4ByteUnsigned::getNumericValue);
|
||||
translate(DPTXlator8BitSigned.class, translator, knxGroup::setNumberValue, DPTXlator8BitSigned::getNumericValue);
|
||||
translate(DPTXlator64BitSigned.class, translator, knxGroup::setNumberValue, DPTXlator64BitSigned::getNumericValue);
|
||||
translate(DPTXlatorSceneNumber.class, translator, knxGroup::setNumberValue, DPTXlatorSceneNumber::getNumericValue);
|
||||
// TODO implement all DPTXlator...
|
||||
} catch (NoTranslatorException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
log.debug("KnxGroup updated: {}", knxGroup);
|
||||
});
|
||||
}
|
||||
|
||||
private void setBooleanValue(final KnxGroup knxGroup, final Boolean value) {
|
||||
knxGroup.setBooleanValue(value);
|
||||
if (value == null) {
|
||||
knxGroup.setNumberValue(null);
|
||||
} else {
|
||||
knxGroup.setNumberValue(value ? 1.0 : 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
private <X extends DPTXlator, T> void translate(final Class<X> dptXlatorClass, final DPTXlator translator, final Consumer<T> setter, final Function<X, T> getter) {
|
||||
if (dptXlatorClass.isInstance(translator)) {
|
||||
setter.accept(getter.apply(dptXlatorClass.cast(translator)));
|
||||
}
|
||||
}
|
||||
|
||||
public KnxGroup create(final String name, final GroupAddress address, final String dpt, final boolean readable, final boolean multiGroup) {
|
||||
final KnxGroup trans = new KnxGroup();
|
||||
trans.setAddress(address);
|
||||
trans.setDpt(dpt);
|
||||
trans.setMultiGroup(multiGroup);
|
||||
trans.setTitle(name);
|
||||
trans.getRead().setAble(readable);
|
||||
return knxGroupRepository.save(trans);
|
||||
}
|
||||
|
||||
public boolean setSendValue(final GroupAddress groupAddress, final double value) throws KnxGroupFormatException {
|
||||
final Optional<KnxGroup> knxGroupOptional = knxGroupRepository.findByAddressRaw(groupAddress.getRawAddress());
|
||||
if (knxGroupOptional.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
final KnxGroup knxGroup = knxGroupOptional.get();
|
||||
try {
|
||||
final DPTXlator translator = findTranslator(knxGroup);
|
||||
if (translator instanceof DPTXlatorBoolean) {
|
||||
((DPTXlatorBoolean) translator).setValue(value == 1.0);
|
||||
} else if (translator instanceof DPTXlator8BitUnsigned) {
|
||||
@ -112,24 +36,67 @@ public class KnxGroupWriteService {
|
||||
} else { // TODO implement all DPTXlator...
|
||||
translator.setValue("" + value);
|
||||
}
|
||||
knxGroup.setSendValue(translator.getData());
|
||||
knxGroup.getSend().setNextTimestamp(ZonedDateTime.now());
|
||||
return true;
|
||||
} catch (NoTranslatorException | KNXFormatException e) {
|
||||
throw new KnxGroupFormatException(knxGroup, value, e.getMessage());
|
||||
knxGroup.setSendValue(translator.getData());
|
||||
applicationEventPublisher.publishEvent(new KnxThreadWakeUpEvent());
|
||||
} catch (KNXFormatException e) {
|
||||
log.error("Failed set value \"{}\" to DptXlator {} for KnxGroup {}", value, translator, knxGroup);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private DPTXlator findTranslator(final KnxGroup knxGroup) throws NoTranslatorException {
|
||||
if (knxGroup.getDpt() == null) {
|
||||
throw new NoTranslatorException("Missing DPT");
|
||||
public void setReceivedData(final GroupAddress groupAddress, final byte[] data, final IndividualAddress knxDeviceAddress) {
|
||||
final Optional<KnxGroup> knxGroupOptional = knxGroupRepository.findByAddressRaw(groupAddress.getRawAddress());
|
||||
if (knxGroupOptional.isEmpty()) {
|
||||
log.error("No KnxGroup with address={}", groupAddress);
|
||||
return;
|
||||
}
|
||||
final int mainNumber = Integer.parseInt(knxGroup.getDpt().split("\\.")[0]);
|
||||
final KnxGroup knxGroup = knxGroupOptional.get();
|
||||
knxGroup.setLastTelegram(new KnxTelegram(data, ZonedDateTime.now(), knxDeviceAddress));
|
||||
translate(knxGroup);
|
||||
}
|
||||
|
||||
private void translate(final KnxGroup knxGroup) {
|
||||
findTranslator(knxGroup).ifPresent(translator -> {
|
||||
translator.setData(knxGroup.getLastTelegram().getData());
|
||||
final Optional<Double> valueOptional = translate(DPTXlatorBoolean.class, translator, DPTXlatorBoolean::getNumericValue)
|
||||
.or(() -> translate(DPTXlator8BitUnsigned.class, translator, DPTXlator8BitUnsigned::getNumericValue))
|
||||
.or(() -> translate(DPTXlator2ByteFloat.class, translator, DPTXlator2ByteFloat::getNumericValue))
|
||||
.or(() -> translate(DPTXlator2ByteUnsigned.class, translator, DPTXlator2ByteUnsigned::getNumericValue))
|
||||
.or(() -> translate(DPTXlator4ByteFloat.class, translator, DPTXlator4ByteFloat::getNumericValue))
|
||||
.or(() -> translate(DPTXlator4ByteSigned.class, translator, DPTXlator4ByteSigned::getNumericValue))
|
||||
.or(() -> translate(DPTXlator4ByteUnsigned.class, translator, DPTXlator4ByteUnsigned::getNumericValue))
|
||||
.or(() -> translate(DPTXlator8BitSigned.class, translator, DPTXlator8BitSigned::getNumericValue))
|
||||
.or(() -> translate(DPTXlator64BitSigned.class, translator, DPTXlator64BitSigned::getNumericValue))
|
||||
.or(() -> translate(DPTXlatorSceneNumber.class, translator, DPTXlatorSceneNumber::getNumericValue));
|
||||
// TODO implement all DPTXlator...
|
||||
if (valueOptional.isPresent()) {
|
||||
knxGroup.setValue(valueOptional.get());
|
||||
knxGroup.setValueTimestamp(ZonedDateTime.now());
|
||||
log.debug("KnxGroup updated: {}", knxGroup);
|
||||
applicationEventPublisher.publishEvent(new ChannelChangedEvent(knxGroup));
|
||||
} else {
|
||||
log.error("Failed to get value from DptXlator {} for KnxGroup {}", translator, knxGroup);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Optional<DPTXlator> findTranslator(final KnxGroup knxGroup) {
|
||||
try {
|
||||
return TranslatorTypes.createTranslator(mainNumber, knxGroup.getDpt());
|
||||
return Optional.of(TranslatorTypes.createTranslator(knxGroup.getDptMain(), knxGroup.getDpt()));
|
||||
} catch (KNXException e) {
|
||||
throw new NoTranslatorException(e);
|
||||
log.error("No DptXlator found for KnxGroup: {}", knxGroup);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private <Xlator extends DPTXlator, Value> Optional<Value> translate(final Class<Xlator> dptXlatorClass, final DPTXlator translator, final Function<Xlator, Value> getValueFromXlator) {
|
||||
if (dptXlatorClass.isInstance(translator)) {
|
||||
final Xlator castXlator = dptXlatorClass.cast(translator);
|
||||
final Value value = getValueFromXlator.apply(castXlator);
|
||||
return Optional.of(value);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import tuwien.auto.calimero.IndividualAddress;
|
||||
|
||||
import javax.persistence.Embeddable;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@Embeddable
|
||||
@NoArgsConstructor
|
||||
public class KnxTelegram {
|
||||
|
||||
private byte[] data;
|
||||
|
||||
private ZonedDateTime timestamp;
|
||||
|
||||
private Integer deviceAddressRaw;
|
||||
|
||||
private String deviceAddressString;
|
||||
|
||||
public KnxTelegram(final byte[] data, final ZonedDateTime timestamp, final IndividualAddress deviceAddress) {
|
||||
this.data = data;
|
||||
this.timestamp = timestamp;
|
||||
this.deviceAddressRaw = deviceAddress.getRawAddress();
|
||||
this.deviceAddressString = deviceAddress.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class KnxThreadWakeUpEvent {
|
||||
|
||||
}
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
package de.ph87.homeautomation.knx.group;
|
||||
|
||||
import tuwien.auto.calimero.KNXException;
|
||||
|
||||
public class NoTranslatorException extends Exception {
|
||||
|
||||
public NoTranslatorException(final String message) {
|
||||
super("Cannot create translator: " + message);
|
||||
}
|
||||
|
||||
public NoTranslatorException(final KNXException e) {
|
||||
super("Cannot create translator: " + e.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,21 +1,16 @@
|
||||
package de.ph87.homeautomation.property;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import de.ph87.homeautomation.channel.Channel;
|
||||
import lombok.*;
|
||||
|
||||
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.Objects;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
public final class Property {
|
||||
|
||||
@Id
|
||||
@ -23,7 +18,7 @@ public final class Property {
|
||||
@Setter(AccessLevel.NONE)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, unique = true)
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(unique = true)
|
||||
@ -33,20 +28,14 @@ public final class Property {
|
||||
|
||||
private Double value;
|
||||
|
||||
public Boolean getBoolean() {
|
||||
final boolean isTrue = Objects.equals(value, 1.0);
|
||||
final boolean isFalse = Objects.equals(value, 0.0);
|
||||
if (value == null || (!isTrue && !isFalse)) {
|
||||
return null;
|
||||
}
|
||||
return isTrue;
|
||||
}
|
||||
@ManyToOne
|
||||
private Channel readChannel;
|
||||
|
||||
public Double getPercent() {
|
||||
if (value == null || value < 0.0 || 100.0 < value) {
|
||||
return null;
|
||||
}
|
||||
return value;
|
||||
@ManyToOne
|
||||
private Channel writeChannel;
|
||||
|
||||
public Property(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package de.ph87.homeautomation.property;
|
||||
|
||||
import de.ph87.homeautomation.shared.ISearchController;
|
||||
import de.ph87.homeautomation.shared.KeyValuePair;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("property")
|
||||
@RequiredArgsConstructor
|
||||
public class PropertyController implements ISearchController {
|
||||
|
||||
private final PropertyWriteService propertyWriteService;
|
||||
|
||||
private final PropertyReadService propertyReadService;
|
||||
|
||||
@PostMapping("set")
|
||||
public void set(@RequestBody final PropertySetDto dto) {
|
||||
propertyWriteService.write(dto.getName(), dto.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostMapping("getById")
|
||||
public KeyValuePair getById(@RequestBody final String name) {
|
||||
final PropertyDto propertyDto = propertyReadService.getDtoByName(name);
|
||||
return toKeyValuePair(propertyDto);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostMapping("searchLike")
|
||||
public List<KeyValuePair> searchLike(@RequestBody final String term) {
|
||||
return propertyReadService.findAllDtoLike("%" + term + "%").stream().map(this::toKeyValuePair).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private KeyValuePair toKeyValuePair(final PropertyDto propertyDto) {
|
||||
return new KeyValuePair(propertyDto.getName(), propertyDto.getTitle());
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,10 +2,11 @@ package de.ph87.homeautomation.property;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@Data
|
||||
public final class PropertyDto {
|
||||
public final class PropertyDto implements Serializable {
|
||||
|
||||
private final long id;
|
||||
|
||||
@ -13,16 +14,16 @@ public final class PropertyDto {
|
||||
|
||||
private final String title;
|
||||
|
||||
private final ZonedDateTime timestamp;
|
||||
|
||||
private final Double value;
|
||||
|
||||
private final ZonedDateTime valueTimestamp;
|
||||
|
||||
public PropertyDto(final Property property) {
|
||||
this.id = property.getId();
|
||||
this.name = property.getName();
|
||||
this.title = property.getTitle();
|
||||
this.timestamp = property.getTimestamp();
|
||||
this.value = property.getValue();
|
||||
this.valueTimestamp = property.getTimestamp();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,37 @@
|
||||
package de.ph87.homeautomation.property;
|
||||
|
||||
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 PropertyReadService {
|
||||
|
||||
private final PropertyRepository propertyRepository;
|
||||
|
||||
private final PropertyMapper propertyMapper;
|
||||
|
||||
public Property getByName(final String name) {
|
||||
return propertyRepository.findByName(name).orElseThrow(RuntimeException::new);
|
||||
}
|
||||
|
||||
public List<Property> findAllByReadChannel_Id(final long readChannelId) {
|
||||
return propertyRepository.findAllByReadChannel_Id(readChannelId);
|
||||
}
|
||||
|
||||
public List<PropertyDto> findAllDtoLike(final String like) {
|
||||
return propertyRepository.findAllByNameLike(like).stream().map(propertyMapper::toDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public PropertyDto getDtoByName(final String name) {
|
||||
return propertyMapper.toDto(getByName(name));
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,10 +2,15 @@ package de.ph87.homeautomation.property;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface PropertyRepository extends CrudRepository<Property, Long> {
|
||||
|
||||
Optional<Property> findByName(String name);
|
||||
|
||||
List<Property> findAllByReadChannel_Id(long readChannelId);
|
||||
|
||||
List<Property> findAllByNameLike(final String like);
|
||||
|
||||
}
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
package de.ph87.homeautomation.property;
|
||||
|
||||
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 java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
public class PropertyService {
|
||||
|
||||
private final Set<IPropertyOwner> owners;
|
||||
|
||||
private final PropertyRepository propertyRepository;
|
||||
|
||||
private final ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
private final PropertyMapper propertyMapper;
|
||||
|
||||
public Optional<PropertyDto> find(final String name) {
|
||||
return propertyRepository.findByName(name).map(propertyMapper::toDto);
|
||||
}
|
||||
|
||||
public Optional<PropertyDto> set(final String name, final double value) {
|
||||
final Optional<PropertyDto> propertyOptional = owners.stream().map(owner -> owner.write(name, value)).findFirst().map(propertyMapper::toDto);
|
||||
propertyOptional.ifPresent(applicationEventPublisher::publishEvent);
|
||||
return propertyOptional;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package de.ph87.homeautomation.property;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PropertySetDto {
|
||||
|
||||
private final String name;
|
||||
|
||||
private final double value;
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package de.ph87.homeautomation.property;
|
||||
|
||||
import de.ph87.homeautomation.channel.ChannelChangedEvent;
|
||||
import de.ph87.homeautomation.channel.ChannelService;
|
||||
import de.ph87.homeautomation.web.WebSocketService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.event.TransactionPhase;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
public class PropertyWriteService {
|
||||
|
||||
private final PropertyReadService propertyReadService;
|
||||
|
||||
private final ChannelService channelService;
|
||||
|
||||
private final PropertyMapper propertyMapper;
|
||||
|
||||
private final WebSocketService webSocketService;
|
||||
|
||||
public void write(final String name, final double value) {
|
||||
write(propertyReadService.getByName(name), value);
|
||||
}
|
||||
|
||||
public void write(final Property property, final double value) {
|
||||
channelService.write(property, value);
|
||||
}
|
||||
|
||||
@TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
|
||||
public void channelChangedEventListener(final ChannelChangedEvent event) {
|
||||
propertyReadService.findAllByReadChannel_Id(event.getChannelId())
|
||||
.forEach(property -> {
|
||||
property.setValue(property.getReadChannel().getValue());
|
||||
property.setTimestamp(property.getReadChannel().getValueTimestamp());
|
||||
log.debug("Updated Property from Channel: {}", property);
|
||||
webSocketService.send(propertyMapper.toDto(property), true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package de.ph87.homeautomation.property2;
|
||||
|
||||
public interface IPropertyOwner {
|
||||
|
||||
String getPropertyOwnerName();
|
||||
|
||||
Property write(final String name, final double value);
|
||||
|
||||
}
|
||||
@ -1,35 +0,0 @@
|
||||
package de.ph87.homeautomation.property2;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@Entity
|
||||
public final class Property {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
@Setter(AccessLevel.NONE)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, unique = true)
|
||||
private String name;
|
||||
|
||||
@Column(unique = true)
|
||||
private String title;
|
||||
|
||||
private ZonedDateTime timestamp;
|
||||
|
||||
private Double value;
|
||||
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
package de.ph87.homeautomation.property2;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PropertyOwnerValidatorService {
|
||||
|
||||
private final Set<IPropertyOwner> owners;
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
final Map<IPropertyOwner, List<IPropertyOwner>> overlapping = owners.stream().collect(Collectors.toMap(owner -> owner, this::getOverlappingList));
|
||||
if (!overlapping.values().stream().allMatch(List::isEmpty)) {
|
||||
throw new RuntimeException(
|
||||
String.format(
|
||||
"Following IPropertyOwners have overlapping names:\n\t%s",
|
||||
overlapping.entrySet().stream()
|
||||
.map(entry -> {
|
||||
final String prefixClassName = entry.getKey().getClass().getCanonicalName();
|
||||
final String prefixPropertyName = entry.getKey().getPropertyOwnerName();
|
||||
final String overlappingList = entry.getValue().stream().map(owner -> owner.getClass().getCanonicalName() + "(" + owner.getPropertyOwnerName() + ")").collect(Collectors.joining("\n\t\t"));
|
||||
return String.format("%s(%s):\n\t\t%s", prefixClassName, prefixPropertyName, overlappingList);
|
||||
})
|
||||
.collect(Collectors.joining("\n\t"))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private List<IPropertyOwner> getOverlappingList(final IPropertyOwner a) {
|
||||
return owners.stream().filter(b -> b.getPropertyOwnerName().startsWith(a.getPropertyOwnerName())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package de.ph87.homeautomation.property2;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface PropertyRepository extends CrudRepository<Property, Long> {
|
||||
|
||||
Optional<Property> findByName(String name);
|
||||
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
package de.ph87.homeautomation.property2;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@Transactional
|
||||
@RequiredArgsConstructor
|
||||
public class PropertyService {
|
||||
|
||||
private final Set<IPropertyOwner> owners;
|
||||
|
||||
private final PropertyRepository propertyRepository;
|
||||
|
||||
public Optional<Property> write(final String name, final double value) {
|
||||
return owners.stream().map(owner -> owner.write(name, value)).findFirst();
|
||||
}
|
||||
|
||||
public Optional<Property> read(final String name) {
|
||||
return propertyRepository.findByName(name);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package de.ph87.homeautomation.schedule;
|
||||
|
||||
import de.ph87.homeautomation.property.Property;
|
||||
import de.ph87.homeautomation.schedule.entry.ScheduleEntry;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
@ -26,11 +27,11 @@ public class Schedule {
|
||||
@Column(nullable = false, unique = true)
|
||||
private String title;
|
||||
|
||||
private String propertyName;
|
||||
@ManyToOne
|
||||
private Property property;
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private PropertyType propertyType = PropertyType.ON_OFF;
|
||||
private SchedulePropertyType propertyType;
|
||||
|
||||
@ToString.Exclude
|
||||
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
|
||||
|
||||
@ -1,10 +1,13 @@
|
||||
package de.ph87.homeautomation.schedule;
|
||||
|
||||
import de.ph87.homeautomation.property.PropertyReadService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static de.ph87.homeautomation.shared.Helpers.mapIfNotNull;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("schedule")
|
||||
@RequiredArgsConstructor
|
||||
@ -14,6 +17,8 @@ public class ScheduleController {
|
||||
|
||||
private final ScheduleWriteService scheduleWriteService;
|
||||
|
||||
private final PropertyReadService propertyReadService;
|
||||
|
||||
@GetMapping("findAll")
|
||||
public List<ScheduleDto> findAll() {
|
||||
return scheduleReadService.findAllDtos();
|
||||
@ -39,19 +44,19 @@ public class ScheduleController {
|
||||
return scheduleWriteService.set(id, Schedule::setEnabled, enabled);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/name")
|
||||
public ScheduleDto setName(@PathVariable final long id, @RequestBody final String name) {
|
||||
return scheduleWriteService.set(id, Schedule::setTitle, name);
|
||||
@PostMapping("set/{id}/title")
|
||||
public ScheduleDto setTitle(@PathVariable final long id, @RequestBody final String title) {
|
||||
return scheduleWriteService.set(id, Schedule::setTitle, title);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/propertyName")
|
||||
public ScheduleDto setPropertyName(@PathVariable final long id, @RequestBody final String propertyName) {
|
||||
return scheduleWriteService.set(id, Schedule::setPropertyName, propertyName);
|
||||
public ScheduleDto setPropertyName(@PathVariable final long id, @RequestBody(required = false) final String propertyName) {
|
||||
return scheduleWriteService.set(id, (schedule, v) -> schedule.setProperty(mapIfNotNull(v, propertyReadService::getByName)), propertyName);
|
||||
}
|
||||
|
||||
@PostMapping("set/{id}/propertyType")
|
||||
public ScheduleDto setPropertyType(@PathVariable final long id, @RequestBody final String propertyType) {
|
||||
return scheduleWriteService.set(id, Schedule::setPropertyType, PropertyType.valueOf(propertyType));
|
||||
return scheduleWriteService.set(id, Schedule::setPropertyType, SchedulePropertyType.valueOf(propertyType));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,11 +1,14 @@
|
||||
package de.ph87.homeautomation.schedule;
|
||||
|
||||
import de.ph87.homeautomation.property.Property;
|
||||
import de.ph87.homeautomation.schedule.entry.ScheduleEntryDto;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static de.ph87.homeautomation.shared.Helpers.mapIfNotNull;
|
||||
|
||||
@Getter
|
||||
public class ScheduleDto {
|
||||
|
||||
@ -17,7 +20,7 @@ public class ScheduleDto {
|
||||
|
||||
public final String propertyName;
|
||||
|
||||
public final PropertyType propertyType;
|
||||
public final SchedulePropertyType propertyType;
|
||||
|
||||
public final Set<ScheduleEntryDto> entries;
|
||||
|
||||
@ -25,7 +28,7 @@ public class ScheduleDto {
|
||||
this.id = schedule.getId();
|
||||
this.enabled = schedule.isEnabled();
|
||||
this.title = schedule.getTitle();
|
||||
this.propertyName = schedule.getPropertyName();
|
||||
this.propertyName = mapIfNotNull(schedule.getProperty(), Property::getName);
|
||||
this.propertyType = schedule.getPropertyType();
|
||||
this.entries = schedule.getEntries().stream().map(ScheduleEntryDto::new).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package de.ph87.homeautomation.schedule;
|
||||
|
||||
import de.ph87.homeautomation.property.PropertyService;
|
||||
import de.ph87.homeautomation.property.PropertySetException;
|
||||
import de.ph87.homeautomation.property.PropertyWriteService;
|
||||
import de.ph87.homeautomation.schedule.entry.ScheduleEntry;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -21,7 +20,7 @@ public class ScheduleExecutionService {
|
||||
|
||||
private final ScheduleCalculationService scheduleCalculationService;
|
||||
|
||||
private final PropertyService propertyService;
|
||||
private final PropertyWriteService propertyWriteService;
|
||||
|
||||
public void executeAllLastDue() {
|
||||
final ZonedDateTime now = ZonedDateTime.now();
|
||||
@ -29,7 +28,7 @@ public class ScheduleExecutionService {
|
||||
}
|
||||
|
||||
private void executeLastDue(final Schedule schedule, final ZonedDateTime now) {
|
||||
if (schedule.getPropertyName() == null || schedule.getPropertyName().isEmpty()) {
|
||||
if (schedule.getProperty() == null) {
|
||||
log.error("Cannot execute Schedule {}: No property set!", schedule);
|
||||
return;
|
||||
}
|
||||
@ -42,11 +41,7 @@ public class ScheduleExecutionService {
|
||||
private void executeEntry(final Schedule schedule, final ScheduleEntry entry, final ZonedDateTime now) {
|
||||
entry.setLastClearTimestamp(entry.getNextClearTimestamp());
|
||||
log.info("Executing Schedule \"{}\" Entry {}", schedule.getTitle(), entry);
|
||||
try {
|
||||
propertyService.set(schedule.getPropertyName(), entry.getValue());
|
||||
} catch (PropertySetException e) {
|
||||
log.error(e.getMessage());
|
||||
}
|
||||
propertyWriteService.write(schedule.getProperty(), entry.getValue());
|
||||
scheduleCalculationService.calculateSchedule(schedule, now);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
package de.ph87.homeautomation.schedule;
|
||||
|
||||
public enum SchedulePropertyType {
|
||||
SWITCH, PERCENT, SHUTTER, SCENE
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
import org.junit.jupiter.api.Test;
|
||||
import tuwien.auto.calimero.GroupAddress;
|
||||
|
||||
public class GroupAddressTranslatorTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
getPrintln(1048);
|
||||
getPrintln(771);
|
||||
getPrintln(1293);
|
||||
}
|
||||
|
||||
private void getPrintln(final int i) {
|
||||
System.out.printf("%d: %s\n", i, new GroupAddress(i));
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user