2 * Copyright (c) 2010-2020 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.binding.astro.internal.action;
15 import java.lang.reflect.Method;
16 import java.lang.reflect.Proxy;
17 import java.time.ZonedDateTime;
19 import javax.measure.quantity.Angle;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.astro.internal.AstroBindingConstants;
24 import org.openhab.binding.astro.internal.handler.AstroThingHandler;
25 import org.openhab.binding.astro.internal.handler.SunHandler;
26 import org.openhab.binding.astro.internal.model.SunPhaseName;
27 import org.openhab.core.automation.annotation.ActionInput;
28 import org.openhab.core.automation.annotation.ActionOutput;
29 import org.openhab.core.automation.annotation.RuleAction;
30 import org.openhab.core.library.types.QuantityType;
31 import org.openhab.core.thing.binding.ThingActions;
32 import org.openhab.core.thing.binding.ThingActionsScope;
33 import org.openhab.core.thing.binding.ThingHandler;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 * The {AstroActions } defines rule actions for the Astro binding.
40 * <b>Note:</b>The static method <b>invokeMethodOf</b> handles the case where
41 * the test <i>actions instanceof AstroActions</i> fails. This test can fail
42 * due to an issue in openHAB core v2.5.0 where the {@link AstroActions} class
43 * can be loaded by a different classloader than the <i>actions</i> instance.
45 * @author Gaƫl L'hopital - Initial contribution
47 @ThingActionsScope(name = "astro")
49 public class AstroActions implements ThingActions, IAstroActions {
51 private final Logger logger = LoggerFactory.getLogger(AstroActions.class);
52 protected @Nullable AstroThingHandler handler;
54 public AstroActions() {
55 logger.debug("Astro actions service instanciated");
59 public void setThingHandler(@Nullable ThingHandler handler) {
60 if (handler instanceof AstroThingHandler) {
61 this.handler = (AstroThingHandler) handler;
66 public @Nullable ThingHandler getThingHandler() {
71 @RuleAction(label = "Astro : Get Azimuth", description = "Get the azimuth of the sun for a given time")
72 public @Nullable @ActionOutput(name = "getAzimuth", label = "Azimuth", type = "org.openhab.core.library.types.QuantityType<javax.measure.quantity.Angle>") QuantityType<Angle> getAzimuth(
73 @ActionInput(name = "date", label = "Date", required = false, description = "Considered date") @Nullable ZonedDateTime date) {
74 logger.debug("Astro action 'getAzimuth' called");
75 AstroThingHandler theHandler = this.handler;
76 if (theHandler != null) {
77 return theHandler.getAzimuth(date != null ? date : ZonedDateTime.now());
79 logger.info("Astro Action service ThingHandler is null!");
85 @RuleAction(label = "Astro : Get Elevation", description = "Get the Elevation of the sun for a given time")
86 public @Nullable @ActionOutput(name = "getElevation", label = "Elevation", type = "org.openhab.core.library.types.QuantityType<javax.measure.quantity.Angle>") QuantityType<Angle> getElevation(
87 @ActionInput(name = "date", label = "Date", required = false, description = "Considered date") @Nullable ZonedDateTime date) {
88 logger.debug("Astro action 'getElevation' called");
89 AstroThingHandler theHandler = this.handler;
90 if (theHandler != null) {
91 return theHandler.getElevation(date != null ? date : ZonedDateTime.now());
93 logger.info("Astro Action service ThingHandler is null!");
99 @RuleAction(label = "Sun : Get Event Time", description = "Get the date time of a given planet event")
100 public @Nullable @ActionOutput(name = "getEventTime", type = "java.time.ZonedDateTime") ZonedDateTime getEventTime(
101 @ActionInput(name = "phaseName", label = "Phase", required = true, description = "Requested phase") String phaseName,
102 @ActionInput(name = "date", label = "Date", required = false, description = "Considered date") @Nullable ZonedDateTime date,
103 @ActionInput(name = "moment", label = "Moment", required = false, defaultValue = "START", description = "Either START or END") @Nullable String moment) {
104 logger.debug("Sun action 'getEventTime' called");
106 AstroThingHandler theHandler = this.handler;
107 if (theHandler != null) {
108 if (theHandler instanceof SunHandler) {
109 SunHandler handler = (SunHandler) theHandler;
110 SunPhaseName phase = SunPhaseName.valueOf(phaseName.toUpperCase());
111 return handler.getEventTime(phase, date != null ? date : ZonedDateTime.now(),
112 moment == null || AstroBindingConstants.EVENT_START.equalsIgnoreCase(moment));
114 logger.info("Astro Action service ThingHandler is not a SunHandler!");
117 logger.info("Astro Action service ThingHandler is null!");
119 } catch (IllegalArgumentException e) {
120 logger.info("Parameter {} is not a valid phase name", phaseName);
125 public static @Nullable QuantityType<Angle> getElevation(@Nullable ThingActions actions,
126 @Nullable ZonedDateTime date) {
127 return invokeMethodOf(actions).getElevation(date);
130 public static @Nullable QuantityType<Angle> getAzimuth(@Nullable ThingActions actions,
131 @Nullable ZonedDateTime date) {
132 return invokeMethodOf(actions).getAzimuth(date);
135 public static @Nullable ZonedDateTime getEventTime(@Nullable ThingActions actions, @Nullable String phaseName,
136 @Nullable ZonedDateTime date, @Nullable String moment) {
137 if (phaseName != null) {
138 return invokeMethodOf(actions).getEventTime(phaseName, date, moment);
140 throw new IllegalArgumentException("phaseName can not be null");
144 private static IAstroActions invokeMethodOf(@Nullable ThingActions actions) {
145 if (actions == null) {
146 throw new IllegalArgumentException("actions cannot be null");
148 if (actions.getClass().getName().equals(AstroActions.class.getName())) {
149 if (actions instanceof IAstroActions) {
150 return (IAstroActions) actions;
152 return (IAstroActions) Proxy.newProxyInstance(IAstroActions.class.getClassLoader(),
153 new Class[] { IAstroActions.class }, (Object proxy, Method method, Object[] args) -> {
154 Method m = actions.getClass().getDeclaredMethod(method.getName(),
155 method.getParameterTypes());
156 return m.invoke(actions, args);
160 throw new IllegalArgumentException("Actions is not an instance of AstroActions");