Provide detailed Sunrise/-set times per Schedule from Server
This commit is contained in:
parent
0b146b5972
commit
fd5ceced45
25
src/main/angular/src/app/api/astro/Astro.ts
Normal file
25
src/main/angular/src/app/api/astro/Astro.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import {validateDateAllowNull, validateNumberNotNull, validateStringNullToEmpty} from "../validators";
|
||||||
|
|
||||||
|
export class Astro {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly zenith: number,
|
||||||
|
readonly sunrise: Date,
|
||||||
|
readonly sunset: Date,
|
||||||
|
readonly sunriseName: string,
|
||||||
|
readonly sunsetName: string,
|
||||||
|
) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: any): Astro {
|
||||||
|
return new Astro(
|
||||||
|
validateNumberNotNull(json['zenith']),
|
||||||
|
validateDateAllowNull(json['sunrise']),
|
||||||
|
validateDateAllowNull(json['sunset']),
|
||||||
|
validateStringNullToEmpty(json['sunriseName']),
|
||||||
|
validateStringNullToEmpty(json['sunsetName']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,17 +1,22 @@
|
|||||||
import {validateBooleanNotNull, validateListOrEmpty, validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators";
|
import {validateBooleanNotNull, validateListOrEmpty, validateNumberNotNull, validateStringNotEmptyNotNull} from "../validators";
|
||||||
import {ScheduleEntry} from "./entry/ScheduleEntry";
|
import {ScheduleEntry} from "./entry/ScheduleEntry";
|
||||||
|
import {Astro} from "../astro/Astro";
|
||||||
|
|
||||||
export class Schedule {
|
export class Schedule {
|
||||||
|
|
||||||
readonly next?: ScheduleEntry;
|
readonly next?: ScheduleEntry;
|
||||||
|
|
||||||
|
readonly last?: ScheduleEntry;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly id: number,
|
readonly id: number,
|
||||||
readonly enabled: boolean,
|
readonly enabled: boolean,
|
||||||
readonly title: string,
|
readonly title: string,
|
||||||
readonly entries: ScheduleEntry[],
|
readonly entries: ScheduleEntry[],
|
||||||
|
readonly astros: Astro[],
|
||||||
) {
|
) {
|
||||||
this.next = entries.filter(e => e.nextFuzzyTimestamp).sort((a, b) => a.nextFuzzyTimestamp.date.getTime() - b.nextFuzzyTimestamp.date.getTime())[0];
|
this.next = entries.filter(e => e.nextFuzzyTimestamp).sort((a, b) => a.nextFuzzyTimestamp.date.getTime() - b.nextFuzzyTimestamp.date.getTime())[0];
|
||||||
|
this.last = entries.filter(e => e.lastFuzzyTimestamp).sort((a, b) => b.nextFuzzyTimestamp.date.getTime() - a.nextFuzzyTimestamp.date.getTime())[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromJson(json: any): Schedule {
|
static fromJson(json: any): Schedule {
|
||||||
@ -20,6 +25,7 @@ export class Schedule {
|
|||||||
validateBooleanNotNull(json['enabled']),
|
validateBooleanNotNull(json['enabled']),
|
||||||
validateStringNotEmptyNotNull(json['title']),
|
validateStringNotEmptyNotNull(json['title']),
|
||||||
validateListOrEmpty(json['entries'], ScheduleEntry.fromJson, ScheduleEntry.comparePosition),
|
validateListOrEmpty(json['entries'], ScheduleEntry.fromJson, ScheduleEntry.comparePosition),
|
||||||
|
validateListOrEmpty(json['astros'], Astro.fromJson),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,7 @@ export class ScheduleEntry {
|
|||||||
readonly lastClearTimestamp: Timestamp | null,
|
readonly lastClearTimestamp: Timestamp | null,
|
||||||
readonly nextClearTimestamp: Timestamp | null,
|
readonly nextClearTimestamp: Timestamp | null,
|
||||||
readonly nextFuzzyTimestamp: Timestamp | null,
|
readonly nextFuzzyTimestamp: Timestamp | null,
|
||||||
|
readonly lastFuzzyTimestamp: Timestamp | null,
|
||||||
readonly property: Property | null,
|
readonly property: Property | null,
|
||||||
readonly value: number,
|
readonly value: number,
|
||||||
readonly bulk: Bulk | null,
|
readonly bulk: Bulk | null,
|
||||||
@ -57,6 +58,7 @@ export class ScheduleEntry {
|
|||||||
Timestamp.fromDateOrNull(validateDateAllowNull(json['lastClearTimestamp'])),
|
Timestamp.fromDateOrNull(validateDateAllowNull(json['lastClearTimestamp'])),
|
||||||
Timestamp.fromDateOrNull(validateDateAllowNull(json['nextClearTimestamp'])),
|
Timestamp.fromDateOrNull(validateDateAllowNull(json['nextClearTimestamp'])),
|
||||||
Timestamp.fromDateOrNull(validateDateAllowNull(json['nextFuzzyTimestamp'])),
|
Timestamp.fromDateOrNull(validateDateAllowNull(json['nextFuzzyTimestamp'])),
|
||||||
|
Timestamp.fromDateOrNull(validateDateAllowNull(json['lastFuzzyTimestamp'])),
|
||||||
Property.fromJsonAllowNull(json['property']),
|
Property.fromJsonAllowNull(json['property']),
|
||||||
validateNumberNotNull(json['value']),
|
validateNumberNotNull(json['value']),
|
||||||
Bulk.fromJsonOrNull(json['bulk']),
|
Bulk.fromJsonOrNull(json['bulk']),
|
||||||
|
|||||||
@ -17,6 +17,8 @@ import {PropertyListComponent} from './pages/property/list/property-list.compone
|
|||||||
import {ChannelListComponent} from './pages/channel/list/channel-list.component';
|
import {ChannelListComponent} from './pages/channel/list/channel-list.component';
|
||||||
import {BulkListComponent} from './pages/bulk/list/bulk-list.component';
|
import {BulkListComponent} from './pages/bulk/list/bulk-list.component';
|
||||||
import {BulkEditorComponent} from './pages/bulk/editor/bulk-editor.component';
|
import {BulkEditorComponent} from './pages/bulk/editor/bulk-editor.component';
|
||||||
|
import {LeftPadDirective} from './pipes/left-pad.directive';
|
||||||
|
import {EntryValueComponent} from './shared/entry-value/entry-value.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -33,6 +35,8 @@ import {BulkEditorComponent} from './pages/bulk/editor/bulk-editor.component';
|
|||||||
DeviceListComponent,
|
DeviceListComponent,
|
||||||
BulkListComponent,
|
BulkListComponent,
|
||||||
BulkEditorComponent,
|
BulkEditorComponent,
|
||||||
|
LeftPadDirective,
|
||||||
|
EntryValueComponent,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule,
|
BrowserModule,
|
||||||
|
|||||||
@ -55,23 +55,11 @@
|
|||||||
<ng-container *ngIf="entry.type === 'SUNRISE' || entry.type === 'SUNSET'">
|
<ng-container *ngIf="entry.type === 'SUNRISE' || entry.type === 'SUNSET'">
|
||||||
<td>
|
<td>
|
||||||
<select [ngModel]="entry.zenith" (ngModelChange)="set(entry, 'zenith', $event)">
|
<select [ngModel]="entry.zenith" (ngModelChange)="set(entry, 'zenith', $event)">
|
||||||
<option value="87">
|
<option *ngFor="let event of schedule.astros; let index = index" [value]="event.zenith">
|
||||||
[ 87°]
|
[{{event.zenith | number:'0.1-1' | leftPad:5}}°, {{(entry.type === 'SUNRISE' ? event.sunrise : event.sunset) | date:'HH:mm'}}] {{entry.type === 'SUNRISE' ? event.sunriseName : event.sunsetName}}
|
||||||
<ng-container *ngIf="entry.type === 'SUNRISE'">Nach Sonnenaufgang</ng-container>
|
|
||||||
<ng-container *ngIf="entry.type === 'SUNSET'">Vor Sonnenuntergang</ng-container>
|
|
||||||
</option>
|
</option>
|
||||||
<option value="90.8333">
|
|
||||||
[ 90°]
|
|
||||||
<ng-container *ngIf="entry.type === 'SUNRISE'">Sonnenaufgang</ng-container>
|
|
||||||
<ng-container *ngIf="entry.type === 'SUNSET'">Sonnenuntergang</ng-container>
|
|
||||||
</option>
|
|
||||||
<option value="93">[ 93°]</option>
|
|
||||||
<option value="96">[ 96°] Bürgerliche Dämmerung</option>
|
|
||||||
<option value="99">[ 99°]</option>
|
|
||||||
<option value="102">[102°] Nautische Dämmerung</option>
|
|
||||||
<option value="105">[105°]</option>
|
|
||||||
<option value="108">[108°] Astronomische Dämmerung</option>
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<td *ngIf="entry.type !== 'SUNRISE' && entry.type !== 'SUNSET'" class="empty"></td>
|
<td *ngIf="entry.type !== 'SUNRISE' && entry.type !== 'SUNSET'" class="empty"></td>
|
||||||
@ -85,7 +73,7 @@
|
|||||||
<td class="middle">:</td>
|
<td class="middle">:</td>
|
||||||
<td class="last">
|
<td class="last">
|
||||||
<select [ngModel]="entry.minute" (ngModelChange)="set(entry, 'minute', $event)">
|
<select [ngModel]="entry.minute" (ngModelChange)="set(entry, 'minute', $event)">
|
||||||
<option *ngFor="let _ of [].constructor(60); let value = index" [ngValue]="value">{{value | number:'2.0'}}</option>
|
<option *ngFor="let _ of [].constructor(12); let value = index" [ngValue]="value * 5">{{value * 5 | number:'2.0'}}</option>
|
||||||
</select>
|
</select>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@ -132,44 +120,10 @@
|
|||||||
<td>
|
<td>
|
||||||
<app-search [searchService]="propertyService" [initial]="entry.property?.id" (valueChange)="set(entry, 'property', $event)"></app-search>
|
<app-search [searchService]="propertyService" [initial]="entry.property?.id" (valueChange)="set(entry, 'property', $event)"></app-search>
|
||||||
</td>
|
</td>
|
||||||
<ng-container [ngSwitch]="entry.property?.type">
|
|
||||||
<td *ngSwitchCase="'BOOLEAN'" [class.true]="entry.value" [class.false]="!entry.value" (click)="set(entry, 'value', entry.value > 0 ? 0 : 1)">
|
<td>
|
||||||
{{entry.value ? "An" : "Aus"}}
|
<app-entry-value [entry]="entry" [allowChange]="true" (onSet)="set(entry, $event.key, $event.value)"></app-entry-value>
|
||||||
</td>
|
</td>
|
||||||
<td *ngSwitchCase="'SHUTTER'" [class.true]="entry.value === 0" [class.false]="entry.value === 100" [class.tristate]="0 < entry.value && entry.value < 100">
|
|
||||||
<select [ngModel]="entry.value" (ngModelChange)="set(entry, 'value', $event)">
|
|
||||||
<option [ngValue]="0">100% Offen</option>
|
|
||||||
<option [ngValue]="35"> 50%</option>
|
|
||||||
<option [ngValue]="55"> 75%</option>
|
|
||||||
<option [ngValue]="75"> 90% Sonnenschutz</option>
|
|
||||||
<option [ngValue]="85">100% Schlitze</option>
|
|
||||||
<option [ngValue]="100">100% Geschlossen</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td *ngSwitchCase="'BRIGHTNESS_PERCENT'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
|
|
||||||
<select [ngModel]="entry.value" (ngModelChange)="set(entry, 'value', $event)">
|
|
||||||
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td *ngSwitchCase="'COLOR_TEMPERATURE'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
|
|
||||||
<select [ngModel]="entry.value" (ngModelChange)="set(entry, 'value', $event)">
|
|
||||||
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td *ngSwitchCase="'LUX'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
|
|
||||||
<select [ngModel]="entry.value" (ngModelChange)="set(entry, 'value', $event)">
|
|
||||||
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td *ngSwitchCase="'SCENE'">
|
|
||||||
<select [ngModel]="entry.value" (ngModelChange)="set(entry, 'value', $event)">
|
|
||||||
<option *ngFor="let scene of scenes" [ngValue]="scene.number">#{{scene.number | number:'2.0-0'}} {{scene.title}}</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td *ngSwitchDefault class="empty">
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<app-search [searchService]="bulkService" [initial]="entry.bulk?.id" (valueChange)="set(entry, 'bulk', $event)"></app-search>
|
<app-search [searchService]="bulkService" [initial]="entry.bulk?.id" (valueChange)="set(entry, 'bulk', $event)"></app-search>
|
||||||
|
|||||||
@ -6,8 +6,6 @@ import {ScheduleEntryService} from "../../../api/schedule/entry/schedule-entry.s
|
|||||||
import {faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCircle, faTimesCircle} from '@fortawesome/free-regular-svg-icons';
|
import {faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCircle, faTimesCircle} from '@fortawesome/free-regular-svg-icons';
|
||||||
import {ActivatedRoute, Router} from "@angular/router";
|
import {ActivatedRoute, Router} from "@angular/router";
|
||||||
import {PropertyService} from "../../../api/property/property.service";
|
import {PropertyService} from "../../../api/property/property.service";
|
||||||
import {Scene} from "../../../api/scene/Scene";
|
|
||||||
import {SceneService} from "../../../api/scene/scene.service";
|
|
||||||
import {BulkService} from "../../../api/bulk/BulkService";
|
import {BulkService} from "../../../api/bulk/BulkService";
|
||||||
import {Update} from "../../../api/Update";
|
import {Update} from "../../../api/Update";
|
||||||
import {NO_OP} from "../../../api/api.service";
|
import {NO_OP} from "../../../api/api.service";
|
||||||
@ -35,8 +33,6 @@ export class ScheduleEditorComponent implements OnInit {
|
|||||||
|
|
||||||
schedule!: Schedule;
|
schedule!: Schedule;
|
||||||
|
|
||||||
scenes: Scene[] = [];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly router: Router,
|
readonly router: Router,
|
||||||
readonly activatedRoute: ActivatedRoute,
|
readonly activatedRoute: ActivatedRoute,
|
||||||
@ -44,14 +40,12 @@ export class ScheduleEditorComponent implements OnInit {
|
|||||||
readonly scheduleEntryService: ScheduleEntryService,
|
readonly scheduleEntryService: ScheduleEntryService,
|
||||||
readonly propertyService: PropertyService,
|
readonly propertyService: PropertyService,
|
||||||
readonly bulkService: BulkService,
|
readonly bulkService: BulkService,
|
||||||
readonly sceneService: SceneService,
|
|
||||||
) {
|
) {
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.scheduleService.subscribe(update => this.update(update));
|
this.scheduleService.subscribe(update => this.update(update));
|
||||||
this.sceneService.findAll(scenes => this.scenes = scenes);
|
|
||||||
this.activatedRoute.params.subscribe(params => this.scheduleService.getById(params['id'], schedule => this.schedule = schedule));
|
this.activatedRoute.params.subscribe(params => this.scheduleService.getById(params['id'], schedule => this.schedule = schedule));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,9 +2,10 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<th>Bezeichnung</th>
|
<th>Bezeichnung</th>
|
||||||
<th colspan="3">Zeitpunkt</th>
|
<th colspan="3">Nächste</th>
|
||||||
<th colspan="3">Eigenschaft</th>
|
<th colspan="3">Eigenschaft</th>
|
||||||
<th>Massenausführung</th>
|
<th>Massenausführung</th>
|
||||||
|
<th colspan="3">Letzte</th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr *ngFor="let schedule of schedules; trackBy: Schedule.trackBy">
|
<tr *ngFor="let schedule of schedules; trackBy: Schedule.trackBy">
|
||||||
@ -24,12 +25,18 @@
|
|||||||
|
|
||||||
<td class="number first" [class.empty]="!schedule.next?.property">{{schedule.next?.property?.title}}</td>
|
<td class="number first" [class.empty]="!schedule.next?.property">{{schedule.next?.property?.title}}</td>
|
||||||
<td class="number middle" [class.empty]="!schedule.next?.property"> = </td>
|
<td class="number middle" [class.empty]="!schedule.next?.property"> = </td>
|
||||||
<td class="number last" [class.empty]="!schedule.next?.property">{{schedule.next?.value}}</td>
|
<td class="number last" [class.empty]="!schedule.next?.property">
|
||||||
|
<app-entry-value *ngIf="schedule.next" [entry]="schedule.next" [allowChange]="false"></app-entry-value>
|
||||||
|
</td>
|
||||||
|
|
||||||
<td [class.empty]="!schedule.next?.bulk">
|
<td [class.empty]="!schedule.next?.bulk">
|
||||||
{{schedule.next?.bulk?.name}}
|
{{schedule.next?.bulk?.name}}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
<td class="number first" [class.empty]="!schedule.last?.lastFuzzyTimestamp">{{schedule.last?.lastFuzzyTimestamp.dayName}}</td>
|
||||||
|
<td class="number middle" [class.empty]="!schedule.last?.lastFuzzyTimestamp">: </td>
|
||||||
|
<td class="number last" [class.empty]="!schedule.last?.lastFuzzyTimestamp">{{schedule.last?.lastFuzzyTimestamp.timeString}}</td>
|
||||||
|
|
||||||
<td class="delete" (click)="delete(schedule)">
|
<td class="delete" (click)="delete(schedule)">
|
||||||
<fa-icon title="Löschen" [icon]="faTimes"></fa-icon>
|
<fa-icon title="Löschen" [icon]="faTimes"></fa-icon>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
20
src/main/angular/src/app/pipes/left-pad.directive.ts
Normal file
20
src/main/angular/src/app/pipes/left-pad.directive.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import {Pipe, PipeTransform} from '@angular/core';
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'leftPad',
|
||||||
|
})
|
||||||
|
export class LeftPadDirective implements PipeTransform {
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
transform(value: any, count: number): any {
|
||||||
|
let result = "" + value;
|
||||||
|
const rest: number = count - result.length;
|
||||||
|
if (rest > 0) {
|
||||||
|
result = " ".repeat(rest) + result;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
<ng-container [ngSwitch]="entry.property?.type">
|
||||||
|
|
||||||
|
<div *ngSwitchCase="'BOOLEAN'" [class.true]="entry.value" [class.false]="!entry.value" (click)="set('value', entry.value > 0 ? 0 : 1)">
|
||||||
|
{{entry.value ? "An" : "Aus"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngSwitchCase="'SHUTTER'" [class.true]="entry.value === 0" [class.false]="entry.value === 100" [class.tristate]="0 < entry.value && entry.value < 100">
|
||||||
|
<select [ngModel]="entry.value" (ngModelChange)="set('value', $event)" [disabled]="!allowChange">
|
||||||
|
<option [ngValue]="0">100% Offen</option>
|
||||||
|
<option [ngValue]="35"> 50%</option>
|
||||||
|
<option [ngValue]="55"> 75%</option>
|
||||||
|
<option [ngValue]="75"> 90% Sonnenschutz</option>
|
||||||
|
<option [ngValue]="85">100% Schlitze</option>
|
||||||
|
<option [ngValue]="100">100% Geschlossen</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngSwitchCase="'BRIGHTNESS_PERCENT'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
|
||||||
|
<select [ngModel]="entry.value" (ngModelChange)="set('value', $event)" [disabled]="!allowChange">
|
||||||
|
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngSwitchCase="'COLOR_TEMPERATURE'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
|
||||||
|
<select [ngModel]="entry.value" (ngModelChange)="set('value', $event)" [disabled]="!allowChange">
|
||||||
|
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngSwitchCase="'LUX'" [class.true]="entry.value" [class.false]="!entry.value" [class.tristate]="0 < entry.value && entry.value < 100">
|
||||||
|
<select [ngModel]="entry.value" (ngModelChange)="set('value', $event)" [disabled]="!allowChange">
|
||||||
|
<option *ngFor="let _ of [].constructor(21); let value = index" [ngValue]="value * 5">{{value * 5}}%</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngSwitchCase="'SCENE'">
|
||||||
|
<select [ngModel]="entry.value" (ngModelChange)="set('value', $event)" [disabled]="!allowChange">
|
||||||
|
<option *ngFor="let scene of scenes" [ngValue]="scene.number">#{{scene.number | number:'2.0-0'}} {{scene.title}}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div *ngSwi
|
||||||
|
tchDefault class="empty">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</ng-container>
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||||
|
import {ScheduleEntry} from "../../api/schedule/entry/ScheduleEntry";
|
||||||
|
import {Scene} from "../../api/scene/Scene";
|
||||||
|
import {SceneService} from "../../api/scene/scene.service";
|
||||||
|
|
||||||
|
export class OnSet {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly key: string,
|
||||||
|
readonly value: any,
|
||||||
|
) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-entry-value',
|
||||||
|
templateUrl: './entry-value.component.html',
|
||||||
|
styleUrls: ['./entry-value.component.less']
|
||||||
|
})
|
||||||
|
export class EntryValueComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
entry!: ScheduleEntry;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
allowChange: boolean = false;
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
onSet: EventEmitter<OnSet> = new EventEmitter<OnSet>();
|
||||||
|
|
||||||
|
scenes: Scene[] = [];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
readonly sceneService: SceneService,) {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.sceneService.findAll(scenes => this.scenes = scenes);
|
||||||
|
}
|
||||||
|
|
||||||
|
set(key: string, value: any): void {
|
||||||
|
if (!this.allowChange) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.onSet.emit(new OnSet(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -4,10 +4,12 @@
|
|||||||
|
|
||||||
import {getBaseUrl} from "./UrlHelper";
|
import {getBaseUrl} from "./UrlHelper";
|
||||||
|
|
||||||
|
const PROD: boolean = false;
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false,
|
production: false,
|
||||||
restBase: getBaseUrl('http', 8080),
|
restBase: PROD ? 'http://10.0.0.50:8082' : getBaseUrl('http', 8080),
|
||||||
websocketBase: getBaseUrl('ws', 8080),
|
websocketBase: PROD ? 'ws://10.0.0.50:8082' : getBaseUrl('ws', 8080),
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
package de.ph87.homeautomation.schedule;
|
package de.ph87.homeautomation.schedule;
|
||||||
|
|
||||||
import com.luckycatlabs.sunrisesunset.Zenith;
|
import de.ph87.homeautomation.schedule.astro.AstroCalculator;
|
||||||
import com.luckycatlabs.sunrisesunset.calculator.SolarEventCalculator;
|
|
||||||
import com.luckycatlabs.sunrisesunset.dto.Location;
|
|
||||||
import de.ph87.homeautomation.Config;
|
|
||||||
import de.ph87.homeautomation.schedule.entry.ScheduleEntry;
|
import de.ph87.homeautomation.schedule.entry.ScheduleEntry;
|
||||||
import de.ph87.homeautomation.schedule.entry.ScheduleEntryType;
|
import de.ph87.homeautomation.schedule.entry.ScheduleEntryType;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@ -14,11 +11,8 @@ import org.springframework.context.event.EventListener;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.GregorianCalendar;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -27,14 +21,14 @@ import java.util.Optional;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ScheduleCalculator {
|
public class ScheduleCalculator {
|
||||||
|
|
||||||
private final Config config;
|
|
||||||
|
|
||||||
private final ScheduleReader scheduleReader;
|
private final ScheduleReader scheduleReader;
|
||||||
|
|
||||||
private final ApplicationEventPublisher applicationEventPublisher;
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
private final ScheduleMapper scheduleMapper;
|
private final ScheduleMapper scheduleMapper;
|
||||||
|
|
||||||
|
private final AstroCalculator astroCalculator;
|
||||||
|
|
||||||
@EventListener(ApplicationStartedEvent.class)
|
@EventListener(ApplicationStartedEvent.class)
|
||||||
public void calculateAllNext() {
|
public void calculateAllNext() {
|
||||||
final ZonedDateTime now = ZonedDateTime.now();
|
final ZonedDateTime now = ZonedDateTime.now();
|
||||||
@ -82,7 +76,8 @@ public class ScheduleCalculator {
|
|||||||
return midnight.withHour(entry.getHour()).withMinute(entry.getMinute()).withSecond(entry.getSecond());
|
return midnight.withHour(entry.getHour()).withMinute(entry.getMinute()).withSecond(entry.getSecond());
|
||||||
case SUNRISE:
|
case SUNRISE:
|
||||||
case SUNSET:
|
case SUNSET:
|
||||||
return astroNext(entry, midnight);
|
final boolean sunrise = entry.getType() == ScheduleEntryType.SUNRISE;
|
||||||
|
return astroCalculator.forDay(midnight, sunrise, entry.getZenith());
|
||||||
default:
|
default:
|
||||||
log.error("AstroEvent not implemented: {}", entry.getType());
|
log.error("AstroEvent not implemented: {}", entry.getType());
|
||||||
break;
|
break;
|
||||||
@ -90,49 +85,20 @@ public class ScheduleCalculator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ZonedDateTime astroNext(final ScheduleEntry entry, ZonedDateTime midnight) {
|
|
||||||
final Location location = new Location(config.getLatitude(), config.getLongitude());
|
|
||||||
final SolarEventCalculator calculator = new SolarEventCalculator(location, config.getTimezone());
|
|
||||||
final Calendar calendar = GregorianCalendar.from(midnight);
|
|
||||||
final Calendar nextCalendar = astroNext(calculator, entry.getType(), new Zenith(entry.getZenith()), calendar);
|
|
||||||
if (nextCalendar == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(nextCalendar.getTimeInMillis()), midnight.getZone());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Calendar astroNext(final SolarEventCalculator calculator, final ScheduleEntryType type, final Zenith solarZenith, final Calendar calendar) {
|
|
||||||
switch (type) {
|
|
||||||
case SUNRISE:
|
|
||||||
return calculator.computeSunriseCalendar(solarZenith, calendar);
|
|
||||||
case SUNSET:
|
|
||||||
return calculator.computeSunsetCalendar(solarZenith, calendar);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isAnyWeekdayEnabled(final ScheduleEntry entry) {
|
private boolean isAnyWeekdayEnabled(final ScheduleEntry entry) {
|
||||||
return entry.isMonday() || entry.isTuesday() || entry.isWednesday() || entry.isThursday() || entry.isFriday() || entry.isSaturday() || entry.isSunday();
|
return entry.isMonday() || entry.isTuesday() || entry.isWednesday() || entry.isThursday() || entry.isFriday() || entry.isSaturday() || entry.isSunday();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isWeekdayEnabled(final ScheduleEntry entry, final ZonedDateTime value) {
|
private boolean isWeekdayEnabled(final ScheduleEntry entry, final ZonedDateTime value) {
|
||||||
switch (value.getDayOfWeek()) {
|
return switch (value.getDayOfWeek()) {
|
||||||
case MONDAY:
|
case MONDAY -> entry.isMonday();
|
||||||
return entry.isMonday();
|
case TUESDAY -> entry.isTuesday();
|
||||||
case TUESDAY:
|
case WEDNESDAY -> entry.isWednesday();
|
||||||
return entry.isTuesday();
|
case THURSDAY -> entry.isThursday();
|
||||||
case WEDNESDAY:
|
case FRIDAY -> entry.isFriday();
|
||||||
return entry.isWednesday();
|
case SATURDAY -> entry.isSaturday();
|
||||||
case THURSDAY:
|
case SUNDAY -> entry.isSunday();
|
||||||
return entry.isThursday();
|
};
|
||||||
case FRIDAY:
|
|
||||||
return entry.isFriday();
|
|
||||||
case SATURDAY:
|
|
||||||
return entry.isSaturday();
|
|
||||||
case SUNDAY:
|
|
||||||
return entry.isSunday();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package de.ph87.homeautomation.schedule;
|
package de.ph87.homeautomation.schedule;
|
||||||
|
|
||||||
import de.ph87.homeautomation.property.PropertyReader;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
@ -15,8 +14,6 @@ public class ScheduleController {
|
|||||||
|
|
||||||
private final ScheduleWriter scheduleWriter;
|
private final ScheduleWriter scheduleWriter;
|
||||||
|
|
||||||
private final PropertyReader propertyReader;
|
|
||||||
|
|
||||||
@GetMapping("findAll")
|
@GetMapping("findAll")
|
||||||
public List<ScheduleDto> findAll() {
|
public List<ScheduleDto> findAll() {
|
||||||
return scheduleReader.findAllDtos();
|
return scheduleReader.findAllDtos();
|
||||||
|
|||||||
@ -1,27 +1,32 @@
|
|||||||
package de.ph87.homeautomation.schedule;
|
package de.ph87.homeautomation.schedule;
|
||||||
|
|
||||||
|
import de.ph87.homeautomation.schedule.astro.AstroDto;
|
||||||
import de.ph87.homeautomation.schedule.entry.ScheduleEntryDto;
|
import de.ph87.homeautomation.schedule.entry.ScheduleEntryDto;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class ScheduleDto implements Serializable {
|
public class ScheduleDto implements Serializable {
|
||||||
|
|
||||||
public final long id;
|
private final long id;
|
||||||
|
|
||||||
public final boolean enabled;
|
private final boolean enabled;
|
||||||
|
|
||||||
public final String title;
|
private final String title;
|
||||||
|
|
||||||
public final Set<ScheduleEntryDto> entries;
|
private final Set<ScheduleEntryDto> entries;
|
||||||
|
|
||||||
public ScheduleDto(final Schedule schedule, final Set<ScheduleEntryDto> entries) {
|
private final List<AstroDto> astros;
|
||||||
|
|
||||||
|
public ScheduleDto(final Schedule schedule, final Set<ScheduleEntryDto> entries, final List<AstroDto> astros) {
|
||||||
this.id = schedule.getId();
|
this.id = schedule.getId();
|
||||||
this.enabled = schedule.isEnabled();
|
this.enabled = schedule.isEnabled();
|
||||||
this.title = schedule.getTitle();
|
this.title = schedule.getTitle();
|
||||||
this.entries = entries;
|
this.entries = entries;
|
||||||
|
this.astros = astros;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,7 @@ public class ScheduleExecutor {
|
|||||||
bulkExecutor.execute(entry.getBulk());
|
bulkExecutor.execute(entry.getBulk());
|
||||||
}
|
}
|
||||||
entry.setLastClearTimestamp(entry.getNextClearTimestamp());
|
entry.setLastClearTimestamp(entry.getNextClearTimestamp());
|
||||||
|
entry.setLastFuzzyTimestamp(entry.getNextFuzzyTimestamp());
|
||||||
scheduleWriter.notifyChanged(schedule);
|
scheduleWriter.notifyChanged(schedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package de.ph87.homeautomation.schedule;
|
package de.ph87.homeautomation.schedule;
|
||||||
|
|
||||||
|
import de.ph87.homeautomation.schedule.astro.AstroDto;
|
||||||
|
import de.ph87.homeautomation.schedule.astro.AstroService;
|
||||||
import de.ph87.homeautomation.schedule.entry.ScheduleEntryDto;
|
import de.ph87.homeautomation.schedule.entry.ScheduleEntryDto;
|
||||||
import de.ph87.homeautomation.schedule.entry.ScheduleEntryMapper;
|
import de.ph87.homeautomation.schedule.entry.ScheduleEntryMapper;
|
||||||
import de.ph87.homeautomation.web.WebSocketService;
|
import de.ph87.homeautomation.web.WebSocketService;
|
||||||
@ -8,6 +10,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -21,15 +24,17 @@ public class ScheduleMapper {
|
|||||||
|
|
||||||
private final WebSocketService webSocketService;
|
private final WebSocketService webSocketService;
|
||||||
|
|
||||||
|
private final AstroService astroService;
|
||||||
|
|
||||||
public ScheduleDto toDto(final Schedule schedule) {
|
public ScheduleDto toDto(final Schedule schedule) {
|
||||||
final Set<ScheduleEntryDto> entries = schedule.getEntries().stream().map(scheduleEntryMapper::toDto).collect(Collectors.toSet());
|
final Set<ScheduleEntryDto> entries = schedule.getEntries().stream().map(scheduleEntryMapper::toDto).collect(Collectors.toSet());
|
||||||
return new ScheduleDto(schedule, entries);
|
final List<AstroDto> astros = astroService.findAllNext();
|
||||||
|
return new ScheduleDto(schedule, entries, astros);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScheduleDto publish(final Schedule schedule, final boolean existing) {
|
public void publish(final Schedule schedule, final boolean existing) {
|
||||||
final ScheduleDto dto = toDto(schedule);
|
final ScheduleDto dto = toDto(schedule);
|
||||||
webSocketService.send(ScheduleDto.class, dto, existing);
|
webSocketService.send(ScheduleDto.class, dto, existing);
|
||||||
return dto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,45 @@
|
|||||||
|
package de.ph87.homeautomation.schedule.astro;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Astro {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Version
|
||||||
|
private long version;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private boolean enabled = true;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private String error;
|
||||||
|
|
||||||
|
@Column(unique = true)
|
||||||
|
private double zenith;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String differentNameForSunset;
|
||||||
|
|
||||||
|
public Astro(final double zenith, @NonNull final String name, @Nullable final String differentNameForSunset) {
|
||||||
|
this.zenith = zenith;
|
||||||
|
this.name = name;
|
||||||
|
this.differentNameForSunset = differentNameForSunset;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package de.ph87.homeautomation.schedule.astro;
|
||||||
|
|
||||||
|
import com.luckycatlabs.sunrisesunset.Zenith;
|
||||||
|
import com.luckycatlabs.sunrisesunset.calculator.SolarEventCalculator;
|
||||||
|
import com.luckycatlabs.sunrisesunset.dto.Location;
|
||||||
|
import de.ph87.homeautomation.Config;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AstroCalculator {
|
||||||
|
|
||||||
|
private final Config config;
|
||||||
|
|
||||||
|
public ZonedDateTime next(final ZonedDateTime now, final boolean sunrise, final double zenith) {
|
||||||
|
ZonedDateTime day = now.truncatedTo(ChronoUnit.DAYS);
|
||||||
|
ZonedDateTime next;
|
||||||
|
do {
|
||||||
|
next = forDay(day, sunrise, zenith);
|
||||||
|
day = day.plusDays(1);
|
||||||
|
} while (next != null && !next.isAfter(now));
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZonedDateTime forDay(final ZonedDateTime midnight, final boolean sunrise, final double zenith) {
|
||||||
|
final Location location = new Location(config.getLatitude(), config.getLongitude());
|
||||||
|
final SolarEventCalculator calculator = new SolarEventCalculator(location, config.getTimezone());
|
||||||
|
final Calendar calendar = GregorianCalendar.from(midnight);
|
||||||
|
final Calendar nextCalendar = forDay(calculator, sunrise, new Zenith(zenith), calendar);
|
||||||
|
if (nextCalendar == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(nextCalendar.getTimeInMillis()), midnight.getZone());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Calendar forDay(final SolarEventCalculator calculator, final boolean sunrise, final Zenith solarZenith, final Calendar calendar) {
|
||||||
|
if (sunrise) {
|
||||||
|
return calculator.computeSunriseCalendar(solarZenith, calendar);
|
||||||
|
} else {
|
||||||
|
return calculator.computeSunsetCalendar(solarZenith, calendar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package de.ph87.homeautomation.schedule.astro;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class AstroDto {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final double zenith;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final ZonedDateTime sunrise;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final ZonedDateTime sunset;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final String sunriseName;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final String sunsetName;
|
||||||
|
|
||||||
|
public AstroDto(@NonNull final Astro astro, @NonNull final ZonedDateTime sunrise, @NonNull final ZonedDateTime sunset) {
|
||||||
|
this.zenith = astro.getZenith();
|
||||||
|
this.sunrise = sunrise;
|
||||||
|
this.sunset = sunset;
|
||||||
|
this.sunriseName = astro.getName();
|
||||||
|
this.sunsetName = astro.getDifferentNameForSunset() == null ? astro.getName() : astro.getDifferentNameForSunset();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package de.ph87.homeautomation.schedule.astro;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface AstroRepository extends JpaRepository<Astro, Long> {
|
||||||
|
|
||||||
|
List<Astro> findAllByEnabledTrue();
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
package de.ph87.homeautomation.schedule.astro;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@Transactional
|
||||||
|
@RequestMapping("Astro")
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AstroService {
|
||||||
|
|
||||||
|
private final AstroRepository astroRepository;
|
||||||
|
|
||||||
|
private final AstroCalculator astroCalculator;
|
||||||
|
|
||||||
|
@EventListener(ApplicationStartedEvent.class)
|
||||||
|
public void startup() {
|
||||||
|
if (astroRepository.count() == 0) {
|
||||||
|
astroRepository.save(new Astro(71.0000, "Aufgang +++++", "Untergang +++++"));
|
||||||
|
astroRepository.save(new Astro(75.0000, "Aufgang ++++", "Untergang ++++"));
|
||||||
|
astroRepository.save(new Astro(80.0000, "Aufgang +++", "Untergang +++"));
|
||||||
|
astroRepository.save(new Astro(85.0000, "Aufgang ++", "Untergang ++"));
|
||||||
|
astroRepository.save(new Astro(90.0000, "Aufgang +", "Untergang +"));
|
||||||
|
astroRepository.save(new Astro(90.8333, "Aufgang", "Untergang"));
|
||||||
|
astroRepository.save(new Astro(92.0000, "Aufgang -", null));
|
||||||
|
astroRepository.save(new Astro(93.0000, "Aufgang --", null));
|
||||||
|
astroRepository.save(new Astro(94.0000, "Bürgerlich ++", null));
|
||||||
|
astroRepository.save(new Astro(95.0000, "Bürgerlich +", null));
|
||||||
|
astroRepository.save(new Astro(96.0000, "Bürgerlich", null));
|
||||||
|
astroRepository.save(new Astro(97.0000, "Bürgerlich -", null));
|
||||||
|
astroRepository.save(new Astro(98.0000, "Bürgerlich --", null));
|
||||||
|
astroRepository.save(new Astro(99.0000, "Bürgerlich ---", null));
|
||||||
|
astroRepository.save(new Astro(100.000, "Nautisch ++", null));
|
||||||
|
astroRepository.save(new Astro(101.000, "Nautisch +", null));
|
||||||
|
astroRepository.save(new Astro(102.000, "Nautisch", null));
|
||||||
|
astroRepository.save(new Astro(103.000, "Nautisch -", null));
|
||||||
|
astroRepository.save(new Astro(104.000, "Nautisch --", null));
|
||||||
|
astroRepository.save(new Astro(105.000, "Nautisch ---", null));
|
||||||
|
astroRepository.save(new Astro(106.000, "Astronomisch ++", null));
|
||||||
|
astroRepository.save(new Astro(107.000, "Astronomisch +", null));
|
||||||
|
astroRepository.save(new Astro(108.000, "Astronomisch", null));
|
||||||
|
astroRepository.save(new Astro(110.000, "Astronomisch -", null));
|
||||||
|
astroRepository.save(new Astro(120.000, "Astronomisch --", null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AstroDto> findAllNext() {
|
||||||
|
final ZonedDateTime now = ZonedDateTime.now();
|
||||||
|
return astroRepository.findAllByEnabledTrue().stream().map(astro -> next(now, astro)).filter(Objects::nonNull).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AstroDto next(final ZonedDateTime now, final Astro astro) {
|
||||||
|
final ZonedDateTime sunrise = astroCalculator.next(now, true, astro.getZenith());
|
||||||
|
final ZonedDateTime sunset = astroCalculator.next(now, false, astro.getZenith());
|
||||||
|
if (sunrise == null || sunset == null) {
|
||||||
|
astro.setEnabled(false);
|
||||||
|
astro.setError("sunrise (%s) or sunset (%s) NULL for %s".formatted(sunrise, sunset, now));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new AstroDto(astro, sunrise, sunset);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -74,11 +74,13 @@ public class ScheduleEntry {
|
|||||||
|
|
||||||
private ZonedDateTime nextClearTimestamp;
|
private ZonedDateTime nextClearTimestamp;
|
||||||
|
|
||||||
private ZonedDateTime lastClearTimestamp;
|
|
||||||
|
|
||||||
@Setter(AccessLevel.NONE)
|
@Setter(AccessLevel.NONE)
|
||||||
private ZonedDateTime nextFuzzyTimestamp;
|
private ZonedDateTime nextFuzzyTimestamp;
|
||||||
|
|
||||||
|
private ZonedDateTime lastClearTimestamp;
|
||||||
|
|
||||||
|
private ZonedDateTime lastFuzzyTimestamp;
|
||||||
|
|
||||||
public ScheduleEntry(final Schedule schedule) {
|
public ScheduleEntry(final Schedule schedule) {
|
||||||
this.schedule = schedule;
|
this.schedule = schedule;
|
||||||
this.position = schedule.getEntries().size();
|
this.position = schedule.getEntries().size();
|
||||||
|
|||||||
@ -48,6 +48,8 @@ public class ScheduleEntryDto implements Serializable {
|
|||||||
|
|
||||||
public final ZonedDateTime nextFuzzyTimestamp;
|
public final ZonedDateTime nextFuzzyTimestamp;
|
||||||
|
|
||||||
|
public final ZonedDateTime lastFuzzyTimestamp;
|
||||||
|
|
||||||
public final PropertyDto property;
|
public final PropertyDto property;
|
||||||
|
|
||||||
public final double value;
|
public final double value;
|
||||||
@ -74,6 +76,7 @@ public class ScheduleEntryDto implements Serializable {
|
|||||||
this.nextClearTimestamp = entry.getNextClearTimestamp();
|
this.nextClearTimestamp = entry.getNextClearTimestamp();
|
||||||
this.lastClearTimestamp = entry.getLastClearTimestamp();
|
this.lastClearTimestamp = entry.getLastClearTimestamp();
|
||||||
this.nextFuzzyTimestamp = entry.getNextFuzzyTimestamp();
|
this.nextFuzzyTimestamp = entry.getNextFuzzyTimestamp();
|
||||||
|
this.lastFuzzyTimestamp = entry.getLastFuzzyTimestamp();
|
||||||
this.property = property;
|
this.property = property;
|
||||||
this.value = entry.getValue();
|
this.value = entry.getValue();
|
||||||
this.bulk = bulk;
|
this.bulk = bulk;
|
||||||
|
|||||||
@ -4,4 +4,5 @@ cd "$(dirname "$0")" || exit 1
|
|||||||
|
|
||||||
scp target/Homeautomation-1.0-SNAPSHOT.jar media@10.0.0.50:/home/media/java/Homeautomation/Homeautomation.jar.update &&
|
scp target/Homeautomation-1.0-SNAPSHOT.jar media@10.0.0.50:/home/media/java/Homeautomation/Homeautomation.jar.update &&
|
||||||
git tag "$(date +'deploy---%Y-%m-%d---%H-%M-%S')" &&
|
git tag "$(date +'deploy---%Y-%m-%d---%H-%M-%S')" &&
|
||||||
curl -m 2 -s http://10.0.0.50:8082/server/shutdown
|
curl -m 2 -s http://10.0.0.50:8082/server/shutdown &&
|
||||||
|
exit 0
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user