package de.ph87.data.message.handler;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.*;
import de.ph87.data.message.*;
import de.ph87.data.series.varying.*;
import de.ph87.data.value.Value;
import de.ph87.data.value.*;
import lombok.*;
import lombok.extern.slf4j.*;
import org.springframework.context.*;
import org.springframework.stereotype.*;
import java.time.*;
import java.util.*;
import java.util.regex.*;
import java.util.stream.*;
@Slf4j
@Service
@RequiredArgsConstructor
public class EspHomeHandler implements IMessageHandler {
private static final Pattern REGEX = Pattern.compile("^(?\\w+)/sensor/(?\\w+)$");
private final ObjectMapper objectMapper;
private final ApplicationEventPublisher applicationEventPublisher;
@Override
public void handle(@NonNull final Message message) throws Exception {
final Matcher matcher = REGEX.matcher(message.topic);
if (!matcher.find()) {
return;
}
final String area = matcher.group("area");
final String property = propertyReplace(matcher.group("property"));
final String name = "%s/%s".formatted(area, property.replace("_", "/"));
final Unit targetUnit = switch (property) {
case "iaq" -> Unit.IAQ;
case "iaq_co2" -> Unit.IAQ_CO2_EQUIVALENT;
case "iaq_voc" -> Unit.IAQ_VOC_EQUIVALENT;
case "pressure" -> Unit.PRESSURE_HPA;
case "temperature" -> Unit.TEMPERATURE_C;
case "humidity_relative" -> Unit.HUMIDITY_RELATIVE_PERCENT;
case "humidity_absolute" -> Unit.HUMIDITY_ABSOLUTE_GM3;
case "sun" -> Unit.SUN_DC;
default -> null;
};
if (targetUnit == null) {
log.debug("Skipping property: {}", name);
return;
}
final Inbound inbound = objectMapper.readValue(message.payload, Inbound.class);
final Unit unitFromPayload = inbound.units.stream().filter(ufp -> ufp.base == targetUnit.base).findFirst().orElse(null);
if (unitFromPayload == null) {
log.error("Unit mismatch: fromTopic={}, fromPayload=[{}]", targetUnit, inbound.getUnits().stream().map(Enum::name).collect(Collectors.joining(",")));
return;
}
final Value value = new Value(inbound.value, unitFromPayload);
applicationEventPublisher.publishEvent(new VaryingInbound(name, inbound.date, value.as(targetUnit)));
}
private String propertyReplace(final String property) {
if ("iaq_co2_equivalent".equals(property)) {
return "iaq_co2";
}
if ("iaq_equivalent_voc".equals(property)) {
return "iaq_voc";
}
return property;
}
@Getter
@ToString
private static class Inbound {
@NonNull
public final ZonedDateTime date;
public final double value;
@NonNull
@JsonDeserialize(using = Unit.ListDeserializer.class)
public final List units;
public Inbound(final long timestamp, final double value, @JsonProperty("unit") @NonNull final List units) {
this.date = ZonedDateTime.ofInstant(Instant.ofEpochSecond(timestamp), ZoneId.systemDefault());
this.value = value;
this.units = units;
}
}
}