Compare commits
3 Commits
85a749f199
...
5358f1b9f6
| Author | SHA1 | Date | |
|---|---|---|---|
| 5358f1b9f6 | |||
| d81034e6c4 | |||
| 49ce44eff9 |
@ -4,7 +4,7 @@ import {map, Subscription} from 'rxjs';
|
||||
import {StompService} from '@stomp/ng2-stompjs';
|
||||
import {FromJson, Next} from './types';
|
||||
|
||||
const DEV_TO_PROD = true;
|
||||
const DEV_TO_PROD = false;
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
|
||||
@ -28,6 +28,14 @@ export class Unit {
|
||||
|
||||
static readonly ILLUMINANCE_LUX = new Unit('ILLUMINANCE_LUX', 'lux');
|
||||
|
||||
static readonly BOOLEAN = new Unit('BOOLEAN', '');
|
||||
|
||||
static readonly DOOR_BOOLEAN = new Unit('DOOR_BOOLEAN', '');
|
||||
|
||||
static readonly WINDOW_BOOLEAN = new Unit('WINDOW_BOOLEAN', '');
|
||||
|
||||
static readonly LIGHT_BOOLEAN = new Unit('LIGHT_BOOLEAN', '');
|
||||
|
||||
private constructor(
|
||||
readonly name: string,
|
||||
readonly unit: string,
|
||||
|
||||
@ -53,18 +53,44 @@ export class Value {
|
||||
return new Value(-this.value, this.unit, this.decimals, this.locale);
|
||||
}
|
||||
|
||||
plus(other: Value | undefined): Value | undefined {
|
||||
if (!other) {
|
||||
return undefined;
|
||||
}
|
||||
return new Value(this.value + other.value, this.unit, this.decimals, this.locale);
|
||||
plus(other: Value | number | undefined | null): Value | undefined {
|
||||
const v = this.extractValue(other);
|
||||
return v === undefined ? undefined : new Value(this.value + v, this.unit, this.decimals, this.locale);
|
||||
}
|
||||
|
||||
minus(other: Value | undefined): Value | undefined {
|
||||
if (!other) {
|
||||
minus(other: Value | number | undefined | null): Value | undefined {
|
||||
const v = this.extractValue(other);
|
||||
return v === undefined ? undefined : new Value(this.value - v, this.unit, this.decimals, this.locale);
|
||||
}
|
||||
|
||||
gte(other: Value | number | undefined | null): boolean | undefined {
|
||||
const v = this.extractValue(other);
|
||||
return v === undefined ? undefined : this.value >= v;
|
||||
}
|
||||
|
||||
gt(other: Value | number | undefined | null): boolean | undefined {
|
||||
const v = this.extractValue(other);
|
||||
return v === undefined ? undefined : this.value > v;
|
||||
}
|
||||
|
||||
lte(other: Value | number | undefined | null): boolean | undefined {
|
||||
const v = this.extractValue(other);
|
||||
return v === undefined ? undefined : this.value <= v;
|
||||
}
|
||||
|
||||
lt(other: Value | number | undefined | null): boolean | undefined {
|
||||
const v = this.extractValue(other);
|
||||
return v === undefined ? undefined : this.value < v;
|
||||
}
|
||||
|
||||
extractValue(other: Value | number | undefined | null): number | undefined {
|
||||
if (other === undefined || other === null) {
|
||||
return undefined;
|
||||
}
|
||||
return new Value(this.value - other.value, this.unit, this.decimals, this.locale);
|
||||
if (other instanceof Value && other.unit !== this.unit) {
|
||||
throw new Error(`Unit mismatch: this=${JSON.stringify(this)}, other=${JSON.stringify(other)}`);
|
||||
}
|
||||
return typeof other === "number" ? other : other.value;
|
||||
}
|
||||
|
||||
notNegative(): Value {
|
||||
|
||||
@ -8,6 +8,7 @@ export class WeatherHour {
|
||||
readonly clouds: Value,
|
||||
readonly irradiation: Value,
|
||||
readonly precipitation: Value,
|
||||
readonly temperature: Value,
|
||||
) {
|
||||
//
|
||||
}
|
||||
@ -18,6 +19,7 @@ export class WeatherHour {
|
||||
Value.fromJson2(json['clouds'], locale),
|
||||
Value.fromJson2(json['irradiation'], locale),
|
||||
Value.fromJson2(json['precipitation'], locale),
|
||||
Value.fromJson2(json['temperature'], locale),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -4,9 +4,22 @@
|
||||
</div>
|
||||
<div class="day">
|
||||
<div class="hour" *ngFor="let hour of hours">
|
||||
<div class="bar weekdayHolder" *ngIf="hour.date.getHours() === 8">
|
||||
{{ dateFormat(hour.date | date:'E') }}
|
||||
</div>
|
||||
<div class="bar clouds" [style.height]="clouds(hour)"></div>
|
||||
<div class="bar precipitation" [style.height]="precipitation(hour)"></div>
|
||||
<div class="bar irradiation" [style.height]="irradiation(hour)"></div>
|
||||
<div class="bar precipitation" [style.height]="precipitation(hour)"></div>
|
||||
<div class="bar temperature" [style.height]="temperature(hour)" [ngClass]="temperatureClasses(hour)"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="legend">
|
||||
<span class="line temperatureGTE30">≥30°C</span>
|
||||
<span class="line temperatureGTE20">≥20°C</span>
|
||||
<span class="line temperatureGTE10">≥10°C</span>
|
||||
<span class="line temperatureGT0">>0°C</span>
|
||||
<span class="line temperatureNegative">≤0°C</span>
|
||||
<span class="line"> </span>
|
||||
<span class="line">Niederschlag 100% = {{ PRECIPITATION_MAX_MM }}mm</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
width: 100%; // any width will do (flex cares about real with)
|
||||
overflow: visible;
|
||||
|
||||
.bar {
|
||||
position: absolute;
|
||||
@ -25,8 +26,73 @@
|
||||
|
||||
.precipitation {
|
||||
background-color: blue;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.temperature {
|
||||
border-top: 0.06em solid black;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.temperatureGTE30 {
|
||||
border-top-color: red;
|
||||
}
|
||||
|
||||
.temperatureGTE20 {
|
||||
border-top-color: orange;
|
||||
}
|
||||
|
||||
.temperatureGTE10 {
|
||||
border-top-color: yellow;
|
||||
}
|
||||
|
||||
.temperatureGT0 {
|
||||
border-top-color: blue;
|
||||
}
|
||||
|
||||
.temperatureNegative {
|
||||
border-top-color: white;
|
||||
}
|
||||
|
||||
.weekdayHolder {
|
||||
overflow: visible;
|
||||
opacity: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.legend {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
|
||||
.line {
|
||||
padding: 0 0.25em;
|
||||
font-size: 50%;
|
||||
}
|
||||
|
||||
.temperatureGTE30 {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.temperatureGTE20 {
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.temperatureGTE10 {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
.temperatureGT0 {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.temperatureNegative {
|
||||
color: white;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {NgForOf} from '@angular/common';
|
||||
import {DatePipe, NgClass, NgForOf, NgIf} from '@angular/common';
|
||||
import {WeatherHour} from './WeatherHour';
|
||||
import {WeatherService} from './weather.service';
|
||||
import {WeatherDay} from './WeatherDay';
|
||||
@ -11,13 +11,18 @@ const DAY_COUNT = 7;
|
||||
@Component({
|
||||
selector: 'app-weather-diagram',
|
||||
imports: [
|
||||
NgForOf
|
||||
NgForOf,
|
||||
NgIf,
|
||||
DatePipe,
|
||||
NgClass
|
||||
],
|
||||
templateUrl: './weather-diagram.component.html',
|
||||
styleUrl: './weather-diagram.component.less'
|
||||
})
|
||||
export class WeatherDiagramComponent implements OnInit {
|
||||
|
||||
protected readonly PRECIPITATION_MAX_MM = 15;
|
||||
|
||||
protected days: WeatherDay[] = [];
|
||||
|
||||
protected hours: WeatherHour[] = [];
|
||||
@ -44,7 +49,11 @@ export class WeatherDiagramComponent implements OnInit {
|
||||
}
|
||||
|
||||
precipitation(hour: WeatherHour) {
|
||||
return (hour.precipitation.percent(15)?.value || 0) + '%';
|
||||
return (hour.precipitation.percent(this.PRECIPITATION_MAX_MM)?.value || 0) + '%';
|
||||
}
|
||||
|
||||
temperature(hour: WeatherHour) {
|
||||
return (hour.temperature.plus(10)?.percent(50)?.value || 0) + '%';
|
||||
}
|
||||
|
||||
private updateHours() {
|
||||
@ -74,4 +83,26 @@ export class WeatherDiagramComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
dateFormat(date: string | null) {
|
||||
if (!date) {
|
||||
return "";
|
||||
}
|
||||
return date.substring(0, 2);
|
||||
}
|
||||
|
||||
temperatureClasses(hour: WeatherHour): {} {
|
||||
const temperatureGTE30 = hour.temperature.gte(30);
|
||||
const temperatureGTE20 = hour.temperature.gte(20);
|
||||
const temperatureGTE10 = hour.temperature.gte(10);
|
||||
const temperatureGT0 = hour.temperature.gt(0);
|
||||
const temperatureNegative = hour.temperature.lte(0);
|
||||
return {
|
||||
"temperatureGTE30": temperatureGTE30,
|
||||
"temperatureGTE20": temperatureGTE20 && !temperatureGTE30,
|
||||
"temperatureGTE10": temperatureGTE10 && !temperatureGTE20,
|
||||
"temperatureGT0": temperatureGT0 && !temperatureGTE10,
|
||||
"temperatureNegative": temperatureNegative
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -45,6 +45,11 @@ public enum Unit {
|
||||
IRRADIATION_KWH_M2("kWh/m²", 1000, IRRADIATION_WH_M2),
|
||||
|
||||
PRECIPITATION_MM("mm"),
|
||||
|
||||
BOOLEAN(""),
|
||||
DOOR_BOOLEAN("", 1, BOOLEAN),
|
||||
WINDOW_BOOLEAN("", 1, BOOLEAN),
|
||||
LIGHT_BOOLEAN("", 1, BOOLEAN),
|
||||
;
|
||||
|
||||
public final String unit;
|
||||
|
||||
@ -60,6 +60,18 @@ public class BrightSkyDto {
|
||||
this.timestamp = timestamp.withZoneSameInstant(TimeZone.getDefault().toZoneId());
|
||||
}
|
||||
|
||||
public double getSolar() {
|
||||
return solar == null ? 0.0 : solar;
|
||||
}
|
||||
|
||||
public double getCloud_cover() {
|
||||
return cloud_cover == null ? 0.0 : cloud_cover;
|
||||
}
|
||||
|
||||
public double getPrecipitation() {
|
||||
return precipitation == null ? 0.0 : precipitation;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,13 +1,18 @@
|
||||
package de.ph87.data.weather;
|
||||
|
||||
import de.ph87.data.value.Unit;
|
||||
import de.ph87.data.value.Value;
|
||||
import de.ph87.data.value.*;
|
||||
import lombok.*;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.*;
|
||||
import java.time.*;
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Data
|
||||
@ToString(includeFieldNames = false)
|
||||
@ -67,11 +72,15 @@ public class WeatherDay {
|
||||
@NonNull
|
||||
public final Value precipitation;
|
||||
|
||||
@NonNull
|
||||
public final Value temperature;
|
||||
|
||||
public Hour(@NonNull final BrightSkyDto.Weather dto) {
|
||||
date = dto.getTimestamp();
|
||||
clouds = new Value(dto.getCloud_cover(), Unit.CLOUD_COVER_PERCENT);
|
||||
irradiation = new Value(dto.getSolar() * 1000, Unit.IRRADIATION_WH_M2);
|
||||
precipitation = new Value(dto.getPrecipitation(), Unit.PRECIPITATION_MM);
|
||||
temperature = new Value((dto.getTemperature()), Unit.TEMPERATURE_C);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user