code clean
This commit is contained in:
parent
908134600c
commit
e005f1ef8c
@ -5,9 +5,9 @@ import org.springframework.boot.autoconfigure.*;
|
|||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class Backend {
|
public class Backend {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(Backend.class, args);
|
SpringApplication.run(Backend.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -3,7 +3,7 @@ package de.ph87.data.message;
|
|||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
public interface IMessageHandler {
|
public interface IMessageHandler {
|
||||||
|
|
||||||
void handle(@NonNull final Message message) throws Exception;
|
void handle(@NonNull final Message message) throws Exception;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,18 +5,18 @@ import lombok.*;
|
|||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
public class Message {
|
public class Message {
|
||||||
|
|
||||||
public final String topic;
|
public final String topic;
|
||||||
|
|
||||||
@ToString.Exclude
|
@ToString.Exclude
|
||||||
public final String payload;
|
public final String payload;
|
||||||
|
|
||||||
public final String payloadLoggable;
|
public final String payloadLoggable;
|
||||||
|
|
||||||
public Message(final String topic, final String payload) {
|
public Message(final String topic, final String payload) {
|
||||||
this.topic = topic;
|
this.topic = topic;
|
||||||
this.payload = payload;
|
this.payload = payload;
|
||||||
this.payloadLoggable = payload.replace("\n", "\\n").replace("\r", "\\r");
|
this.payloadLoggable = payload.replace("\n", "\\n").replace("\r", "\\r");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,9 +10,9 @@ import java.util.*;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class MessageService {
|
public class MessageService {
|
||||||
|
|
||||||
private final List<IMessageHandler> messageHandlers;
|
private final List<IMessageHandler> messageHandlers;
|
||||||
|
|
||||||
public void handle(@NonNull final Message message) {
|
public void handle(@NonNull final Message message) {
|
||||||
messageHandlers.forEach(handler -> {
|
messageHandlers.forEach(handler -> {
|
||||||
try {
|
try {
|
||||||
@ -22,5 +22,5 @@ public class MessageService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,8 +6,7 @@ import com.fasterxml.jackson.databind.annotation.*;
|
|||||||
import de.ph87.data.message.*;
|
import de.ph87.data.message.*;
|
||||||
import de.ph87.data.series.*;
|
import de.ph87.data.series.*;
|
||||||
import de.ph87.data.series.entry.*;
|
import de.ph87.data.series.entry.*;
|
||||||
import de.ph87.data.unit.Value;
|
import de.ph87.data.value.Value;
|
||||||
import de.ph87.data.unit.*;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.extern.slf4j.*;
|
import lombok.extern.slf4j.*;
|
||||||
import org.springframework.stereotype.*;
|
import org.springframework.stereotype.*;
|
||||||
@ -21,13 +20,13 @@ import java.util.stream.*;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class EspHomeHandler implements IMessageHandler {
|
public class EspHomeHandler implements IMessageHandler {
|
||||||
|
|
||||||
private static final Pattern REGEX = Pattern.compile("^(?<area>\\w+)/sensor/(?<property>\\w+)$");
|
private static final Pattern REGEX = Pattern.compile("^(?<area>\\w+)/sensor/(?<property>\\w+)$");
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
private final EntryService entryService;
|
private final EntryService entryService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(@NonNull final Message message) throws Exception {
|
public void handle(@NonNull final Message message) throws Exception {
|
||||||
final Matcher matcher = REGEX.matcher(message.topic);
|
final Matcher matcher = REGEX.matcher(message.topic);
|
||||||
@ -37,15 +36,15 @@ public class EspHomeHandler implements IMessageHandler {
|
|||||||
final String area = matcher.group("area");
|
final String area = matcher.group("area");
|
||||||
final String property = propertyReplace(matcher.group("property"));
|
final String property = propertyReplace(matcher.group("property"));
|
||||||
final String name = "%s/%s".formatted(area, property.replace("_", "/"));
|
final String name = "%s/%s".formatted(area, property.replace("_", "/"));
|
||||||
final Unit targetUnit = switch (property) {
|
final Value.Unit targetUnit = switch (property) {
|
||||||
case "iaq" -> Unit.IAQ;
|
case "iaq" -> Value.Unit.IAQ;
|
||||||
case "iaq_co2" -> Unit.IAQ_CO2_EQUIVALENT;
|
case "iaq_co2" -> Value.Unit.IAQ_CO2_EQUIVALENT;
|
||||||
case "iaq_voc" -> Unit.IAQ_VOC_EQUIVALENT;
|
case "iaq_voc" -> Value.Unit.IAQ_VOC_EQUIVALENT;
|
||||||
case "pressure" -> Unit.PRESSURE_HPA;
|
case "pressure" -> Value.Unit.PRESSURE_HPA;
|
||||||
case "temperature" -> Unit.TEMPERATURE_C;
|
case "temperature" -> Value.Unit.TEMPERATURE_C;
|
||||||
case "humidity_relative" -> Unit.HUMIDITY_RELATIVE_PERCENT;
|
case "humidity_relative" -> Value.Unit.HUMIDITY_RELATIVE_PERCENT;
|
||||||
case "humidity_absolute" -> Unit.HUMIDITY_ABSOLUTE_GM3;
|
case "humidity_absolute" -> Value.Unit.HUMIDITY_ABSOLUTE_GM3;
|
||||||
case "sun" -> Unit.SUN_DC;
|
case "sun" -> Value.Unit.SUN_DC;
|
||||||
default -> null;
|
default -> null;
|
||||||
};
|
};
|
||||||
if (targetUnit == null) {
|
if (targetUnit == null) {
|
||||||
@ -53,7 +52,7 @@ public class EspHomeHandler implements IMessageHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Inbound inbound = objectMapper.readValue(message.payload, Inbound.class);
|
final Inbound inbound = objectMapper.readValue(message.payload, Inbound.class);
|
||||||
final Unit unitFromPayload = inbound.units.stream().filter(ufp -> ufp.base == targetUnit.base).findFirst().orElse(null);
|
final Value.Unit unitFromPayload = inbound.units.stream().filter(ufp -> ufp.base == targetUnit.base).findFirst().orElse(null);
|
||||||
if (unitFromPayload == null) {
|
if (unitFromPayload == null) {
|
||||||
log.error("Unit mismatch: fromTopic={}, fromPayload=[{}]", targetUnit, inbound.getUnits().stream().map(Enum::name).collect(Collectors.joining(",")));
|
log.error("Unit mismatch: fromTopic={}, fromPayload=[{}]", targetUnit, inbound.getUnits().stream().map(Enum::name).collect(Collectors.joining(",")));
|
||||||
return;
|
return;
|
||||||
@ -61,7 +60,7 @@ public class EspHomeHandler implements IMessageHandler {
|
|||||||
final Value value = new Value(inbound.value, unitFromPayload);
|
final Value value = new Value(inbound.value, unitFromPayload);
|
||||||
entryService.receive(new SeriesInbound(name, inbound.date, value.as(targetUnit)));
|
entryService.receive(new SeriesInbound(name, inbound.date, value.as(targetUnit)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String propertyReplace(final String property) {
|
private String propertyReplace(final String property) {
|
||||||
if ("iaq_co2_equivalent".equals(property)) {
|
if ("iaq_co2_equivalent".equals(property)) {
|
||||||
return "iaq_co2";
|
return "iaq_co2";
|
||||||
@ -71,26 +70,26 @@ public class EspHomeHandler implements IMessageHandler {
|
|||||||
}
|
}
|
||||||
return property;
|
return property;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
private static class Inbound {
|
private static class Inbound {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final ZonedDateTime date;
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
public final double value;
|
public final double value;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@JsonDeserialize(using = UnitListDeserializer.class)
|
@JsonDeserialize(using = Value.Unit.ListDeserializer.class)
|
||||||
public final List<Unit> units;
|
public final List<Value.Unit> units;
|
||||||
|
|
||||||
public Inbound(final long timestamp, final double value, @JsonProperty("unit") @NonNull final List<Unit> units) {
|
public Inbound(final long timestamp, final double value, @JsonProperty("unit") @NonNull final List<Value.Unit> units) {
|
||||||
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.units = units;
|
this.units = units;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,7 @@ import com.fasterxml.jackson.databind.*;
|
|||||||
import de.ph87.data.message.*;
|
import de.ph87.data.message.*;
|
||||||
import de.ph87.data.series.*;
|
import de.ph87.data.series.*;
|
||||||
import de.ph87.data.series.entry.*;
|
import de.ph87.data.series.entry.*;
|
||||||
import de.ph87.data.unit.Value;
|
import de.ph87.data.value.Value;
|
||||||
import de.ph87.data.unit.*;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.extern.slf4j.*;
|
import lombok.extern.slf4j.*;
|
||||||
import org.springframework.stereotype.*;
|
import org.springframework.stereotype.*;
|
||||||
@ -17,13 +16,13 @@ import java.util.regex.*;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class HeizungHandler implements IMessageHandler {
|
public class HeizungHandler implements IMessageHandler {
|
||||||
|
|
||||||
private static final Pattern REGEX = Pattern.compile("^aggregation/(?<property>heizung/.+)/temperatur$");
|
private static final Pattern REGEX = Pattern.compile("^aggregation/(?<property>heizung/.+)/temperatur$");
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
private final EntryService entryService;
|
private final EntryService entryService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(@NonNull final Message message) throws Exception {
|
public void handle(@NonNull final Message message) throws Exception {
|
||||||
final Matcher matcher = REGEX.matcher(message.topic);
|
final Matcher matcher = REGEX.matcher(message.topic);
|
||||||
@ -34,21 +33,21 @@ public class HeizungHandler implements IMessageHandler {
|
|||||||
final Inbound inbound = objectMapper.readValue(message.payload, Inbound.class);
|
final Inbound inbound = objectMapper.readValue(message.payload, Inbound.class);
|
||||||
entryService.receive(new SeriesInbound(property, inbound.date, inbound.value));
|
entryService.receive(new SeriesInbound(property, inbound.date, inbound.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
private static class Inbound {
|
private static class Inbound {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final ZonedDateTime date;
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
public final Value value;
|
public final Value value;
|
||||||
|
|
||||||
public Inbound(final long timestamp, final double sum, final int count) {
|
public Inbound(final long timestamp, final double sum, final int count) {
|
||||||
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
||||||
this.value = new Value(sum / count, Unit.TEMPERATURE_C);
|
this.value = new Value(sum / count, Value.Unit.TEMPERATURE_C);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,7 @@ import com.fasterxml.jackson.databind.*;
|
|||||||
import de.ph87.data.message.*;
|
import de.ph87.data.message.*;
|
||||||
import de.ph87.data.series.*;
|
import de.ph87.data.series.*;
|
||||||
import de.ph87.data.series.entry.*;
|
import de.ph87.data.series.entry.*;
|
||||||
import de.ph87.data.unit.Value;
|
import de.ph87.data.value.Value;
|
||||||
import de.ph87.data.unit.*;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.extern.slf4j.*;
|
import lombok.extern.slf4j.*;
|
||||||
import org.springframework.stereotype.*;
|
import org.springframework.stereotype.*;
|
||||||
@ -16,38 +15,38 @@ import java.time.*;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class OpenDTUHandler implements IMessageHandler {
|
public class OpenDTUHandler implements IMessageHandler {
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
private final EntryService entryService;
|
private final EntryService entryService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(final @NonNull Message message) throws Exception {
|
public void handle(final @NonNull Message message) throws Exception {
|
||||||
if (!"openDTU/pv/patrix/json".equals(message.topic)) {
|
if (!"openDTU/pv/patrix/json".equals(message.topic)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Inbound inbound = objectMapper.readValue(message.payload, Inbound.class);
|
final Inbound inbound = objectMapper.readValue(message.payload, Inbound.class);
|
||||||
entryService.receive(new SeriesInbound("electricity/energy/produced", inbound.date, inbound.energy.as(Unit.ENERGY_KWH)));
|
entryService.receive(new SeriesInbound("electricity/energy/produced", inbound.date, inbound.energy.as(Value.Unit.ENERGY_KWH)));
|
||||||
entryService.receive(new SeriesInbound("electricity/power/produced", inbound.date, inbound.power.as(Unit.POWER_W)));
|
entryService.receive(new SeriesInbound("electricity/power/produced", inbound.date, inbound.power.as(Value.Unit.POWER_W)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
private static class Inbound {
|
private static class Inbound {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final ZonedDateTime date;
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
public final Value energy;
|
public final Value energy;
|
||||||
|
|
||||||
public final Value power;
|
public final Value power;
|
||||||
|
|
||||||
public Inbound(final long timestamp, final double energyProducedKWh, final double powerW) {
|
public Inbound(final long timestamp, final double energyProducedKWh, final double powerW) {
|
||||||
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
||||||
this.energy = new Value(energyProducedKWh, Unit.ENERGY_KWH);
|
this.energy = new Value(energyProducedKWh, Value.Unit.ENERGY_KWH);
|
||||||
this.power = new Value(powerW, Unit.POWER_W);
|
this.power = new Value(powerW, Value.Unit.POWER_W);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,7 @@ import com.fasterxml.jackson.databind.*;
|
|||||||
import de.ph87.data.message.*;
|
import de.ph87.data.message.*;
|
||||||
import de.ph87.data.series.*;
|
import de.ph87.data.series.*;
|
||||||
import de.ph87.data.series.entry.*;
|
import de.ph87.data.series.entry.*;
|
||||||
import de.ph87.data.unit.Value;
|
import de.ph87.data.value.Value;
|
||||||
import de.ph87.data.unit.*;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.extern.slf4j.*;
|
import lombok.extern.slf4j.*;
|
||||||
import org.springframework.stereotype.*;
|
import org.springframework.stereotype.*;
|
||||||
@ -16,11 +15,11 @@ import java.time.*;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class SimpleJsonHandler implements IMessageHandler {
|
public class SimpleJsonHandler implements IMessageHandler {
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
private final EntryService entryService;
|
private final EntryService entryService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(@NonNull final Message message) throws Exception {
|
public void handle(@NonNull final Message message) throws Exception {
|
||||||
if (!message.topic.endsWith("/SimpleJson")) {
|
if (!message.topic.endsWith("/SimpleJson")) {
|
||||||
@ -29,25 +28,25 @@ public class SimpleJsonHandler implements IMessageHandler {
|
|||||||
final Inbound inbound = objectMapper.readValue(message.payload, Inbound.class);
|
final Inbound inbound = objectMapper.readValue(message.payload, Inbound.class);
|
||||||
entryService.receive(new SeriesInbound(inbound.name, inbound.date, inbound.value));
|
entryService.receive(new SeriesInbound(inbound.name, inbound.date, inbound.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
private static class Inbound {
|
private static class Inbound {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final ZonedDateTime date;
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
public final Value value;
|
public final Value value;
|
||||||
|
|
||||||
public Inbound(@NonNull final String name, final long timestamp, final double value, @NonNull final Unit unit) {
|
public Inbound(@NonNull final String name, final long timestamp, final double value, @NonNull final Value.Unit unit) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
||||||
this.value = new Value(value, unit);
|
this.value = new Value(value, unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,7 @@ import com.fasterxml.jackson.databind.*;
|
|||||||
import de.ph87.data.message.*;
|
import de.ph87.data.message.*;
|
||||||
import de.ph87.data.series.*;
|
import de.ph87.data.series.*;
|
||||||
import de.ph87.data.series.entry.*;
|
import de.ph87.data.series.entry.*;
|
||||||
import de.ph87.data.unit.Value;
|
import de.ph87.data.value.Value;
|
||||||
import de.ph87.data.unit.*;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.extern.slf4j.*;
|
import lombok.extern.slf4j.*;
|
||||||
import org.springframework.stereotype.*;
|
import org.springframework.stereotype.*;
|
||||||
@ -16,42 +15,42 @@ import java.time.*;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class SmartMeterHandler implements IMessageHandler {
|
public class SmartMeterHandler implements IMessageHandler {
|
||||||
|
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
private final EntryService entryService;
|
private final EntryService entryService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(@NonNull final Message message) throws Exception {
|
public void handle(@NonNull final Message message) throws Exception {
|
||||||
if (!"electricity/grid/json".equals(message.topic)) {
|
if (!"electricity/grid/json".equals(message.topic)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Inbound inbound = objectMapper.readValue(message.payload, Inbound.class);
|
final Inbound inbound = objectMapper.readValue(message.payload, Inbound.class);
|
||||||
entryService.receive(new SeriesInbound("electricity/energy/purchased", inbound.date, inbound.energyPurchased.as(Unit.ENERGY_KWH)));
|
entryService.receive(new SeriesInbound("electricity/energy/purchased", inbound.date, inbound.energyPurchased.as(Value.Unit.ENERGY_KWH)));
|
||||||
entryService.receive(new SeriesInbound("electricity/energy/delivered", inbound.date, inbound.energyDelivered.as(Unit.ENERGY_KWH)));
|
entryService.receive(new SeriesInbound("electricity/energy/delivered", inbound.date, inbound.energyDelivered.as(Value.Unit.ENERGY_KWH)));
|
||||||
entryService.receive(new SeriesInbound("electricity/power/difference", inbound.date, inbound.powerDifference.as(Unit.POWER_W)));
|
entryService.receive(new SeriesInbound("electricity/power/difference", inbound.date, inbound.powerDifference.as(Value.Unit.POWER_W)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
private static class Inbound {
|
private static class Inbound {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final ZonedDateTime date;
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
public final Value energyPurchased;
|
public final Value energyPurchased;
|
||||||
|
|
||||||
public final Value energyDelivered;
|
public final Value energyDelivered;
|
||||||
|
|
||||||
public final Value powerDifference;
|
public final Value powerDifference;
|
||||||
|
|
||||||
public Inbound(final long timestamp, final double purchaseWh, final double deliveryWh, final double powerW) {
|
public Inbound(final long timestamp, final double purchaseWh, final double deliveryWh, final double powerW) {
|
||||||
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
|
||||||
this.energyPurchased = new Value(purchaseWh, Unit.ENERGY_WH);
|
this.energyPurchased = new Value(purchaseWh, Value.Unit.ENERGY_WH);
|
||||||
this.energyDelivered = new Value(deliveryWh, Unit.ENERGY_WH);
|
this.energyDelivered = new Value(deliveryWh, Value.Unit.ENERGY_WH);
|
||||||
this.powerDifference = new Value(powerW, Unit.POWER_W);
|
this.powerDifference = new Value(powerW, Value.Unit.POWER_W);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,19 +8,19 @@ import org.springframework.stereotype.*;
|
|||||||
@Component
|
@Component
|
||||||
@ConfigurationProperties(prefix = "de.ph87.data.message.receive.mqtt")
|
@ConfigurationProperties(prefix = "de.ph87.data.message.receive.mqtt")
|
||||||
public class MqttConfig {
|
public class MqttConfig {
|
||||||
|
|
||||||
private String host;
|
private String host;
|
||||||
|
|
||||||
private int port = 1883;
|
private int port = 1883;
|
||||||
|
|
||||||
private String topic;
|
private String topic;
|
||||||
|
|
||||||
private String clientId;
|
private String clientId;
|
||||||
|
|
||||||
private int connectTimeoutSec = 3;
|
private int connectTimeoutSec = 3;
|
||||||
|
|
||||||
private long retrySec = 3;
|
private long retrySec = 3;
|
||||||
|
|
||||||
private int connectKeepAliveSec = 3;
|
private int connectKeepAliveSec = 3;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,23 +17,23 @@ import java.util.*;
|
|||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class MqttReceiver {
|
public class MqttReceiver {
|
||||||
|
|
||||||
private final MqttConfig config;
|
private final MqttConfig config;
|
||||||
|
|
||||||
private final MessageService messageService;
|
private final MessageService messageService;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private MqttClient client;
|
private MqttClient client;
|
||||||
|
|
||||||
private final Thread thread = new Thread(this::run, "MQTT-WATCH");
|
private final Thread thread = new Thread(this::run, "MQTT-WATCH");
|
||||||
|
|
||||||
private boolean stop = false;
|
private boolean stop = false;
|
||||||
|
|
||||||
@EventListener(ApplicationStartedEvent.class)
|
@EventListener(ApplicationStartedEvent.class)
|
||||||
public void startup() {
|
public void startup() {
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PreDestroy
|
@PreDestroy
|
||||||
public void preDestroy() {
|
public void preDestroy() {
|
||||||
synchronized (thread) {
|
synchronized (thread) {
|
||||||
@ -42,7 +42,7 @@ public class MqttReceiver {
|
|||||||
log.debug("stopping...");
|
log.debug("stopping...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void run() {
|
private void run() {
|
||||||
try {
|
try {
|
||||||
log.debug("started");
|
log.debug("started");
|
||||||
@ -63,7 +63,7 @@ public class MqttReceiver {
|
|||||||
log.debug("terminated");
|
log.debug("terminated");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _connect() throws InterruptedException {
|
private void _connect() throws InterruptedException {
|
||||||
final String clientId;
|
final String clientId;
|
||||||
final boolean cleanSession;
|
final boolean cleanSession;
|
||||||
@ -97,7 +97,7 @@ public class MqttReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _disconnect() {
|
private void _disconnect() {
|
||||||
if (client != null && client.isConnected()) {
|
if (client != null && client.isConnected()) {
|
||||||
try {
|
try {
|
||||||
@ -107,7 +107,7 @@ public class MqttReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void _receive(final String topic, final MqttMessage mqttMessage) {
|
private void _receive(final String topic, final MqttMessage mqttMessage) {
|
||||||
Thread.currentThread().setName("MQTT-RECEIVE");
|
Thread.currentThread().setName("MQTT-RECEIVE");
|
||||||
final String payload = new String(mqttMessage.getPayload(), StandardCharsets.UTF_8);
|
final String payload = new String(mqttMessage.getPayload(), StandardCharsets.UTF_8);
|
||||||
@ -115,5 +115,5 @@ public class MqttReceiver {
|
|||||||
log.debug("received: {}", message);
|
log.debug("received: {}", message);
|
||||||
messageService.handle(message);
|
messageService.handle(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package de.ph87.data.series;
|
package de.ph87.data.series;
|
||||||
|
|
||||||
import de.ph87.data.unit.*;
|
import de.ph87.data.value.Value;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
@ -9,35 +9,35 @@ import lombok.*;
|
|||||||
@ToString
|
@ToString
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
public class Series {
|
public class Series {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private long id;
|
private long id;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false, unique = true)
|
@Column(nullable = false, unique = true)
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false, unique = true)
|
@Column(nullable = false, unique = true)
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private Unit unit;
|
private Value.Unit unit;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private int decimals = 1;
|
private int decimals = 1;
|
||||||
|
|
||||||
public Series(@NonNull final String name, @NonNull final Unit unit) {
|
public Series(@NonNull final String name, @NonNull final Value.Unit unit) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.title = name;
|
this.title = name;
|
||||||
this.unit = unit;
|
this.unit = unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +1,23 @@
|
|||||||
package de.ph87.data.series;
|
package de.ph87.data.series;
|
||||||
|
|
||||||
import de.ph87.data.unit.*;
|
import de.ph87.data.value.Value;
|
||||||
import jakarta.annotation.*;
|
import jakarta.annotation.*;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
public class SeriesDto {
|
public class SeriesDto {
|
||||||
|
|
||||||
public final long id;
|
public final long id;
|
||||||
|
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
public final String title;
|
public final String title;
|
||||||
|
|
||||||
public final Unit unit;
|
public final Value.Unit unit;
|
||||||
|
|
||||||
public final int decimals;
|
public final int decimals;
|
||||||
|
|
||||||
public SeriesDto(@NonNull final Series series) {
|
public SeriesDto(@NonNull final Series series) {
|
||||||
this.id = series.getId();
|
this.id = series.getId();
|
||||||
this.name = series.getName();
|
this.name = series.getName();
|
||||||
@ -25,12 +25,12 @@ public class SeriesDto {
|
|||||||
this.unit = series.getUnit();
|
this.unit = series.getUnit();
|
||||||
this.decimals = series.getDecimals();
|
this.decimals = series.getDecimals();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String format(@Nullable final Double value) {
|
public String format(@Nullable final Double value) {
|
||||||
if (value == null || Double.isNaN(value)) {
|
if (value == null || Double.isNaN(value)) {
|
||||||
return "--- %s".formatted(unit.unit);
|
return "--- %s".formatted(unit.unit);
|
||||||
}
|
}
|
||||||
return "%%.%df %%s".formatted(decimals).formatted(value, unit.unit);
|
return "%%.%df %%s".formatted(decimals).formatted(value, unit.unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package de.ph87.data.series;
|
package de.ph87.data.series;
|
||||||
|
|
||||||
import de.ph87.data.unit.Value;
|
import de.ph87.data.value.Value;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
import java.time.*;
|
import java.time.*;
|
||||||
@ -8,19 +8,19 @@ import java.time.*;
|
|||||||
@Getter
|
@Getter
|
||||||
@ToString
|
@ToString
|
||||||
public class SeriesInbound {
|
public class SeriesInbound {
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final String name;
|
public final String name;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public final ZonedDateTime date;
|
public final ZonedDateTime date;
|
||||||
|
|
||||||
public final Value value;
|
public final Value value;
|
||||||
|
|
||||||
public SeriesInbound(@NonNull final String name, @NonNull final ZonedDateTime date, final Value value) {
|
public SeriesInbound(@NonNull final String name, @NonNull final ZonedDateTime date, final Value value) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.date = date;
|
this.date = date;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import org.springframework.data.repository.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public interface SeriesRepository extends ListCrudRepository<Series, Long> {
|
public interface SeriesRepository extends ListCrudRepository<Series, Long> {
|
||||||
|
|
||||||
Optional<Series> findByName(@NonNull String name);
|
Optional<Series> findByName(@NonNull String name);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package de.ph87.data.series;
|
package de.ph87.data.series;
|
||||||
|
|
||||||
import de.ph87.data.*;
|
import de.ph87.data.*;
|
||||||
import de.ph87.data.unit.*;
|
import de.ph87.data.value.Value;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.extern.slf4j.*;
|
import lombok.extern.slf4j.*;
|
||||||
import org.springframework.stereotype.*;
|
import org.springframework.stereotype.*;
|
||||||
@ -14,42 +14,42 @@ import java.util.function.*;
|
|||||||
@Transactional
|
@Transactional
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class SeriesService {
|
public class SeriesService {
|
||||||
|
|
||||||
private final SeriesRepository seriesRepository;
|
private final SeriesRepository seriesRepository;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public SeriesDto modify(final long id, @NonNull final Consumer<Series> modifier) {
|
public SeriesDto modify(final long id, @NonNull final Consumer<Series> modifier) {
|
||||||
final Series series = getById(id);
|
final Series series = getById(id);
|
||||||
modifier.accept(series);
|
modifier.accept(series);
|
||||||
return publish(series, Action.CHANGED);
|
return publish(series, Action.CHANGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public void delete(final long id) {
|
public void delete(final long id) {
|
||||||
final Series series = getById(id);
|
final Series series = getById(id);
|
||||||
seriesRepository.delete(series);
|
seriesRepository.delete(series);
|
||||||
publish(series, Action.DELETED);
|
publish(series, Action.DELETED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Series getById(final long id) {
|
private Series getById(final long id) {
|
||||||
return seriesRepository.findById(id).orElseThrow();
|
return seriesRepository.findById(id).orElseThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SeriesDto getDtoById(final long id) {
|
public SeriesDto getDtoById(final long id) {
|
||||||
return toDto(getById(id));
|
return toDto(getById(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
private SeriesDto publish(@NonNull final Series series, @NonNull final Action action) {
|
private SeriesDto publish(@NonNull final Series series, @NonNull final Action action) {
|
||||||
final SeriesDto dto = toDto(series);
|
final SeriesDto dto = toDto(series);
|
||||||
log.info("Series {}: {}", action, series);
|
log.info("Series {}: {}", action, series);
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SeriesDto toDto(@NonNull final Series series) {
|
private SeriesDto toDto(@NonNull final Series series) {
|
||||||
return new SeriesDto(series);
|
return new SeriesDto(series);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Series getOrCreate(@NonNull final String name, @NonNull final Unit unit) {
|
public Series getOrCreate(@NonNull final String name, @NonNull final Value.Unit unit) {
|
||||||
return seriesRepository
|
return seriesRepository
|
||||||
.findByName(name)
|
.findByName(name)
|
||||||
.orElseGet(() -> {
|
.orElseGet(() -> {
|
||||||
@ -58,5 +58,5 @@ public class SeriesService {
|
|||||||
return series;
|
return series;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
package de.ph87.data.series.entry;
|
package de.ph87.data.series.entry;
|
||||||
|
|
||||||
import de.ph87.data.series.*;
|
import de.ph87.data.series.*;
|
||||||
import de.ph87.data.unit.Value;
|
import de.ph87.data.value.Value;
|
||||||
import de.ph87.data.unit.*;
|
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
@ -19,27 +18,27 @@ import java.time.temporal.*;
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
public class Entry {
|
public class Entry {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
private long id;
|
private long id;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
private Series series;
|
private Series series;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private ZonedDateTime date;
|
private ZonedDateTime date;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Column(nullable = false, name = "`value`")
|
@Column(nullable = false, name = "`value`")
|
||||||
private double value;
|
private double value;
|
||||||
|
|
||||||
public Entry(@NonNull final Series series, @NonNull final ZonedDateTime date, final Value value) throws Unit.NotConvertible {
|
public Entry(@NonNull final Series series, @NonNull final ZonedDateTime date, final Value value) throws Value.Unit.NotConvertible {
|
||||||
this.series = series;
|
this.series = series;
|
||||||
this.date = date.truncatedTo(ChronoUnit.MINUTES);
|
this.date = date.truncatedTo(ChronoUnit.MINUTES);
|
||||||
this.value = value.as(series.getUnit()).value;
|
this.value = value.as(series.getUnit()).value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,9 @@ import java.time.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public interface EntryRepository extends ListCrudRepository<Entry, Long> {
|
public interface EntryRepository extends ListCrudRepository<Entry, Long> {
|
||||||
|
|
||||||
Optional<Entry> findBySeriesAndDate(@NonNull Series series, @NonNull ZonedDateTime truncated);
|
Optional<Entry> findBySeriesAndDate(@NonNull Series series, @NonNull ZonedDateTime truncated);
|
||||||
|
|
||||||
List<Entry> findAllBySeriesIdAndDateGreaterThanEqualAndDateLessThanEqual(long id, @NonNull ZonedDateTime begin, @NonNull ZonedDateTime end);
|
List<Entry> findAllBySeriesIdAndDateGreaterThanEqualAndDateLessThanEqual(long id, @NonNull ZonedDateTime begin, @NonNull ZonedDateTime end);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package de.ph87.data.series.entry;
|
package de.ph87.data.series.entry;
|
||||||
|
|
||||||
import de.ph87.data.series.*;
|
import de.ph87.data.series.*;
|
||||||
import de.ph87.data.unit.*;
|
import de.ph87.data.value.Value;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
import lombok.extern.slf4j.*;
|
import lombok.extern.slf4j.*;
|
||||||
import org.springframework.stereotype.*;
|
import org.springframework.stereotype.*;
|
||||||
@ -20,7 +20,7 @@ public class EntryService {
|
|||||||
|
|
||||||
private final SeriesService seriesService;
|
private final SeriesService seriesService;
|
||||||
|
|
||||||
public void write(@NonNull final Series series, @NonNull final SeriesInbound measure) throws Unit.NotConvertible {
|
public void write(@NonNull final Series series, @NonNull final SeriesInbound measure) throws Value.Unit.NotConvertible {
|
||||||
final ZonedDateTime truncated = measure.date.truncatedTo(ChronoUnit.MINUTES).minusMinutes(measure.date.getMinute() % 5);
|
final ZonedDateTime truncated = measure.date.truncatedTo(ChronoUnit.MINUTES).minusMinutes(measure.date.getMinute() % 5);
|
||||||
if (entryRepository.findBySeriesAndDate(series, truncated).isEmpty()) {
|
if (entryRepository.findBySeriesAndDate(series, truncated).isEmpty()) {
|
||||||
final Entry created = entryRepository.save(new Entry(series, truncated, measure.value));
|
final Entry created = entryRepository.save(new Entry(series, truncated, measure.value));
|
||||||
@ -28,7 +28,7 @@ public class EntryService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void receive(@NonNull final SeriesInbound measure) throws Unit.NotConvertible {
|
public void receive(@NonNull final SeriesInbound measure) throws Value.Unit.NotConvertible {
|
||||||
final Series series = seriesService.getOrCreate(measure.name, measure.value.unit);
|
final Series series = seriesService.getOrCreate(measure.name, measure.value.unit);
|
||||||
write(series, measure);
|
write(series, measure);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,51 +0,0 @@
|
|||||||
package de.ph87.data.unit;
|
|
||||||
|
|
||||||
import lombok.*;
|
|
||||||
|
|
||||||
public enum Unit {
|
|
||||||
TEMPERATURE_C("°C"),
|
|
||||||
PRESSURE_HPA("hPa"),
|
|
||||||
HUMIDITY_RELATIVE_PERCENT("%"),
|
|
||||||
HUMIDITY_ABSOLUTE_MGL("mg/L"),
|
|
||||||
HUMIDITY_ABSOLUTE_GM3("g/m³", 1, HUMIDITY_ABSOLUTE_MGL),
|
|
||||||
ILLUMINANCE_LUX("lux"),
|
|
||||||
RESISTANCE_OHMS("Ω"),
|
|
||||||
ALTITUDE_M("m"),
|
|
||||||
POWER_W("W"),
|
|
||||||
POWER_KW("kW", 1000, POWER_W),
|
|
||||||
ENERGY_WH("W"),
|
|
||||||
ENERGY_KWH("kWh", 1000, ENERGY_WH),
|
|
||||||
IAQ("IAQ"),
|
|
||||||
IAQ_CO2_EQUIVALENT("ppm"),
|
|
||||||
IAQ_VOC_EQUIVALENT("ppm"),
|
|
||||||
SUN_DC("Δ°C"),
|
|
||||||
UNIT_PERCENT("%"),
|
|
||||||
;
|
|
||||||
|
|
||||||
public final String unit;
|
|
||||||
|
|
||||||
public final double factor;
|
|
||||||
|
|
||||||
public final Unit base;
|
|
||||||
|
|
||||||
Unit(@NonNull final String unit) {
|
|
||||||
this.unit = unit;
|
|
||||||
this.factor = 1.0;
|
|
||||||
this.base = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Unit(@NonNull final String unit, final double factor, @NonNull final Unit base) {
|
|
||||||
this.unit = unit;
|
|
||||||
this.factor = factor;
|
|
||||||
this.base = base;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class NotConvertible extends Exception {
|
|
||||||
|
|
||||||
public NotConvertible(final @NonNull Unit source, final Unit target) {
|
|
||||||
super("Cannot convert Units: source=%s, target=%s".formatted(source, target));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
package de.ph87.data.unit;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.*;
|
|
||||||
import com.fasterxml.jackson.databind.*;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class UnitListDeserializer extends JsonDeserializer<List<Unit>> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Unit> deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException {
|
|
||||||
final String name = jsonParser.getValueAsString();
|
|
||||||
return Arrays.stream(Unit.values()).filter(unit -> unit.unit.equals(name)).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
package de.ph87.data.unit;
|
|
||||||
|
|
||||||
import lombok.*;
|
|
||||||
|
|
||||||
public class Value {
|
|
||||||
|
|
||||||
public final double value;
|
|
||||||
|
|
||||||
public final Unit unit;
|
|
||||||
|
|
||||||
public Value(final double value, @NonNull final Unit unit) {
|
|
||||||
this.value = value;
|
|
||||||
this.unit = unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Value as(@NonNull final Unit target) throws Unit.NotConvertible {
|
|
||||||
if (this.unit == target) {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
if (this.unit.base != target.base) {
|
|
||||||
throw new Unit.NotConvertible(this.unit, target);
|
|
||||||
}
|
|
||||||
return new Value(value * this.unit.factor / target.factor, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
88
src/main/java/de/ph87/data/value/Value.java
Normal file
88
src/main/java/de/ph87/data/value/Value.java
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package de.ph87.data.value;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.*;
|
||||||
|
import com.fasterxml.jackson.databind.*;
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Value {
|
||||||
|
|
||||||
|
public final double value;
|
||||||
|
|
||||||
|
public final Unit unit;
|
||||||
|
|
||||||
|
public Value(final double value, @NonNull final Unit unit) {
|
||||||
|
this.value = value;
|
||||||
|
this.unit = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value as(@NonNull final Unit target) throws Unit.NotConvertible {
|
||||||
|
if (this.unit == target) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
if (this.unit.base != target.base) {
|
||||||
|
throw new Unit.NotConvertible(this.unit, target);
|
||||||
|
}
|
||||||
|
return new Value(value * this.unit.factor / target.factor, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Unit {
|
||||||
|
TEMPERATURE_C("°C"),
|
||||||
|
PRESSURE_HPA("hPa"),
|
||||||
|
HUMIDITY_RELATIVE_PERCENT("%"),
|
||||||
|
HUMIDITY_ABSOLUTE_MGL("mg/L"),
|
||||||
|
HUMIDITY_ABSOLUTE_GM3("g/m³", 1, HUMIDITY_ABSOLUTE_MGL),
|
||||||
|
ILLUMINANCE_LUX("lux"),
|
||||||
|
RESISTANCE_OHMS("Ω"),
|
||||||
|
ALTITUDE_M("m"),
|
||||||
|
POWER_W("W"),
|
||||||
|
POWER_KW("kW", 1000, POWER_W),
|
||||||
|
ENERGY_WH("W"),
|
||||||
|
ENERGY_KWH("kWh", 1000, ENERGY_WH),
|
||||||
|
IAQ("IAQ"),
|
||||||
|
IAQ_CO2_EQUIVALENT("ppm"),
|
||||||
|
IAQ_VOC_EQUIVALENT("ppm"),
|
||||||
|
SUN_DC("Δ°C"),
|
||||||
|
UNIT_PERCENT("%"),
|
||||||
|
;
|
||||||
|
|
||||||
|
public final String unit;
|
||||||
|
|
||||||
|
public final double factor;
|
||||||
|
|
||||||
|
public final Unit base;
|
||||||
|
|
||||||
|
Unit(@NonNull final String unit) {
|
||||||
|
this.unit = unit;
|
||||||
|
this.factor = 1.0;
|
||||||
|
this.base = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unit(@NonNull final String unit, final double factor, @NonNull final Value.Unit base) {
|
||||||
|
this.unit = unit;
|
||||||
|
this.factor = factor;
|
||||||
|
this.base = base;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NotConvertible extends Exception {
|
||||||
|
|
||||||
|
public NotConvertible(final @NonNull Value.Unit source, final Unit target) {
|
||||||
|
super("Cannot convert Units: source=%s, target=%s".formatted(source, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ListDeserializer extends JsonDeserializer<List<Unit>> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Unit> deserialize(final JsonParser jsonParser, final DeserializationContext deserializationContext) throws IOException {
|
||||||
|
final String name = jsonParser.getValueAsString();
|
||||||
|
return Arrays.stream(values()).filter(unit -> unit.unit.equals(name)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user