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; } } }