Compare commits
8 Commits
deploy---2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ded5e6c7d | |||
| eb99652e76 | |||
| ac750e9515 | |||
| 0111036617 | |||
| 2986238dc8 | |||
| bad017e1dd | |||
| 1acd5506c6 | |||
| 277e321480 |
6
pom.xml
6
pom.xml
@ -66,6 +66,12 @@
|
|||||||
<version>1.2</version>
|
<version>1.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -13,8 +13,6 @@ public class Config {
|
|||||||
|
|
||||||
private double longitude = 6.9645334;
|
private double longitude = 6.9645334;
|
||||||
|
|
||||||
private String timezone = "Europe/Berlin";
|
|
||||||
|
|
||||||
private boolean insertDemoData = false;
|
private boolean insertDemoData = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,8 @@ import org.springframework.context.event.EventListener;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -55,12 +57,12 @@ public class ScheduleCalculator {
|
|||||||
entry.setNextClearTimestamp(null);
|
entry.setNextClearTimestamp(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ZonedDateTime midnight = now.withHour(0).withMinute(0).withSecond(0).withNano(0);
|
LocalDate day = now.toLocalDate();
|
||||||
ZonedDateTime next = calculateEntryForDay(entry, midnight);
|
ZonedDateTime next = calculateEntryForDay(entry, day);
|
||||||
while (next != null && (!next.isAfter(now) || !isAfterLast(entry, next) || !isWeekdayEnabled(entry, next))) {
|
while (next != null && (!next.isAfter(now) || !isAfterLast(entry, next) || !isWeekdayEnabled(entry, next))) {
|
||||||
log.debug(" -- skipping: next={}", next);
|
log.debug(" -- skipping: next={}", next);
|
||||||
midnight = midnight.plusDays(1);
|
day = day.plusDays(1);
|
||||||
next = calculateEntryForDay(entry, midnight);
|
next = calculateEntryForDay(entry, day);
|
||||||
}
|
}
|
||||||
log.debug(" => {}", next);
|
log.debug(" => {}", next);
|
||||||
entry.setNextClearTimestamp(next);
|
entry.setNextClearTimestamp(next);
|
||||||
@ -70,14 +72,14 @@ public class ScheduleCalculator {
|
|||||||
return entry.getLastClearTimestamp() == null || next.isAfter(entry.getLastClearTimestamp());
|
return entry.getLastClearTimestamp() == null || next.isAfter(entry.getLastClearTimestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ZonedDateTime calculateEntryForDay(final ScheduleEntry entry, final ZonedDateTime midnight) {
|
private ZonedDateTime calculateEntryForDay(final ScheduleEntry entry, final LocalDate day) {
|
||||||
switch (entry.getType()) {
|
switch (entry.getType()) {
|
||||||
case TIME:
|
case TIME:
|
||||||
return midnight.withHour(entry.getHour()).withMinute(entry.getMinute()).withSecond(entry.getSecond());
|
return day.atStartOfDay().atZone(ZoneId.systemDefault()).withHour(entry.getHour()).withMinute(entry.getMinute()).withSecond(entry.getSecond());
|
||||||
case SUNRISE:
|
case SUNRISE:
|
||||||
case SUNSET:
|
case SUNSET:
|
||||||
final boolean sunrise = entry.getType() == ScheduleEntryType.SUNRISE;
|
final boolean sunrise = entry.getType() == ScheduleEntryType.SUNRISE;
|
||||||
return astroCalculator.forDay(midnight, sunrise, entry.getZenith());
|
return astroCalculator.forDay(day, sunrise, entry.getZenith()).withLaterOffsetAtOverlap();
|
||||||
default:
|
default:
|
||||||
log.error("AstroEvent not implemented: {}", entry.getType());
|
log.error("AstroEvent not implemented: {}", entry.getType());
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -8,10 +8,12 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@ -19,25 +21,15 @@ public class AstroCalculator {
|
|||||||
|
|
||||||
private final Config config;
|
private final Config config;
|
||||||
|
|
||||||
public ZonedDateTime next(final ZonedDateTime now, final boolean sunrise, final double zenith) {
|
public ZonedDateTime forDay(final LocalDate day, final boolean sunrise, final double zenith) {
|
||||||
ZonedDateTime day = now.truncatedTo(ChronoUnit.DAYS);
|
|
||||||
ZonedDateTime next;
|
|
||||||
do {
|
|
||||||
next = forDay(day, sunrise, zenith);
|
|
||||||
day = day.plusDays(1);
|
|
||||||
} while (next != null && !next.isAfter(now));
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ZonedDateTime forDay(final ZonedDateTime midnight, final boolean sunrise, final double zenith) {
|
|
||||||
final Location location = new Location(config.getLatitude(), config.getLongitude());
|
final Location location = new Location(config.getLatitude(), config.getLongitude());
|
||||||
final SolarEventCalculator calculator = new SolarEventCalculator(location, config.getTimezone());
|
final SolarEventCalculator calculator = new SolarEventCalculator(location, TimeZone.getTimeZone("UTC"));
|
||||||
final Calendar calendar = GregorianCalendar.from(midnight);
|
final Calendar calendar = GregorianCalendar.from(day.atStartOfDay(ZoneId.of("UTC")));
|
||||||
final Calendar nextCalendar = forDay(calculator, sunrise, new Zenith(zenith), calendar);
|
final Calendar nextCalendar = forDay(calculator, sunrise, new Zenith(zenith), calendar);
|
||||||
if (nextCalendar == null) {
|
if (nextCalendar == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(nextCalendar.getTimeInMillis()), midnight.getZone());
|
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(nextCalendar.getTimeInMillis()), ZoneId.systemDefault());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Calendar forDay(final SolarEventCalculator calculator, final boolean sunrise, final Zenith solarZenith, final Calendar calendar) {
|
private Calendar forDay(final SolarEventCalculator calculator, final boolean sunrise, final Zenith solarZenith, final Calendar calendar) {
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -0,0 +1,70 @@
|
|||||||
|
package de.ph87.homeautomation.schedule;
|
||||||
|
|
||||||
|
import de.ph87.homeautomation.Config;
|
||||||
|
import de.ph87.homeautomation.schedule.astro.AstroCalculator;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
class ScheduleCalculatorDaylightSavingTimeTransitionTest {
|
||||||
|
|
||||||
|
private static final ZonedDateTime DAY_OF_DST_SET_BACK = ZonedDateTime.of(2024, 10, 27, 0, 0, 0, 0, ZoneId.of("Europe/Berlin"));
|
||||||
|
|
||||||
|
private static final AstroCalculator astroCalculator = new AstroCalculator(new Config());
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withHour() {
|
||||||
|
final ZonedDateTime morning = DAY_OF_DST_SET_BACK.withHour(6);
|
||||||
|
assertEquals(6, morning.getHour());
|
||||||
|
assertEquals(0, morning.getMinute());
|
||||||
|
assertEquals(0, morning.getSecond());
|
||||||
|
assertEquals(0, morning.getNano());
|
||||||
|
assertEquals(3600, morning.getOffset().getTotalSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void sunrise_dstSetBack() {
|
||||||
|
final ZonedDateTime morning = astroCalculator.forDay(DAY_OF_DST_SET_BACK.toLocalDate(), true, 90);
|
||||||
|
assertEquals(7, morning.getHour());
|
||||||
|
assertEquals(19, morning.getMinute());
|
||||||
|
assertEquals(0, morning.getSecond());
|
||||||
|
assertEquals(0, morning.getNano());
|
||||||
|
assertEquals(3600, morning.getOffset().getTotalSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void sunset_dstSetBack() {
|
||||||
|
final ZonedDateTime morning = astroCalculator.forDay(DAY_OF_DST_SET_BACK.toLocalDate(), false, 90);
|
||||||
|
assertEquals(17, morning.getHour());
|
||||||
|
assertEquals(13, morning.getMinute());
|
||||||
|
assertEquals(0, morning.getSecond());
|
||||||
|
assertEquals(0, morning.getNano());
|
||||||
|
assertEquals(3600, morning.getOffset().getTotalSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void sunrise_noDstChange() {
|
||||||
|
final ZonedDateTime morning = astroCalculator.forDay(DAY_OF_DST_SET_BACK.minusDays(1).toLocalDate(), true, 90);
|
||||||
|
assertEquals(8, morning.getHour());
|
||||||
|
assertEquals(17, morning.getMinute());
|
||||||
|
assertEquals(0, morning.getSecond());
|
||||||
|
assertEquals(0, morning.getNano());
|
||||||
|
assertEquals(7200, morning.getOffset().getTotalSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void sunset_noDstChange() {
|
||||||
|
final ZonedDateTime morning = astroCalculator.forDay(DAY_OF_DST_SET_BACK.minusDays(1).toLocalDate(), false, 90);
|
||||||
|
assertEquals(18, morning.getHour());
|
||||||
|
assertEquals(14, morning.getMinute());
|
||||||
|
assertEquals(0, morning.getSecond());
|
||||||
|
assertEquals(0, morning.getNano());
|
||||||
|
assertEquals(7200, morning.getOffset().getTotalSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user