mqtt, series, meter, varying, Heizung, OpenDTU, SmartMeter, PatrixJson
This commit is contained in:
commit
606ee34731
38
.gitignore
vendored
Normal file
38
.gitignore
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
target/
|
||||||
|
!.mvn/wrapper/maven-wrapper.jar
|
||||||
|
!**/src/main/**/target/
|
||||||
|
!**/src/test/**/target/
|
||||||
|
|
||||||
|
### IntelliJ IDEA ###
|
||||||
|
.idea/modules.xml
|
||||||
|
.idea/jarRepositories.xml
|
||||||
|
.idea/compiler.xml
|
||||||
|
.idea/libraries/
|
||||||
|
*.iws
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
|
||||||
|
### Eclipse ###
|
||||||
|
.apt_generated
|
||||||
|
.classpath
|
||||||
|
.factorypath
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.springBeans
|
||||||
|
.sts4-cache
|
||||||
|
|
||||||
|
### NetBeans ###
|
||||||
|
/nbproject/private/
|
||||||
|
/nbbuild/
|
||||||
|
/dist/
|
||||||
|
/nbdist/
|
||||||
|
/.nb-gradle/
|
||||||
|
build/
|
||||||
|
!**/src/main/**/build/
|
||||||
|
!**/src/test/**/build/
|
||||||
|
|
||||||
|
### VS Code ###
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
### Mac OS ###
|
||||||
|
.DS_Store
|
||||||
10
application.properties
Normal file
10
application.properties
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
logging.level.de.ph87.home=DEBUG
|
||||||
|
#-
|
||||||
|
spring.datasource.url=jdbc:h2:./database;AUTO_SERVER=TRUE
|
||||||
|
spring.datasource.driverClassName=org.h2.Driver
|
||||||
|
spring.datasource.username=sa
|
||||||
|
spring.datasource.password=password
|
||||||
|
#-
|
||||||
|
#spring.jpa.hibernate.ddl-auto=create
|
||||||
|
#-
|
||||||
|
de.ph87.patrix.mqtt.host=10.0.0.50
|
||||||
32
pom.xml
Normal file
32
pom.xml
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<artifactId>Home</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>de.ph87.patrix</groupId>
|
||||||
|
<artifactId>PatrixParent</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>de.ph87.patrix</groupId>
|
||||||
|
<artifactId>PatrixCrud</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>de.ph87.patrix</groupId>
|
||||||
|
<artifactId>PatrixMqtt</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>tech.units</groupId>
|
||||||
|
<artifactId>indriya</artifactId>
|
||||||
|
<version>2.2.2</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
15
src/main/java/de/ph87/home/Backend.java
Normal file
15
src/main/java/de/ph87/home/Backend.java
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package de.ph87.home;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@ComponentScan(basePackages = {"de.ph87.home", "de.ph87.patrix"})
|
||||||
|
public class Backend {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Backend.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
58
src/main/java/de/ph87/home/meter/Meter.java
Normal file
58
src/main/java/de/ph87/home/meter/Meter.java
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package de.ph87.home.meter;
|
||||||
|
|
||||||
|
import de.ph87.home.series.Series;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
import static de.ph87.home.unit.UnitHelper.convert;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Meter {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Version
|
||||||
|
@ToString.Exclude
|
||||||
|
private long version;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@ToString.Exclude
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
private Series series;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@ToString.Include
|
||||||
|
public String series() {
|
||||||
|
return series.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private ZonedDateTime since;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String number;
|
||||||
|
|
||||||
|
@Column(nullable = false, name = "`value`")
|
||||||
|
private double value;
|
||||||
|
|
||||||
|
public Meter(@NonNull final Series series, @NonNull final ZonedDateTime since, @NonNull final String number, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
this.series = series;
|
||||||
|
this.since = since;
|
||||||
|
this.number = number;
|
||||||
|
this.value = convert(value, series.getUnit()).getValue().doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
14
src/main/java/de/ph87/home/meter/MeterRepository.java
Normal file
14
src/main/java/de/ph87/home/meter/MeterRepository.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package de.ph87.home.meter;
|
||||||
|
|
||||||
|
import de.ph87.home.series.Series;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.springframework.data.repository.ListCrudRepository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface MeterRepository extends ListCrudRepository<Meter, Long> {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
Optional<Meter> findFirstBySeriesOrderBySinceDesc(@NonNull final Series series);
|
||||||
|
|
||||||
|
}
|
||||||
29
src/main/java/de/ph87/home/meter/MeterService.java
Normal file
29
src/main/java/de/ph87/home/meter/MeterService.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package de.ph87.home.meter;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValueInbound;
|
||||||
|
import de.ph87.home.series.Series;
|
||||||
|
import de.ph87.home.series.SeriesService;
|
||||||
|
import de.ph87.home.series.Type;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MeterService {
|
||||||
|
|
||||||
|
private final MeterRepository meterRepository;
|
||||||
|
|
||||||
|
private final SeriesService seriesService;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Meter getOrCreate(@NonNull final MeterValueInbound event) {
|
||||||
|
final Series series = seriesService.getOrCreate(event.getName(), Type.METER, event.value.getUnit());
|
||||||
|
return meterRepository.findFirstBySeriesOrderBySinceDesc(series)
|
||||||
|
.filter(meter -> meter.getNumber().equals(event.getNumber()))
|
||||||
|
.orElseGet(() -> meterRepository.save(new Meter(series, event.getDate(), event.getNumber(), event.getValue())));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
19
src/main/java/de/ph87/home/meter/value/MeterPoint.java
Normal file
19
src/main/java/de/ph87/home/meter/value/MeterPoint.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package de.ph87.home.meter.value;
|
||||||
|
|
||||||
|
import de.ph87.home.point.PointResult;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class MeterPoint extends PointResult.Point {
|
||||||
|
|
||||||
|
public final double delta;
|
||||||
|
|
||||||
|
public MeterPoint(@NonNull final ZonedDateTime date, final double delta) {
|
||||||
|
super(date);
|
||||||
|
this.delta = delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
82
src/main/java/de/ph87/home/meter/value/MeterValue.java
Normal file
82
src/main/java/de/ph87/home/meter/value/MeterValue.java
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package de.ph87.home.meter.value;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.Meter;
|
||||||
|
import de.ph87.home.unit.Aligned;
|
||||||
|
import de.ph87.home.unit.Interval;
|
||||||
|
import de.ph87.home.unit.UnitHelper;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@MappedSuperclass
|
||||||
|
@NoArgsConstructor
|
||||||
|
public abstract class MeterValue {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private Id id;
|
||||||
|
|
||||||
|
@Column(nullable = false, updatable = false)
|
||||||
|
private double min;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private double max;
|
||||||
|
|
||||||
|
protected MeterValue(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
this.id = id;
|
||||||
|
this.min = UnitHelper.convert(value, id.meter.getSeries().getUnit()).getValue().doubleValue();
|
||||||
|
this.max = this.min;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(@NonNull final ComparableQuantity<?> value) {
|
||||||
|
final double converted = UnitHelper.convert(value, id.meter.getSeries().getUnit()).getValue().doubleValue();
|
||||||
|
if (converted < min) {
|
||||||
|
throw new RuntimeException("Meter cannot run backwards: MeterValue=%s, inbound=%s".formatted(this, value));
|
||||||
|
}
|
||||||
|
min = Math.min(converted, min);
|
||||||
|
max = Math.max(converted, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Embeddable
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class Id {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@ToString.Exclude
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
private Meter meter;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@ToString.Include
|
||||||
|
public String series() {
|
||||||
|
return meter.series();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@ToString.Include
|
||||||
|
public String meter() {
|
||||||
|
return meter.getNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false, updatable = false)
|
||||||
|
private ZonedDateTime date;
|
||||||
|
|
||||||
|
public Id(@NonNull final Interval interval, @NonNull final ZonedDateTime date, @NonNull final Meter meter) {
|
||||||
|
this.date = new Aligned(date, interval).date;
|
||||||
|
this.meter = meter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "%s()";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package de.ph87.home.meter.value;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class MeterValueInbound {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final String number;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ComparableQuantity<?> value;
|
||||||
|
|
||||||
|
public MeterValueInbound(@NonNull final String name, @NonNull final String number, final long date, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
this(name, number, ZonedDateTime.ofInstant(Instant.ofEpochSecond(date), ZoneId.systemDefault()), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MeterValueInbound(@NonNull final String name, @NonNull final String number, @NonNull final ZonedDateTime date, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
this.name = name;
|
||||||
|
this.number = number;
|
||||||
|
this.date = date;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
package de.ph87.home.meter.value;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.Meter;
|
||||||
|
import de.ph87.home.meter.MeterService;
|
||||||
|
import de.ph87.home.meter.value.day.MeterDay;
|
||||||
|
import de.ph87.home.meter.value.day.MeterDayRepository;
|
||||||
|
import de.ph87.home.meter.value.five.MeterFive;
|
||||||
|
import de.ph87.home.meter.value.five.MeterFiveRepository;
|
||||||
|
import de.ph87.home.meter.value.hour.MeterHour;
|
||||||
|
import de.ph87.home.meter.value.hour.MeterHourRepository;
|
||||||
|
import de.ph87.home.meter.value.month.MeterMonth;
|
||||||
|
import de.ph87.home.meter.value.month.MeterMonthRepository;
|
||||||
|
import de.ph87.home.meter.value.week.MeterWeek;
|
||||||
|
import de.ph87.home.meter.value.week.MeterWeekRepository;
|
||||||
|
import de.ph87.home.meter.value.year.MeterYear;
|
||||||
|
import de.ph87.home.meter.value.year.MeterYearRepository;
|
||||||
|
import de.ph87.home.unit.Interval;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MeterValueReceiver {
|
||||||
|
|
||||||
|
private final MeterFiveRepository meterFiveRepository;
|
||||||
|
|
||||||
|
private final MeterHourRepository meterHourRepository;
|
||||||
|
|
||||||
|
private final MeterDayRepository meterDayRepository;
|
||||||
|
|
||||||
|
private final MeterWeekRepository meterWeekRepository;
|
||||||
|
|
||||||
|
private final MeterMonthRepository meterMonthRepository;
|
||||||
|
|
||||||
|
private final MeterYearRepository meterYearRepository;
|
||||||
|
|
||||||
|
private final MeterService meterService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@EventListener
|
||||||
|
public void onMeterInbound(@NonNull final MeterValueInbound event) {
|
||||||
|
final Meter meter = meterService.getOrCreate(event);
|
||||||
|
updateOrCreate(event, meter, Interval.FIVE, MeterFive::new, meterFiveRepository);
|
||||||
|
updateOrCreate(event, meter, Interval.HOUR, MeterHour::new, meterHourRepository);
|
||||||
|
updateOrCreate(event, meter, Interval.DAY, MeterDay::new, meterDayRepository);
|
||||||
|
updateOrCreate(event, meter, Interval.WEEK, MeterWeek::new, meterWeekRepository);
|
||||||
|
updateOrCreate(event, meter, Interval.MONTH, MeterMonth::new, meterMonthRepository);
|
||||||
|
updateOrCreate(event, meter, Interval.YEAR, MeterYear::new, meterYearRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends MeterValue> void updateOrCreate(
|
||||||
|
@NonNull final MeterValueInbound event,
|
||||||
|
@NonNull final Meter meter,
|
||||||
|
@NonNull final Interval interval,
|
||||||
|
@NonNull final BiFunction<MeterValue.Id, ComparableQuantity<?>, T> create,
|
||||||
|
@NonNull final MeterValueRepository<T> repository
|
||||||
|
) {
|
||||||
|
final MeterYear.Id id = new MeterValue.Id(interval, event.getDate(), meter);
|
||||||
|
repository
|
||||||
|
.findById(id)
|
||||||
|
.ifPresentOrElse(
|
||||||
|
existing -> existing.update(event.getValue()),
|
||||||
|
() -> repository.save(create.apply(id, event.getValue()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package de.ph87.home.meter.value;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.ListCrudRepository;
|
||||||
|
import org.springframework.data.repository.NoRepositoryBean;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@NoRepositoryBean
|
||||||
|
public interface MeterValueRepository<T extends MeterValue> extends ListCrudRepository<T, MeterValue.Id> {
|
||||||
|
|
||||||
|
@Query("select new de.ph87.home.meter.value.MeterPoint(v.id.date, sum(v.max - v.min)) from #{#entityName} v where v.id.meter.series.id = :id and v.id.date >= :first and v.id.date <= :last group by v.id.date")
|
||||||
|
List<MeterPoint> points(@NonNull long id, @NonNull ZonedDateTime first, @NonNull ZonedDateTime last);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
package de.ph87.home.meter.value;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.day.MeterDayRepository;
|
||||||
|
import de.ph87.home.meter.value.five.MeterFiveRepository;
|
||||||
|
import de.ph87.home.meter.value.hour.MeterHourRepository;
|
||||||
|
import de.ph87.home.meter.value.month.MeterMonthRepository;
|
||||||
|
import de.ph87.home.meter.value.week.MeterWeekRepository;
|
||||||
|
import de.ph87.home.meter.value.year.MeterYearRepository;
|
||||||
|
import de.ph87.home.point.PointRequest;
|
||||||
|
import de.ph87.home.series.SeriesDto;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MeterValueService {
|
||||||
|
|
||||||
|
private final MeterFiveRepository meterFiveRepository;
|
||||||
|
|
||||||
|
private final MeterHourRepository meterHourRepository;
|
||||||
|
|
||||||
|
private final MeterDayRepository meterDayRepository;
|
||||||
|
|
||||||
|
private final MeterWeekRepository meterWeekRepository;
|
||||||
|
|
||||||
|
private final MeterMonthRepository meterMonthRepository;
|
||||||
|
|
||||||
|
private final MeterYearRepository meterYearRepository;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public List<MeterPoint> points(@NonNull final SeriesDto series, @NonNull final PointRequest request) {
|
||||||
|
return switch (request.getInner()) {
|
||||||
|
case FIVE -> meterFiveRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
case HOUR -> meterHourRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
case DAY -> meterDayRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
case WEEK -> meterWeekRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
case MONTH -> meterMonthRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
case YEAR -> meterYearRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/meter/value/day/MeterDay.java
Normal file
21
src/main/java/de/ph87/home/meter/value/day/MeterDay.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.meter.value.day;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class MeterDay extends MeterValue {
|
||||||
|
|
||||||
|
public MeterDay(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.meter.value.day;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValueRepository;
|
||||||
|
|
||||||
|
public interface MeterDayRepository extends MeterValueRepository<MeterDay> {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/meter/value/five/MeterFive.java
Normal file
21
src/main/java/de/ph87/home/meter/value/five/MeterFive.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.meter.value.five;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class MeterFive extends MeterValue {
|
||||||
|
|
||||||
|
public MeterFive(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.meter.value.five;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValueRepository;
|
||||||
|
|
||||||
|
public interface MeterFiveRepository extends MeterValueRepository<MeterFive> {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/meter/value/hour/MeterHour.java
Normal file
21
src/main/java/de/ph87/home/meter/value/hour/MeterHour.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.meter.value.hour;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class MeterHour extends MeterValue {
|
||||||
|
|
||||||
|
public MeterHour(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.meter.value.hour;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValueRepository;
|
||||||
|
|
||||||
|
public interface MeterHourRepository extends MeterValueRepository<MeterHour> {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/meter/value/month/MeterMonth.java
Normal file
21
src/main/java/de/ph87/home/meter/value/month/MeterMonth.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.meter.value.month;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class MeterMonth extends MeterValue {
|
||||||
|
|
||||||
|
public MeterMonth(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.meter.value.month;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValueRepository;
|
||||||
|
|
||||||
|
public interface MeterMonthRepository extends MeterValueRepository<MeterMonth> {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/meter/value/week/MeterWeek.java
Normal file
21
src/main/java/de/ph87/home/meter/value/week/MeterWeek.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.meter.value.week;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class MeterWeek extends MeterValue {
|
||||||
|
|
||||||
|
public MeterWeek(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.meter.value.week;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValueRepository;
|
||||||
|
|
||||||
|
public interface MeterWeekRepository extends MeterValueRepository<MeterWeek> {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/meter/value/year/MeterYear.java
Normal file
21
src/main/java/de/ph87/home/meter/value/year/MeterYear.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.meter.value.year;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class MeterYear extends MeterValue {
|
||||||
|
|
||||||
|
public MeterYear(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.meter.value.year;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValueRepository;
|
||||||
|
|
||||||
|
public interface MeterYearRepository extends MeterValueRepository<MeterYear> {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/point/PointController.java
Normal file
21
src/main/java/de/ph87/home/point/PointController.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.point;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("points")
|
||||||
|
public class PointController {
|
||||||
|
|
||||||
|
private final PointService pointService;
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public PointResult request(@RequestBody final PointRequest request) {
|
||||||
|
return pointService.request(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
45
src/main/java/de/ph87/home/point/PointRequest.java
Normal file
45
src/main/java/de/ph87/home/point/PointRequest.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package de.ph87.home.point;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import de.ph87.home.unit.Aligned;
|
||||||
|
import de.ph87.home.unit.Interval;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PointRequest {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final String seriesName;
|
||||||
|
|
||||||
|
public final long offset;
|
||||||
|
|
||||||
|
public final long count;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final Interval outer;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final Interval inner;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@JsonIgnore
|
||||||
|
public final Aligned beginIncluding;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@JsonIgnore
|
||||||
|
public final Aligned endIncluding;
|
||||||
|
|
||||||
|
public PointRequest(@NonNull final String seriesName, final long offset, final long count, @NonNull final Interval outer, @NonNull final Interval inner) {
|
||||||
|
this.seriesName = seriesName;
|
||||||
|
this.offset = offset;
|
||||||
|
this.count = count;
|
||||||
|
this.outer = outer;
|
||||||
|
this.inner = inner;
|
||||||
|
this.endIncluding = new Aligned(ZonedDateTime.now(), outer).minus(offset);
|
||||||
|
this.beginIncluding = endIncluding.minus(this.count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
28
src/main/java/de/ph87/home/point/PointResult.java
Normal file
28
src/main/java/de/ph87/home/point/PointResult.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package de.ph87.home.point;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValue;
|
||||||
|
import de.ph87.home.series.SeriesDto;
|
||||||
|
import de.ph87.home.varying.VaryingValue;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class PointResult {
|
||||||
|
|
||||||
|
public final SeriesDto series;
|
||||||
|
|
||||||
|
public final List<? extends Point> points;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static abstract class Point {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
35
src/main/java/de/ph87/home/point/PointService.java
Normal file
35
src/main/java/de/ph87/home/point/PointService.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package de.ph87.home.point;
|
||||||
|
|
||||||
|
import de.ph87.home.meter.value.MeterValueService;
|
||||||
|
import de.ph87.home.series.SeriesDto;
|
||||||
|
import de.ph87.home.series.SeriesRepository;
|
||||||
|
import de.ph87.home.varying.VaryingValueService;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PointService {
|
||||||
|
|
||||||
|
private final SeriesRepository seriesRepository;
|
||||||
|
|
||||||
|
private final MeterValueService meterValueService;
|
||||||
|
|
||||||
|
private final VaryingValueService varyingValueService;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public PointResult request(@NonNull final PointRequest request) {
|
||||||
|
final SeriesDto series = seriesRepository.findDtoByName(request.getSeriesName()).orElseThrow();
|
||||||
|
final List<? extends PointResult.Point> points = switch (series.getType()) {
|
||||||
|
case METER -> meterValueService.points(series, request);
|
||||||
|
case VARYING -> varyingValueService.points(series, request);
|
||||||
|
};
|
||||||
|
return new PointResult(series, points);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
62
src/main/java/de/ph87/home/receive/HeizungHandler.java
Normal file
62
src/main/java/de/ph87/home/receive/HeizungHandler.java
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package de.ph87.home.receive;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import de.ph87.home.varying.VaryingValueInbound;
|
||||||
|
import de.ph87.patrix.mqtt.MqttEvent;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
import tech.units.indriya.quantity.Quantities;
|
||||||
|
import tech.units.indriya.unit.Units;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class HeizungHandler {
|
||||||
|
|
||||||
|
private static final Pattern REGEX = Pattern.compile("^aggregation/(?<property>heizung/.+)/temperatur$");
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void handle(@NonNull final MqttEvent event) throws Exception {
|
||||||
|
final Matcher matcher = REGEX.matcher(event.topic);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String property = matcher.group("property");
|
||||||
|
final Inbound inbound = objectMapper.readValue(event.payload, Inbound.class);
|
||||||
|
applicationEventPublisher.publishEvent(new VaryingValueInbound(property, inbound.date, inbound.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
private static class Inbound {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
|
public final ComparableQuantity<?> value;
|
||||||
|
|
||||||
|
public Inbound(final long timestamp, final double sum, final int count) {
|
||||||
|
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
||||||
|
this.value = Quantities.getQuantity(sum / count, Units.CELSIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
83
src/main/java/de/ph87/home/receive/OpenDTUHandler.java
Normal file
83
src/main/java/de/ph87/home/receive/OpenDTUHandler.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package de.ph87.home.receive;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import de.ph87.home.meter.value.MeterValueInbound;
|
||||||
|
import de.ph87.home.varying.VaryingValueInbound;
|
||||||
|
import de.ph87.patrix.mqtt.MqttEvent;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
import tech.units.indriya.quantity.Quantities;
|
||||||
|
import tech.units.indriya.unit.Units;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
import static de.ph87.home.unit.UnitHelper.ENERGY_KILOWATT_HOUR;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class OpenDTUHandler {
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void handle(@NonNull final MqttEvent event) throws Exception {
|
||||||
|
if (!"openDTU/pv/patrix/json2".equals(event.topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Inbound inbound = objectMapper.readValue(event.payload, Inbound.class);
|
||||||
|
applicationEventPublisher.publishEvent(new VaryingValueInbound("electricity/producing", inbound.date, inbound.producing));
|
||||||
|
applicationEventPublisher.publishEvent(new MeterValueInbound("electricity/produced", inbound.inverter, inbound.date, inbound.produced));
|
||||||
|
applicationEventPublisher.publishEvent(new VaryingValueInbound("electricity/producing/string0", inbound.date, inbound.producing0));
|
||||||
|
applicationEventPublisher.publishEvent(new MeterValueInbound("electricity/produced/string0", inbound.inverter, inbound.date, inbound.produced0));
|
||||||
|
applicationEventPublisher.publishEvent(new VaryingValueInbound("electricity/producing/string1", inbound.date, inbound.producing1));
|
||||||
|
applicationEventPublisher.publishEvent(new MeterValueInbound("electricity/produced/string1", inbound.inverter, inbound.date, inbound.produced1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public static class Inbound {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final String inverter;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
|
public final ComparableQuantity<?> produced;
|
||||||
|
|
||||||
|
public final ComparableQuantity<?> producing;
|
||||||
|
|
||||||
|
public final ComparableQuantity<?> produced0;
|
||||||
|
|
||||||
|
public final ComparableQuantity<?> producing0;
|
||||||
|
|
||||||
|
public final ComparableQuantity<?> produced1;
|
||||||
|
|
||||||
|
public final ComparableQuantity<?> producing1;
|
||||||
|
|
||||||
|
public Inbound(final long timestamp, @NonNull final String inverter, final double totalKWh, final double totalW, final double string0KWh, final double string0W, final double string1KWh, final double string1W) {
|
||||||
|
this.inverter = inverter;
|
||||||
|
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
||||||
|
this.produced = Quantities.getQuantity(totalKWh, ENERGY_KILOWATT_HOUR);
|
||||||
|
this.producing = Quantities.getQuantity(totalW, Units.WATT);
|
||||||
|
this.produced0 = Quantities.getQuantity(string0KWh, ENERGY_KILOWATT_HOUR);
|
||||||
|
this.producing0 = Quantities.getQuantity(string0W, Units.WATT);
|
||||||
|
this.produced1 = Quantities.getQuantity(string1KWh, ENERGY_KILOWATT_HOUR);
|
||||||
|
this.producing1 = Quantities.getQuantity(string1W, Units.WATT);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
73
src/main/java/de/ph87/home/receive/PatrixJsonHandler.java
Normal file
73
src/main/java/de/ph87/home/receive/PatrixJsonHandler.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package de.ph87.home.receive;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import de.ph87.home.meter.value.MeterValueInbound;
|
||||||
|
import de.ph87.home.unit.PatrixUnit;
|
||||||
|
import de.ph87.home.varying.VaryingValueInbound;
|
||||||
|
import de.ph87.patrix.mqtt.MqttEvent;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import tech.units.indriya.quantity.Quantities;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PatrixJsonHandler {
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void handle(@NonNull final MqttEvent event) throws Exception {
|
||||||
|
if (!event.topic.endsWith("/PatrixJson")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Inbound inbound = objectMapper.readValue(event.payload, Inbound.class);
|
||||||
|
applicationEventPublisher.publishEvent(inbound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||||
|
@JsonSubTypes({
|
||||||
|
@JsonSubTypes.Type(name = "VARYING", value = Varying.class),
|
||||||
|
@JsonSubTypes.Type(name = "METER", value = Meter.class),
|
||||||
|
})
|
||||||
|
private interface Inbound {
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
VARYING,
|
||||||
|
METER,
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public static class Varying extends VaryingValueInbound implements Inbound {
|
||||||
|
|
||||||
|
protected Varying(@NonNull final String name, final long date, final double value, @NonNull final PatrixUnit unit) {
|
||||||
|
super(name, ZonedDateTime.ofInstant(Instant.ofEpochSecond(date), ZoneId.systemDefault()), Quantities.getQuantity(value, unit.unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public static class Meter extends MeterValueInbound implements Inbound {
|
||||||
|
|
||||||
|
protected Meter(@NonNull final String name, @NonNull final String number, final long date, final double value, @NonNull final PatrixUnit unit) {
|
||||||
|
super(name, number, ZonedDateTime.ofInstant(Instant.ofEpochSecond(date), ZoneId.systemDefault()), Quantities.getQuantity(value, unit.unit));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
86
src/main/java/de/ph87/home/receive/SmartMeterHandler.java
Normal file
86
src/main/java/de/ph87/home/receive/SmartMeterHandler.java
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package de.ph87.home.receive;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import de.ph87.home.meter.value.MeterValueInbound;
|
||||||
|
import de.ph87.home.varying.VaryingValueInbound;
|
||||||
|
import de.ph87.patrix.mqtt.MqttEvent;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.ToString;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
import tech.units.indriya.quantity.Quantities;
|
||||||
|
|
||||||
|
import javax.measure.quantity.Energy;
|
||||||
|
import javax.measure.quantity.Power;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
import static de.ph87.home.unit.UnitHelper.*;
|
||||||
|
import static tech.units.indriya.unit.Units.WATT;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SmartMeterHandler {
|
||||||
|
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
|
|
||||||
|
@EventListener
|
||||||
|
public void handle(@NonNull final MqttEvent event) throws Exception {
|
||||||
|
if (!"electricity/grid/json".equals(event.topic)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Inbound inbound = objectMapper.readValue(event.payload, Inbound.class);
|
||||||
|
applicationEventPublisher.publishEvent(new MeterValueInbound("electricity/purchased", inbound.number, inbound.date, inbound.purchased));
|
||||||
|
applicationEventPublisher.publishEvent(new MeterValueInbound("electricity/delivered", inbound.number, inbound.date, inbound.delivered));
|
||||||
|
applicationEventPublisher.publishEvent(new VaryingValueInbound("electricity/purchasing", inbound.date, inbound.purchasing));
|
||||||
|
applicationEventPublisher.publishEvent(new VaryingValueInbound("electricity/delivering", inbound.date, inbound.delivering));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public static class Inbound {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public String number = "1ZPA0020300305"; // TODO implement in smart-meter firmware
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
|
public final ComparableQuantity<Energy> purchased;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ComparableQuantity<Energy> delivered;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ComparableQuantity<Power> purchasing;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ComparableQuantity<Power> delivering;
|
||||||
|
|
||||||
|
public Inbound(
|
||||||
|
final long timestamp,
|
||||||
|
@NonNull final BigDecimal purchaseWh,
|
||||||
|
@NonNull final BigDecimal deliveryWh,
|
||||||
|
@NonNull final BigDecimal powerW
|
||||||
|
) {
|
||||||
|
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
||||||
|
this.purchased = Quantities.getQuantity(purchaseWh, ENERGY_WATT_HOUR);
|
||||||
|
this.delivered = Quantities.getQuantity(deliveryWh, ENERGY_WATT_HOUR);
|
||||||
|
final ComparableQuantity<Power> power = Quantities.getQuantity(powerW, WATT);
|
||||||
|
this.purchasing = zeroIfNegative(power);
|
||||||
|
this.delivering = zeroIfNegative(negate(power));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
49
src/main/java/de/ph87/home/series/Series.java
Normal file
49
src/main/java/de/ph87/home/series/Series.java
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package de.ph87.home.series;
|
||||||
|
|
||||||
|
import de.ph87.home.unit.PatrixUnit;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Series {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private long id;
|
||||||
|
|
||||||
|
@Version
|
||||||
|
@ToString.Exclude
|
||||||
|
private long version;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false, updatable = false)
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private Type type;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false, updatable = false)
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private PatrixUnit unit;
|
||||||
|
|
||||||
|
public Series(@NonNull final String name, @NonNull final Type type, @NonNull final PatrixUnit unit) {
|
||||||
|
this.name = name;
|
||||||
|
this.title = name;
|
||||||
|
this.type = type;
|
||||||
|
this.unit = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
32
src/main/java/de/ph87/home/series/SeriesDto.java
Normal file
32
src/main/java/de/ph87/home/series/SeriesDto.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package de.ph87.home.series;
|
||||||
|
|
||||||
|
import de.ph87.home.unit.PatrixUnit;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class SeriesDto {
|
||||||
|
|
||||||
|
public final long id;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final String title;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final Type type;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final PatrixUnit unit;
|
||||||
|
|
||||||
|
public SeriesDto(@NonNull final Series series) {
|
||||||
|
this.id = series.getId();
|
||||||
|
this.name = series.getName();
|
||||||
|
this.title = series.getTitle();
|
||||||
|
this.type = series.getType();
|
||||||
|
this.unit = series.getUnit();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
src/main/java/de/ph87/home/series/SeriesRepository.java
Normal file
16
src/main/java/de/ph87/home/series/SeriesRepository.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package de.ph87.home.series;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.ListCrudRepository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface SeriesRepository extends ListCrudRepository<Series, Long> {
|
||||||
|
|
||||||
|
Optional<Series> findByName(@NonNull String name);
|
||||||
|
|
||||||
|
@Query("select new de.ph87.home.series.SeriesDto(s) from Series s where s.name = :name")
|
||||||
|
Optional<SeriesDto> findDtoByName(@NonNull String name);
|
||||||
|
|
||||||
|
}
|
||||||
29
src/main/java/de/ph87/home/series/SeriesService.java
Normal file
29
src/main/java/de/ph87/home/series/SeriesService.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package de.ph87.home.series;
|
||||||
|
|
||||||
|
import de.ph87.home.unit.PatrixUnit;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.measure.Unit;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class SeriesService {
|
||||||
|
|
||||||
|
private final SeriesRepository seriesRepository;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Transactional
|
||||||
|
public Series getOrCreate(@NonNull final String name, final @NonNull Type type, @NonNull final Unit<?> unit) {
|
||||||
|
return seriesRepository.findByName(name).orElseGet(() -> {
|
||||||
|
final Series fresh = new Series(name, type, PatrixUnit.from(unit));
|
||||||
|
log.info("Series CREATED: {}", fresh);
|
||||||
|
return seriesRepository.save(fresh);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
6
src/main/java/de/ph87/home/series/Type.java
Normal file
6
src/main/java/de/ph87/home/series/Type.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package de.ph87.home.series;
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
VARYING,
|
||||||
|
METER,
|
||||||
|
}
|
||||||
32
src/main/java/de/ph87/home/unit/Aligned.java
Normal file
32
src/main/java/de/ph87/home/unit/Aligned.java
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package de.ph87.home.unit;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Aligned {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final Interval interval;
|
||||||
|
|
||||||
|
public Aligned(@NonNull final ZonedDateTime date, @NonNull final Interval interval) {
|
||||||
|
this.date = interval.align.apply(date);
|
||||||
|
this.interval = interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Aligned(@NonNull final Aligned aligned, final long plusAmount) {
|
||||||
|
this.date = aligned.interval.plus.apply(aligned.date, plusAmount);
|
||||||
|
this.interval = aligned.interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public Aligned minus(final long amount) {
|
||||||
|
return new Aligned(this, -amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
29
src/main/java/de/ph87/home/unit/Interval.java
Normal file
29
src/main/java/de/ph87/home/unit/Interval.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package de.ph87.home.unit;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public enum Interval {
|
||||||
|
FIVE(date -> date.truncatedTo(ChronoUnit.MINUTES).minusMinutes(date.getMinute() % 5), (date, amount) -> date.plusMinutes(5 * amount)),
|
||||||
|
HOUR(date -> date.truncatedTo(ChronoUnit.HOURS), ZonedDateTime::plusHours),
|
||||||
|
DAY(date -> date.truncatedTo(ChronoUnit.DAYS), ZonedDateTime::plusDays),
|
||||||
|
WEEK(date -> date.truncatedTo(ChronoUnit.DAYS).minusDays(date.getDayOfWeek().getValue() - 1), (date, amount) -> date.plusDays(7 * amount)),
|
||||||
|
MONTH(date -> date.truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1), ZonedDateTime::plusMonths),
|
||||||
|
YEAR(date -> date.truncatedTo(ChronoUnit.DAYS).withDayOfYear(1), ZonedDateTime::plusYears),
|
||||||
|
;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final Function<ZonedDateTime, ZonedDateTime> align;
|
||||||
|
|
||||||
|
public final BiFunction<ZonedDateTime, Long, ZonedDateTime> plus;
|
||||||
|
|
||||||
|
Interval(@NonNull final Function<ZonedDateTime, ZonedDateTime> align, final BiFunction<ZonedDateTime, Long, ZonedDateTime> plus) {
|
||||||
|
this.align = align;
|
||||||
|
this.plus = plus;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
45
src/main/java/de/ph87/home/unit/PatrixUnit.java
Normal file
45
src/main/java/de/ph87/home/unit/PatrixUnit.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package de.ph87.home.unit;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
import tech.units.indriya.AbstractUnit;
|
||||||
|
import tech.units.indriya.unit.Units;
|
||||||
|
|
||||||
|
import javax.measure.Quantity;
|
||||||
|
import javax.measure.Unit;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static de.ph87.home.unit.UnitHelper.ENERGY_KILOWATT_HOUR;
|
||||||
|
|
||||||
|
public enum PatrixUnit {
|
||||||
|
BOOLEAN(AbstractUnit.ONE),
|
||||||
|
VOLUME_L(Units.LITRE),
|
||||||
|
VOLUME_MM3(Units.LITRE.divide(1000000)),
|
||||||
|
LENGTH_CM(Units.METRE.divide(100)),
|
||||||
|
|
||||||
|
POWER_W(Units.WATT),
|
||||||
|
ENERGY_KWH(ENERGY_KILOWATT_HOUR),
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
IAQ(AbstractUnit.ONE),
|
||||||
|
IAQ_CO2_EQUIVALENT(AbstractUnit.ONE),
|
||||||
|
IAQ_VOC_EQUIVALENT(AbstractUnit.ONE),
|
||||||
|
PRESSURE_HPA(AbstractUnit.ONE),
|
||||||
|
TEMPERATURE_C(Units.CELSIUS),
|
||||||
|
HUMIDITY_RELATIVE_PERCENT(AbstractUnit.ONE),
|
||||||
|
HUMIDITY_ABSOLUTE_GM3(AbstractUnit.ONE),
|
||||||
|
SUN_DC(AbstractUnit.ONE),
|
||||||
|
;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final Unit<? extends Quantity<?>> unit;
|
||||||
|
|
||||||
|
<T extends Quantity<T>> PatrixUnit(@NonNull final Unit<T> unit) {
|
||||||
|
this.unit = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static PatrixUnit from(@NonNull final Unit<?> unit) {
|
||||||
|
return Arrays.stream(values()).filter(u -> u.unit.isCompatible(unit)).findFirst().orElseThrow();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
28
src/main/java/de/ph87/home/unit/QuantityConverter.java
Normal file
28
src/main/java/de/ph87/home/unit/QuantityConverter.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package de.ph87.home.unit;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
|
import jakarta.persistence.AttributeConverter;
|
||||||
|
import jakarta.persistence.Converter;
|
||||||
|
import tech.units.indriya.format.SimpleQuantityFormat;
|
||||||
|
|
||||||
|
import javax.measure.Quantity;
|
||||||
|
import javax.measure.format.QuantityFormat;
|
||||||
|
|
||||||
|
@Converter(autoApply = true)
|
||||||
|
public class QuantityConverter implements AttributeConverter<Quantity<?>, String> {
|
||||||
|
|
||||||
|
public static final QuantityFormat FORMAT = SimpleQuantityFormat.getInstance();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String convertToDatabaseColumn(@Nullable Quantity<?> quantity) {
|
||||||
|
return quantity == null ? null : FORMAT.format(quantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Quantity<?> convertToEntityAttribute(@Nullable String string) {
|
||||||
|
return string == null ? null : FORMAT.parse(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
src/main/java/de/ph87/home/unit/UnitHelper.java
Normal file
41
src/main/java/de/ph87/home/unit/UnitHelper.java
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package de.ph87.home.unit;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
import tech.units.indriya.quantity.Quantities;
|
||||||
|
|
||||||
|
import javax.measure.MetricPrefix;
|
||||||
|
import javax.measure.Quantity;
|
||||||
|
import javax.measure.Unit;
|
||||||
|
import javax.measure.quantity.Energy;
|
||||||
|
|
||||||
|
import static tech.units.indriya.unit.Units.HOUR;
|
||||||
|
import static tech.units.indriya.unit.Units.WATT;
|
||||||
|
|
||||||
|
public class UnitHelper {
|
||||||
|
|
||||||
|
public static final Unit<Energy> ENERGY_WATT_HOUR = WATT.multiply(HOUR).asType(Energy.class);
|
||||||
|
|
||||||
|
public static final Unit<Energy> ENERGY_KILOWATT_HOUR = MetricPrefix.KILO(ENERGY_WATT_HOUR);
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static <T extends Quantity<T>> ComparableQuantity<T> zeroIfNegative(final ComparableQuantity<T> value) {
|
||||||
|
final ComparableQuantity<T> zero = Quantities.getQuantity(0, value.getUnit());
|
||||||
|
return value.isGreaterThanOrEqualTo(zero) ? value : zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static <T extends Quantity<T>> ComparableQuantity<T> negate(final ComparableQuantity<T> value) {
|
||||||
|
return value.multiply(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static <Q extends Quantity<Q>> ComparableQuantity<Q> convert(@NonNull final ComparableQuantity<?> value, @NonNull final PatrixUnit unit) {
|
||||||
|
if (!value.getUnit().isCompatible(unit.unit)) {
|
||||||
|
throw new RuntimeException("Incompatible units: value=%s, targetUnit=%s".formatted(value, unit));
|
||||||
|
}
|
||||||
|
//noinspection unchecked
|
||||||
|
return ((ComparableQuantity<Q>) value).to((Unit<Q>) unit.unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
25
src/main/java/de/ph87/home/varying/VaryingPoint.java
Normal file
25
src/main/java/de/ph87/home/varying/VaryingPoint.java
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package de.ph87.home.varying;
|
||||||
|
|
||||||
|
import de.ph87.home.point.PointResult;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class VaryingPoint extends PointResult.Point {
|
||||||
|
|
||||||
|
public final double min;
|
||||||
|
|
||||||
|
public final double max;
|
||||||
|
|
||||||
|
public final double avg;
|
||||||
|
|
||||||
|
public VaryingPoint(@NonNull final ZonedDateTime date, final double min, final double max, final double avg) {
|
||||||
|
super(date);
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
this.avg = avg;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
80
src/main/java/de/ph87/home/varying/VaryingValue.java
Normal file
80
src/main/java/de/ph87/home/varying/VaryingValue.java
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package de.ph87.home.varying;
|
||||||
|
|
||||||
|
import de.ph87.home.series.Series;
|
||||||
|
import de.ph87.home.unit.Aligned;
|
||||||
|
import de.ph87.home.unit.Interval;
|
||||||
|
import jakarta.persistence.*;
|
||||||
|
import lombok.*;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
import static de.ph87.home.unit.UnitHelper.convert;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@MappedSuperclass
|
||||||
|
@NoArgsConstructor
|
||||||
|
public abstract class VaryingValue {
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private Id id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private double min;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private double max;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private double avg;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private long count;
|
||||||
|
|
||||||
|
protected VaryingValue(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
this.id = id;
|
||||||
|
final double converted = convert(value, id.series.getUnit()).getValue().doubleValue();
|
||||||
|
this.min = converted;
|
||||||
|
this.max = converted;
|
||||||
|
this.avg = converted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(@NonNull final ComparableQuantity<?> value) {
|
||||||
|
final double converted = convert(value, id.series.getUnit()).getValue().doubleValue();
|
||||||
|
min = Math.min(min, converted);
|
||||||
|
max = Math.max(max, converted);
|
||||||
|
avg = (avg * count + converted) / (count + 1);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
@Embeddable
|
||||||
|
@EqualsAndHashCode
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class Id {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@ToString.Exclude
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
private Series series;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@ToString.Include
|
||||||
|
public String series() {
|
||||||
|
return series.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Column(nullable = false, updatable = false)
|
||||||
|
private ZonedDateTime date;
|
||||||
|
|
||||||
|
public Id(@NonNull final Interval interval, @NonNull final ZonedDateTime date, @NonNull final Series series) {
|
||||||
|
this.date = new Aligned(date, interval).date;
|
||||||
|
this.series = series;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
33
src/main/java/de/ph87/home/varying/VaryingValueInbound.java
Normal file
33
src/main/java/de/ph87/home/varying/VaryingValueInbound.java
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package de.ph87.home.varying;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class VaryingValueInbound {
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public final ComparableQuantity<?> value;
|
||||||
|
|
||||||
|
public VaryingValueInbound(@NonNull final String name, final long date, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
this(name, ZonedDateTime.ofInstant(Instant.ofEpochSecond(date), ZoneId.systemDefault()), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VaryingValueInbound(@NonNull final String name, @NonNull final ZonedDateTime date, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
this.name = name;
|
||||||
|
this.date = date;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
76
src/main/java/de/ph87/home/varying/VaryingValueReceiver.java
Normal file
76
src/main/java/de/ph87/home/varying/VaryingValueReceiver.java
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package de.ph87.home.varying;
|
||||||
|
|
||||||
|
import de.ph87.home.series.Series;
|
||||||
|
import de.ph87.home.series.SeriesService;
|
||||||
|
import de.ph87.home.series.Type;
|
||||||
|
import de.ph87.home.unit.Interval;
|
||||||
|
import de.ph87.home.varying.day.VaryingDay;
|
||||||
|
import de.ph87.home.varying.day.VaryingDayRepository;
|
||||||
|
import de.ph87.home.varying.five.VaryingFive;
|
||||||
|
import de.ph87.home.varying.five.VaryingFiveRepository;
|
||||||
|
import de.ph87.home.varying.hour.VaryingHour;
|
||||||
|
import de.ph87.home.varying.hour.VaryingHourRepository;
|
||||||
|
import de.ph87.home.varying.month.VaryingMonth;
|
||||||
|
import de.ph87.home.varying.month.VaryingMonthRepository;
|
||||||
|
import de.ph87.home.varying.week.VaryingWeek;
|
||||||
|
import de.ph87.home.varying.week.VaryingWeekRepository;
|
||||||
|
import de.ph87.home.varying.year.VaryingYear;
|
||||||
|
import de.ph87.home.varying.year.VaryingYearRepository;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VaryingValueReceiver {
|
||||||
|
|
||||||
|
private final VaryingFiveRepository varyingFiveRepository;
|
||||||
|
|
||||||
|
private final VaryingHourRepository varyingHourRepository;
|
||||||
|
|
||||||
|
private final VaryingDayRepository varyingDayRepository;
|
||||||
|
|
||||||
|
private final VaryingWeekRepository varyingWeekRepository;
|
||||||
|
|
||||||
|
private final VaryingMonthRepository varyingMonthRepository;
|
||||||
|
|
||||||
|
private final VaryingYearRepository varyingYearRepository;
|
||||||
|
|
||||||
|
private final SeriesService seriesService;
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@EventListener
|
||||||
|
public void onVaryingInbound(@NonNull final VaryingValueInbound event) {
|
||||||
|
final Series series = seriesService.getOrCreate(event.getName(), Type.VARYING, event.value.getUnit());
|
||||||
|
updateOrCreate(event, series, Interval.FIVE, VaryingFive::new, varyingFiveRepository);
|
||||||
|
updateOrCreate(event, series, Interval.HOUR, VaryingHour::new, varyingHourRepository);
|
||||||
|
updateOrCreate(event, series, Interval.DAY, VaryingDay::new, varyingDayRepository);
|
||||||
|
updateOrCreate(event, series, Interval.WEEK, VaryingWeek::new, varyingWeekRepository);
|
||||||
|
updateOrCreate(event, series, Interval.MONTH, VaryingMonth::new, varyingMonthRepository);
|
||||||
|
updateOrCreate(event, series, Interval.YEAR, VaryingYear::new, varyingYearRepository);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends VaryingValue> void updateOrCreate(
|
||||||
|
@NonNull final VaryingValueInbound event,
|
||||||
|
@NonNull final Series series,
|
||||||
|
@NonNull final Interval interval,
|
||||||
|
@NonNull final BiFunction<VaryingValue.Id, ComparableQuantity<?>, T> create,
|
||||||
|
@NonNull final VaryingValueRepository<T> repository
|
||||||
|
) {
|
||||||
|
final VaryingYear.Id id = new VaryingValue.Id(interval, event.getDate(), series);
|
||||||
|
repository
|
||||||
|
.findById(id)
|
||||||
|
.ifPresentOrElse(
|
||||||
|
existing -> existing.update(event.getValue()),
|
||||||
|
() -> repository.save(create.apply(id, event.getValue()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
package de.ph87.home.varying;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.ListCrudRepository;
|
||||||
|
import org.springframework.data.repository.NoRepositoryBean;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@NoRepositoryBean
|
||||||
|
public interface VaryingValueRepository<T extends VaryingValue> extends ListCrudRepository<T, VaryingValue.Id> {
|
||||||
|
|
||||||
|
@Query("select new de.ph87.home.varying.VaryingPoint(v.id.date, v.min, v.max, v.avg) from #{#entityName} v where v.id.series.id = :id and v.id.date >= :begin and v.id.date < :end")
|
||||||
|
List<VaryingPoint> points(@NonNull final long seriesId, @NonNull final ZonedDateTime begin, @NonNull final ZonedDateTime end);
|
||||||
|
|
||||||
|
}
|
||||||
45
src/main/java/de/ph87/home/varying/VaryingValueService.java
Normal file
45
src/main/java/de/ph87/home/varying/VaryingValueService.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package de.ph87.home.varying;
|
||||||
|
|
||||||
|
import de.ph87.home.point.PointRequest;
|
||||||
|
import de.ph87.home.series.SeriesDto;
|
||||||
|
import de.ph87.home.varying.day.VaryingDayRepository;
|
||||||
|
import de.ph87.home.varying.five.VaryingFiveRepository;
|
||||||
|
import de.ph87.home.varying.hour.VaryingHourRepository;
|
||||||
|
import de.ph87.home.varying.month.VaryingMonthRepository;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class VaryingValueService {
|
||||||
|
|
||||||
|
private final VaryingFiveRepository varyingFiveRepository;
|
||||||
|
|
||||||
|
private final VaryingHourRepository varyingHourRepository;
|
||||||
|
|
||||||
|
private final VaryingDayRepository varyingDayRepository;
|
||||||
|
|
||||||
|
private final de.ph87.home.varying.week.VaryingWeekRepository varyingWeekRepository;
|
||||||
|
|
||||||
|
private final VaryingMonthRepository varyingMonthRepository;
|
||||||
|
|
||||||
|
private final de.ph87.home.varying.year.VaryingYearRepository varyingYearRepository;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public List<VaryingPoint> points(@NonNull final SeriesDto series, @NonNull final PointRequest request) {
|
||||||
|
return switch (request.getInner()) {
|
||||||
|
case FIVE -> varyingFiveRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
case HOUR -> varyingHourRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
case DAY -> varyingDayRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
case WEEK -> varyingWeekRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
case MONTH -> varyingMonthRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
case YEAR -> varyingYearRepository.points(series.id, request.beginIncluding.date, request.endIncluding.date);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/varying/day/VaryingDay.java
Normal file
21
src/main/java/de/ph87/home/varying/day/VaryingDay.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.varying.day;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class VaryingDay extends VaryingValue {
|
||||||
|
|
||||||
|
public VaryingDay(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.varying.day;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValueRepository;
|
||||||
|
|
||||||
|
public interface VaryingDayRepository extends VaryingValueRepository<VaryingDay> {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/varying/five/VaryingFive.java
Normal file
21
src/main/java/de/ph87/home/varying/five/VaryingFive.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.varying.five;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class VaryingFive extends VaryingValue {
|
||||||
|
|
||||||
|
public VaryingFive(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.varying.five;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValueRepository;
|
||||||
|
|
||||||
|
public interface VaryingFiveRepository extends VaryingValueRepository<VaryingFive> {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/varying/hour/VaryingHour.java
Normal file
21
src/main/java/de/ph87/home/varying/hour/VaryingHour.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.varying.hour;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class VaryingHour extends VaryingValue {
|
||||||
|
|
||||||
|
public VaryingHour(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.varying.hour;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValueRepository;
|
||||||
|
|
||||||
|
public interface VaryingHourRepository extends VaryingValueRepository<VaryingHour> {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/varying/month/VaryingMonth.java
Normal file
21
src/main/java/de/ph87/home/varying/month/VaryingMonth.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.varying.month;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class VaryingMonth extends VaryingValue {
|
||||||
|
|
||||||
|
public VaryingMonth(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.varying.month;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValueRepository;
|
||||||
|
|
||||||
|
public interface VaryingMonthRepository extends VaryingValueRepository<VaryingMonth> {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/varying/week/VaryingWeek.java
Normal file
21
src/main/java/de/ph87/home/varying/week/VaryingWeek.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.varying.week;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class VaryingWeek extends VaryingValue {
|
||||||
|
|
||||||
|
public VaryingWeek(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.varying.week;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValueRepository;
|
||||||
|
|
||||||
|
public interface VaryingWeekRepository extends VaryingValueRepository<VaryingWeek> {
|
||||||
|
|
||||||
|
}
|
||||||
21
src/main/java/de/ph87/home/varying/year/VaryingYear.java
Normal file
21
src/main/java/de/ph87/home/varying/year/VaryingYear.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package de.ph87.home.varying.year;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValue;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import lombok.ToString;
|
||||||
|
import tech.units.indriya.ComparableQuantity;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@ToString(callSuper = true)
|
||||||
|
public class VaryingYear extends VaryingValue {
|
||||||
|
|
||||||
|
public VaryingYear(@NonNull final Id id, @NonNull final ComparableQuantity<?> value) {
|
||||||
|
super(id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package de.ph87.home.varying.year;
|
||||||
|
|
||||||
|
import de.ph87.home.varying.VaryingValueRepository;
|
||||||
|
|
||||||
|
public interface VaryingYearRepository extends VaryingValueRepository<VaryingYear> {
|
||||||
|
|
||||||
|
}
|
||||||
10
src/main/resources/application.properties
Normal file
10
src/main/resources/application.properties
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
logging.level.root=WARN
|
||||||
|
logging.level.de.ph87=INFO
|
||||||
|
#-
|
||||||
|
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl
|
||||||
|
spring.jpa.hibernate.ddl-auto=update
|
||||||
|
spring.jpa.open-in-view=false
|
||||||
|
#-
|
||||||
|
spring.jackson.serialization.indent_output=true
|
||||||
|
#-
|
||||||
|
spring.main.banner-mode=off
|
||||||
Loading…
Reference in New Issue
Block a user