137 lines
6.1 KiB
Java
137 lines
6.1 KiB
Java
package de.ph87.home.knx.property;
|
|
|
|
import de.ph87.home.knx.Group;
|
|
import de.ph87.home.knx.GroupLoaded;
|
|
import de.ph87.home.knx.GroupService;
|
|
import de.ph87.home.knx.link.KnxLinkService;
|
|
import de.ph87.home.property.PropertyNotFound;
|
|
import de.ph87.home.property.PropertyNotOwned;
|
|
import de.ph87.home.property.PropertyService;
|
|
import de.ph87.home.property.PropertyTypeMismatch;
|
|
import jakarta.annotation.Nullable;
|
|
import lombok.NonNull;
|
|
import lombok.RequiredArgsConstructor;
|
|
import lombok.extern.slf4j.Slf4j;
|
|
import org.springframework.context.event.EventListener;
|
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
|
import org.springframework.scheduling.annotation.Scheduled;
|
|
import org.springframework.stereotype.Service;
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
import tuwien.auto.calimero.GroupAddress;
|
|
import tuwien.auto.calimero.KNXException;
|
|
import tuwien.auto.calimero.dptxlator.DPTXlator;
|
|
import tuwien.auto.calimero.dptxlator.DPTXlatorBoolean;
|
|
import tuwien.auto.calimero.process.ProcessEvent;
|
|
|
|
import java.util.List;
|
|
import java.util.Optional;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
@Slf4j
|
|
@Service
|
|
@Transactional
|
|
@EnableScheduling
|
|
@RequiredArgsConstructor
|
|
public class KnxPropertyService {
|
|
|
|
private final KnxPropertyRepository knxPropertyRepository;
|
|
|
|
private final PropertyService propertyService;
|
|
|
|
private final GroupService groupService;
|
|
|
|
private final KnxLinkService knxLinkService;
|
|
|
|
@Scheduled(initialDelay = 1, fixedDelay = 1, timeUnit = TimeUnit.HOURS)
|
|
public void readAll() {
|
|
knxPropertyRepository.findAll().forEach(this::read);
|
|
}
|
|
|
|
@EventListener(GroupLoaded.class)
|
|
public void onGroupLoad(@NonNull final GroupLoaded groupLoaded) {
|
|
findAllByAddress(groupLoaded.getGroup().getAddress()).forEach(this::read);
|
|
}
|
|
|
|
public void create(@NonNull final String id, @NonNull final KnxPropertyType type, @Nullable final GroupAddress read, @Nullable final GroupAddress write) {
|
|
final KnxProperty knxProperty = knxPropertyRepository.save(new KnxProperty(id, type, read, write));
|
|
updateOrCreateProperty(knxProperty);
|
|
}
|
|
|
|
private void updateOrCreateProperty(@NonNull final KnxProperty knxProperty) {
|
|
try {
|
|
propertyService.createOrUpdate(this, knxProperty.getId(), knxProperty.getType().clazz, (p, value) -> write(knxProperty, value));
|
|
read(knxProperty);
|
|
} catch (PropertyNotOwned e) {
|
|
log.error("Failed to register KnxProperty: knxProperty={}, error={}", knxProperty, e.toString());
|
|
}
|
|
}
|
|
|
|
@EventListener(ProcessEvent.class)
|
|
public void onProcessEvent(@NonNull final ProcessEvent event) {
|
|
findAllByAddress(event.getDestination()).forEach(knxProperty -> onProcessEvent(knxProperty, event));
|
|
}
|
|
|
|
@NonNull
|
|
private List<KnxProperty> findAllByAddress(@NonNull final GroupAddress address) {
|
|
return knxPropertyRepository.findDistinctByReadOrWrite(address, address);
|
|
}
|
|
|
|
private void onProcessEvent(@NonNull final KnxProperty knxProperty, @NonNull final ProcessEvent event) {
|
|
log.debug("onProcessEvent: knxProperty={}, event={}", knxProperty, event);
|
|
groupService.findByAddress(event.getDestination()).ifPresent(group -> onProcessEvent(knxProperty, event, group));
|
|
}
|
|
|
|
private void onProcessEvent(@NonNull final KnxProperty knxProperty, @NonNull final ProcessEvent event, @NonNull final Group group) {
|
|
log.debug("onProcessEvent: knxProperty={}, group={}, event={}", knxProperty, group, event);
|
|
try {
|
|
final DPTXlator translator = group.getDpt().createTranslator();
|
|
translator.setData(event.getASDU());
|
|
log.debug("translator: {}", translator);
|
|
switch (knxProperty.getType()) {
|
|
case BOOLEAN -> {
|
|
if (!(translator instanceof final DPTXlatorBoolean booleanTranslator)) {
|
|
throw new RuntimeException("DPTXlator type should be DPTXlatorBoolean for property.type = BOOLEAN but is: " + translator.getClass().getSimpleName());
|
|
}
|
|
propertyService.update(this, knxProperty.getId(), Boolean.class, booleanTranslator.getValueBoolean(), booleanTranslator.getValue());
|
|
}
|
|
case DOUBLE -> propertyService.update(this, knxProperty.getId(), Double.class, translator.getNumericValue(), translator.getValue());
|
|
}
|
|
} catch (KNXException | PropertyNotFound | PropertyTypeMismatch | PropertyNotOwned e) {
|
|
log.error("Failed to handle ProcessEvent: knxProperty={}, error={}", knxProperty, e.toString());
|
|
}
|
|
}
|
|
|
|
private void read(@NonNull final KnxProperty knxProperty) {
|
|
final Optional<KnxProperty> property = knxPropertyRepository.findById(knxProperty.getId());
|
|
final Optional<GroupAddress> address = property.map(KnxProperty::getRead);
|
|
final Optional<Group> group = address.map(groupService::findByAddress).filter(Optional::isPresent).map(Optional::get);
|
|
group.ifPresent(knxLinkService::queueRead);
|
|
}
|
|
|
|
private void write(@NonNull final KnxProperty knxProperty, @NonNull final Object value) {
|
|
knxPropertyRepository.findById(knxProperty.getId()).map(KnxProperty::getWrite).map(groupService::findByAddress).filter(Optional::isPresent).map(Optional::get).ifPresent(group -> write(knxProperty, group, value));
|
|
}
|
|
|
|
private void write(@NonNull final KnxProperty knxProperty, @NonNull final Group group, @NonNull final Object value) {
|
|
try {
|
|
if (!knxProperty.getType().clazz.isInstance(value)) {
|
|
throw new RuntimeException("Cannot write invalid value type: type=%s, value=%s, knxProperty=%s".formatted(value.getClass(), value, knxProperty));
|
|
}
|
|
final DPTXlator translator = group.getDpt().createTranslator();
|
|
switch (knxProperty.getType()) {
|
|
case BOOLEAN -> {
|
|
if (!(translator instanceof final DPTXlatorBoolean booleanTranslator)) {
|
|
throw new RuntimeException("DPTXlator type should be DPTXlatorBoolean for property.type = BOOLEAN but is: " + translator.getClass().getSimpleName());
|
|
}
|
|
booleanTranslator.setValue((boolean) value);
|
|
}
|
|
case DOUBLE -> translator.setValue((double) value);
|
|
}
|
|
knxLinkService.queueWrite(group, translator);
|
|
} catch (KNXException e) {
|
|
log.error("Failed to write KnxProperty: knxProperty={}, error={}", knxProperty, e.toString());
|
|
}
|
|
}
|
|
|
|
}
|