2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.io.hueemulation.internal.automation;
15 import java.time.Duration;
17 import java.util.Random;
18 import java.util.concurrent.Callable;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.core.automation.ModuleHandlerCallback;
23 import org.openhab.core.automation.Trigger;
24 import org.openhab.core.automation.handler.BaseTriggerModuleHandler;
25 import org.openhab.core.automation.handler.TriggerHandlerCallback;
26 import org.openhab.core.scheduler.ScheduledCompletableFuture;
27 import org.openhab.core.scheduler.Scheduler;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
32 * This trigger module time allows a trigger that is setup with a time (hours:minutes:seconds).
33 * As soon as that time has run up, it will trigger.
35 * A random factor and repeat times can also be configured.
37 * @author David Graeff - Initial contribution
40 public class TimerTriggerHandler extends BaseTriggerModuleHandler implements Callable<Duration> {
42 private final Logger logger = LoggerFactory.getLogger(TimerTriggerHandler.class);
44 public static final String MODULE_TYPE_ID = "timer.TimerTrigger";
45 public static final String CALLBACK_CONTEXT_NAME = "CALLBACK";
46 public static final String MODULE_CONTEXT_NAME = "MODULE";
48 public static final String CFG_REPEAT = "repeat";
49 public static final String CFG_TIME = "time";
50 public static final String CFG_TIME_RND = "randomizeTime";
52 private final Scheduler scheduler;
53 private final Duration duration;
54 private @Nullable ScheduledCompletableFuture<?> schedule;
56 private static class Config {
59 String randomizeTime = "";
64 public TimerTriggerHandler(Trigger module, Scheduler scheduler) {
66 this.scheduler = scheduler;
67 config = module.getConfiguration().as(Config.class);
69 String[] fields = config.time.split(":");
70 Duration d1 = Duration.parse(String.format("P%dH%dM%sS", fields[0], fields[1], fields[2]));
72 // Take optional random time (a range-like parameter) into account
73 if (!config.randomizeTime.isEmpty()) {
74 fields = config.randomizeTime.split(":");
75 Duration d2 = Duration.parse(String.format("P%dH%dM%sS", fields[0], fields[1], fields[2]));
76 // The random time must be later a bigger value than time
77 if (d1.compareTo(d2) >= 0) {
78 throw new IllegalArgumentException();
80 // Compute the difference, turn in to seconds, get a random second value between 0 and that upper bound
81 // and then add it to the base time
82 Duration difference = d2.minus(d1);
83 duration = d1.plus(Duration.ofSeconds(randomSeconds(difference.getSeconds())));
89 protected long randomSeconds(long maximum) {
90 return Math.abs(new Random().nextLong()) % maximum;
94 public synchronized void setCallback(ModuleHandlerCallback callback) {
95 super.setCallback(callback);
96 if (config.repeat != 0) {
101 private void scheduleJob() {
102 schedule = scheduler.after(this, duration);
103 logger.debug("Scheduled timer to expire in '{}' for trigger '{}'.", duration, module.getId());
107 public synchronized void dispose() {
109 ScheduledCompletableFuture<?> future = schedule;
110 if (future != null) {
112 logger.debug("cancelled job for trigger '{}'.", module.getId());
117 public Duration call() {
118 ((TriggerHandlerCallback) callback).triggered(module, Map.of());
120 if (config.repeat == 0) {