Compare commits

...

7 Commits

10 changed files with 75 additions and 29 deletions

View File

@ -54,8 +54,11 @@ export class PropertyListComponent implements OnInit {
} }
private updateProperty(property: Property, existing: boolean): void { private updateProperty(property: Property, existing: boolean): void {
this.updateProperty2(this.booleans, property, existing); if (property.type === PropertyType.BOOLEAN) {
this.updateProperty2(this.shutters, property, existing); this.updateProperty2(this.booleans, property, existing);
} else if (property.type === PropertyType.SHUTTER) {
this.updateProperty2(this.shutters, property, existing);
}
} }
private updateProperty2(properties: Property[], property: Property, existing: boolean) { private updateProperty2(properties: Property[], property: Property, existing: boolean) {

View File

@ -2,6 +2,7 @@ package de.ph87.homeautomation.channel;
import de.ph87.homeautomation.property.Property; import de.ph87.homeautomation.property.Property;
import de.ph87.homeautomation.shared.Helpers; import de.ph87.homeautomation.shared.Helpers;
import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -29,12 +30,11 @@ public class ChannelReader {
return findByChannel(channel).orElseThrow(RuntimeException::new); return findByChannel(channel).orElseThrow(RuntimeException::new);
} }
public Double read(final Property property) { @NonNull
final Channel channel = property.getReadChannel(); public Optional<Double> read(@NonNull final Property property) {
if (channel == null) { return Optional.ofNullable(property.getReadChannel())
return null; .map(this::getByChannel)
} .map(owner -> owner.read(property.getReadChannel().getId()));
return getByChannel(channel).read(property.getReadChannel().getId());
} }
public ChannelDto toDtoAllowNull(final Channel channel) { public ChannelDto toDtoAllowNull(final Channel channel) {

View File

@ -0,0 +1,20 @@
package de.ph87.homeautomation.knx.group;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@RequestMapping("knx/group")
public class KnxGroupImportController {
private final KnxGroupImportService knxGroupImportService;
@GetMapping("import")
public void doImport() {
knxGroupImportService.importGroups();
}
}

View File

@ -1,5 +1,6 @@
package de.ph87.homeautomation.knx.group; package de.ph87.homeautomation.knx.group;
import de.ph87.homeautomation.property.PropertyReader;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
@ -23,6 +24,8 @@ public class KnxGroupImportService {
private final KnxGroupRepository knxGroupRepository; private final KnxGroupRepository knxGroupRepository;
private final PropertyReader propertyReader;
public void importGroups() { public void importGroups() {
try { try {
execute("/usr/bin/git", "fetch", "--all"); execute("/usr/bin/git", "fetch", "--all");
@ -34,6 +37,18 @@ public class KnxGroupImportService {
knxGroupRepository.findAll().forEach(knxGroup -> knxGroup.setEts(false)); knxGroupRepository.findAll().forEach(knxGroup -> knxGroup.setEts(false));
try { try {
Jsoup.parse(new File(ETS_HOME, "G"), "UTF-8").select("GA").forEach(this::importGroup); Jsoup.parse(new File(ETS_HOME, "G"), "UTF-8").select("GA").forEach(this::importGroup);
knxGroupRepository.findAllByEtsFalse().forEach(group -> {
log.warn("Removing obsolete group: {}", group);
propertyReader.findAllByReadChannel_Id(group.getId()).forEach(property -> {
property.setReadChannel(null);
log.warn(" - removed group as Property readChannel: {}", property);
});
propertyReader.findAllByWriteChannel_Id(group.getId()).forEach(property -> {
property.setWriteChannel(null);
log.warn(" - removed group as Property writeChannel: {}", property);
});
knxGroupRepository.delete(group);
});
} catch (IOException e) { } catch (IOException e) {
log.error("Failed to import KnxGroups: {}", e.toString()); log.error("Failed to import KnxGroups: {}", e.toString());
} }
@ -73,7 +88,13 @@ public class KnxGroupImportService {
private void setDpt(final KnxGroup knxGroup, final String dptString) { private void setDpt(final KnxGroup knxGroup, final String dptString) {
final Matcher mainSub = Pattern.compile("^DPST-(?<main>\\d+)-(?<sub>\\d+)$").matcher(dptString); final Matcher mainSub = Pattern.compile("^DPST-(?<main>\\d+)-(?<sub>\\d+)$").matcher(dptString);
if (mainSub.matches()) { if (mainSub.matches()) {
knxGroup.setDptMain(Integer.parseInt(mainSub.group("main"))); final int main = Integer.parseInt(mainSub.group("main"));
if (knxGroup.getDptMain() != main) {
knxGroup.setLastTelegram(null);
knxGroup.setValue(null);
knxGroup.setTimestamp(null);
}
knxGroup.setDptMain(main);
knxGroup.setDptSub(Integer.parseInt(mainSub.group("sub"))); knxGroup.setDptSub(Integer.parseInt(mainSub.group("sub")));
return; return;
} }

View File

@ -4,10 +4,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import tuwien.auto.calimero.GroupAddress; import tuwien.auto.calimero.*;
import tuwien.auto.calimero.KNXException;
import tuwien.auto.calimero.KNXFormatException;
import tuwien.auto.calimero.KNXTimeoutException;
import tuwien.auto.calimero.datapoint.StateDP; import tuwien.auto.calimero.datapoint.StateDP;
import tuwien.auto.calimero.dptxlator.TranslatorTypes; import tuwien.auto.calimero.dptxlator.TranslatorTypes;
import tuwien.auto.calimero.process.ProcessCommunicatorImpl; import tuwien.auto.calimero.process.ProcessCommunicatorImpl;
@ -74,6 +71,12 @@ public class KnxGroupLinkService {
knxGroup.getRead().setNextTimestamp(null); knxGroup.getRead().setNextTimestamp(null);
log.debug("Successfully sent KnxGroup: {}", knxGroup); log.debug("Successfully sent KnxGroup: {}", knxGroup);
return true; return true;
} catch (KNXIllegalArgumentException e) {
log.error("Failed to read KnxGroup {}", knxGroup);
knxGroup.getRead().setErrorCount(knxGroup.getRead().getErrorCount() + 1);
knxGroup.getRead().setErrorMessage(e.getMessage());
knxGroup.getRead().setNextTimestamp(null);
return true;
} catch (KNXTimeoutException | KNXFormatException e) { } catch (KNXTimeoutException | KNXFormatException e) {
log.error("Failed to read KnxGroup {}", knxGroup); log.error("Failed to read KnxGroup {}", knxGroup);
knxGroup.getRead().setErrorCount(knxGroup.getRead().getErrorCount() + 1); knxGroup.getRead().setErrorCount(knxGroup.getRead().getErrorCount() + 1);

View File

@ -1,18 +1,16 @@
package de.ph87.homeautomation.knx.group; package de.ph87.homeautomation.knx.group;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.ListCrudRepository;
import java.time.ZonedDateTime; import java.time.ZonedDateTime;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface KnxGroupRepository extends CrudRepository<KnxGroup, Long>, JpaSpecificationExecutor<KnxGroup> { public interface KnxGroupRepository extends ListCrudRepository<KnxGroup, Long>, JpaSpecificationExecutor<KnxGroup> {
Optional<KnxGroup> findByAddressRaw(int rawAddress); Optional<KnxGroup> findByAddressRaw(int rawAddress);
List<KnxGroup> findAll();
Optional<KnxGroup> findFirstBySend_NextTimestampNotNullOrderBySend_NextTimestampAsc(); Optional<KnxGroup> findFirstBySend_NextTimestampNotNullOrderBySend_NextTimestampAsc();
Optional<KnxGroup> findFirstByRead_NextTimestampLessThanEqualOrderByRead_NextTimestampAsc(ZonedDateTime timestamp); Optional<KnxGroup> findFirstByRead_NextTimestampLessThanEqualOrderByRead_NextTimestampAsc(ZonedDateTime timestamp);
@ -21,4 +19,6 @@ public interface KnxGroupRepository extends CrudRepository<KnxGroup, Long>, JpaS
List<KnxGroup> findAllByNameContainsIgnoreCaseOrAddressStrContainsIgnoreCase(String name, String addressStr); List<KnxGroup> findAllByNameContainsIgnoreCaseOrAddressStrContainsIgnoreCase(String name, String addressStr);
List<KnxGroup> findAllByEtsFalse();
} }

View File

@ -44,6 +44,11 @@ public class PropertyController implements ISearchController {
return propertyWriter.set(id, Property::setSlug, value == null || value.isEmpty() ? null : value); return propertyWriter.set(id, Property::setSlug, value == null || value.isEmpty() ? null : value);
} }
@GetMapping("get/{id}/value")
public Double getValue(@PathVariable final long id) {
return channelReader.read(propertyReader.getById(id)).orElse(null);
}
@PostMapping("set/{id}/value") @PostMapping("set/{id}/value")
public PropertyDto setValue(@PathVariable final long id, @RequestBody final double value) { public PropertyDto setValue(@PathVariable final long id, @RequestBody final double value) {
return propertyWriter.set(id, propertyWriter::writeToChannel, value); return propertyWriter.set(id, propertyWriter::writeToChannel, value);
@ -66,18 +71,10 @@ public class PropertyController implements ISearchController {
@PostMapping("toggle/{id}") @PostMapping("toggle/{id}")
public PropertyDto setValue(@PathVariable final long id) { public PropertyDto setValue(@PathVariable final long id) {
final boolean oldState = getOldStateBoolean(id, false); final boolean oldState = channelReader.read(propertyReader.getById(id)).map(v -> v > 0.0).orElse(false);
return propertyWriter.set(id, propertyWriter::writeToChannel, oldState ? 0.0 : 1.0); return propertyWriter.set(id, propertyWriter::writeToChannel, oldState ? 0.0 : 1.0);
} }
private boolean getOldStateBoolean(final long id, final boolean orElse) {
final Double oldValue = channelReader.read(propertyReader.getById(id));
if (oldValue == null || oldValue.isNaN()) {
return orElse;
}
return oldValue > 0.0;
}
@Override @Override
@GetMapping("searchById/{id}") @GetMapping("searchById/{id}")
public SearchResult searchById(@PathVariable final long id) { public SearchResult searchById(@PathVariable final long id) {

View File

@ -23,6 +23,10 @@ public class PropertyReader {
return propertyRepository.findAllByReadChannel_Id(readChannelId); return propertyRepository.findAllByReadChannel_Id(readChannelId);
} }
public List<Property> findAllByWriteChannel_Id(final long writeChannelId) {
return propertyRepository.findAllByWriteChannel_Id(writeChannelId);
}
public List<PropertyDto> search(final String term) { public List<PropertyDto> search(final String term) {
return RepositorySearchHelper.search(term, propertyRepository, "title", propertyMapper::toDto); return RepositorySearchHelper.search(term, propertyRepository, "title", propertyMapper::toDto);
} }

View File

@ -12,7 +12,7 @@ public interface PropertyRepository extends JpaRepository<Property, Long>, JpaSp
List<Property> findAllByReadChannel_Id(long readChannelId); List<Property> findAllByReadChannel_Id(long readChannelId);
List<Property> findAllByTitleLikeIgnoreCase(final String like); List<Property> findAllByWriteChannel_Id(final long writeChannelId);
boolean existsByTitle(String title); boolean existsByTitle(String title);

View File

@ -2,12 +2,10 @@ package de.ph87.homeautomation.web;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@CrossOrigin
@Configuration @Configuration
@EnableWebSocketMessageBroker @EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {