package de.ph87.homeautomation.knx.group; import de.ph87.homeautomation.channel.ChannelChangedEvent; import de.ph87.homeautomation.channel.ChannelDto; import de.ph87.homeautomation.web.WebSocketService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import tuwien.auto.calimero.GroupAddress; import tuwien.auto.calimero.IndividualAddress; import tuwien.auto.calimero.KNXException; import tuwien.auto.calimero.KNXFormatException; import tuwien.auto.calimero.dptxlator.*; import java.time.ZonedDateTime; import java.util.Optional; import java.util.function.Function; @Slf4j @Service @Transactional @RequiredArgsConstructor public class KnxGroupWriteService { private final KnxGroupRepository knxGroupRepository; private final ApplicationEventPublisher applicationEventPublisher; private final WebSocketService webSocketService; private final KnxGroupMapper knxGroupMapper; public void requestRead(final KnxGroup knxGroup) { knxGroup.getRead().setNextTimestamp(ZonedDateTime.now()); log.debug("Requesting read for KnxGroup: {}", knxGroup); sendThreadWakeUpEvent(); } public void requestWrite(final KnxGroup knxGroup, final double value) { findTranslator(knxGroup).ifPresent(translator -> { try { if (translator instanceof DPTXlatorBoolean) { ((DPTXlatorBoolean) translator).setValue(value == 1.0); } else if (translator instanceof DPTXlator8BitUnsigned) { ((DPTXlator8BitUnsigned) translator).setValue((int) value); } else if (translator instanceof DPTXlatorSceneNumber) { ((DPTXlatorSceneNumber) translator).setValue((int) value - 1); } else { // TODO implement all DPTXlator... translator.setValue("" + value); } knxGroup.getSend().setNextTimestamp(ZonedDateTime.now()); knxGroup.setSendValue(translator.getData()); publish(knxGroup); sendThreadWakeUpEvent(); } catch (KNXFormatException e) { log.error("Failed set value \"{}\" to DptXlator {} for KnxGroup {}", value, translator, knxGroup); } }); } public void setReceivedData(final GroupAddress groupAddress, final byte[] data, final IndividualAddress knxDeviceAddress) { final Optional knxGroupOptional = knxGroupRepository.findByAddressRaw(groupAddress.getRawAddress()); if (knxGroupOptional.isEmpty()) { log.error("No KnxGroup with address={}", groupAddress); return; } final KnxGroup knxGroup = knxGroupOptional.get(); knxGroup.setLastTelegram(new KnxTelegram(data, ZonedDateTime.now(), knxDeviceAddress)); translate(knxGroup); } private void sendThreadWakeUpEvent() { applicationEventPublisher.publishEvent(new KnxThreadWakeUpEvent()); } private void translate(final KnxGroup knxGroup) { findTranslator(knxGroup).ifPresent(translator -> { translator.setData(knxGroup.getLastTelegram().getData()); final Optional valueOptional = translate(DPTXlatorBoolean.class, translator, DPTXlatorBoolean::getNumericValue) .or(() -> translate(DPTXlator8BitUnsigned.class, translator, DPTXlator8BitUnsigned::getNumericValue)) .or(() -> translate(DPTXlator2ByteFloat.class, translator, DPTXlator2ByteFloat::getNumericValue)) .or(() -> translate(DPTXlator2ByteUnsigned.class, translator, DPTXlator2ByteUnsigned::getNumericValue)) .or(() -> translate(DPTXlator4ByteFloat.class, translator, DPTXlator4ByteFloat::getNumericValue)) .or(() -> translate(DPTXlator4ByteSigned.class, translator, DPTXlator4ByteSigned::getNumericValue)) .or(() -> translate(DPTXlator4ByteUnsigned.class, translator, DPTXlator4ByteUnsigned::getNumericValue)) .or(() -> translate(DPTXlator8BitSigned.class, translator, DPTXlator8BitSigned::getNumericValue)) .or(() -> translate(DPTXlator64BitSigned.class, translator, DPTXlator64BitSigned::getNumericValue)) .or(() -> translate(DPTXlatorSceneNumber.class, translator, DPTXlatorSceneNumber::getNumericValue)); // TODO implement all DPTXlator... if (valueOptional.isPresent()) { knxGroup.setValue(valueOptional.get()); knxGroup.setTimestamp(ZonedDateTime.now()); log.debug("KnxGroup updated: {}", knxGroup); publish(knxGroup); applicationEventPublisher.publishEvent(new ChannelChangedEvent(knxGroup)); } else { log.error("Failed to get value from DptXlator {} for KnxGroup {}", translator, knxGroup); } }); } private Optional findTranslator(final KnxGroup knxGroup) { try { return Optional.of(TranslatorTypes.createTranslator(knxGroup.getDptMain(), knxGroup.getDpt())); } catch (KNXException e) { log.error("No DptXlator found for KnxGroup: {}", knxGroup); return Optional.empty(); } } private Optional translate(final Class dptXlatorClass, final DPTXlator translator, final Function getValueFromXlator) { if (dptXlatorClass.isInstance(translator)) { final Xlator castXlator = dptXlatorClass.cast(translator); final Value value = getValueFromXlator.apply(castXlator); return Optional.of(value); } return Optional.empty(); } private KnxGroupDto publish(final KnxGroup knxGroup) { final KnxGroupDto dto = knxGroupMapper.toDto(knxGroup); webSocketService.send(ChannelDto.class.getSimpleName(), dto, true); return dto; } }