2 * Copyright (c) 2010-2024 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.pushover.internal.handler;
15 import static org.openhab.binding.pushover.internal.PushoverBindingConstants.*;
17 import java.util.Collection;
18 import java.util.List;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.eclipse.jetty.client.HttpClient;
24 import org.openhab.binding.pushover.internal.actions.PushoverActions;
25 import org.openhab.binding.pushover.internal.config.PushoverAccountConfiguration;
26 import org.openhab.binding.pushover.internal.config.PushoverConfigOptionProvider;
27 import org.openhab.binding.pushover.internal.connection.PushoverAPIConnection;
28 import org.openhab.binding.pushover.internal.connection.PushoverMessageBuilder;
29 import org.openhab.binding.pushover.internal.dto.Sound;
30 import org.openhab.core.i18n.CommunicationException;
31 import org.openhab.core.i18n.ConfigurationException;
32 import org.openhab.core.thing.ChannelUID;
33 import org.openhab.core.thing.Thing;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingStatusDetail;
36 import org.openhab.core.thing.binding.BaseThingHandler;
37 import org.openhab.core.thing.binding.ThingHandlerService;
38 import org.openhab.core.types.Command;
41 * The {@link PushoverAccountHandler} is responsible for handling commands, which are sent to one of the channels.
43 * @author Christoph Weitkamp - Initial contribution
46 public class PushoverAccountHandler extends BaseThingHandler {
48 private static final Collection<Class<? extends ThingHandlerService>> SUPPORTED_THING_ACTIONS = Set
49 .of(PushoverActions.class, PushoverConfigOptionProvider.class);
51 private final HttpClient httpClient;
53 private PushoverAccountConfiguration config = new PushoverAccountConfiguration();
54 private @Nullable PushoverAPIConnection connection;
56 public PushoverAccountHandler(Thing thing, HttpClient httpClient) {
58 this.httpClient = httpClient;
62 public void handleCommand(ChannelUID channelUID, Command command) {
67 public void initialize() {
68 config = getConfigAs(PushoverAccountConfiguration.class);
70 boolean configValid = true;
71 final String apikey = config.apikey;
72 if (apikey == null || apikey.isBlank()) {
73 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
74 TEXT_OFFLINE_CONF_ERROR_MISSING_APIKEY);
77 final String user = config.user;
78 if (user == null || user.isBlank()) {
79 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
80 TEXT_OFFLINE_CONF_ERROR_MISSING_USER);
85 updateStatus(ThingStatus.UNKNOWN);
87 connection = new PushoverAPIConnection(httpClient, config);
88 scheduler.submit(this::asyncValidateUser);
93 public Collection<Class<? extends ThingHandlerService>> getServices() {
94 return SUPPORTED_THING_ACTIONS;
98 * Retrieves the list of current sounds and their descriptions from the Pushover API.
100 * @return a list of {@link Sound}s
102 public List<Sound> getSounds() {
104 PushoverAPIConnection connection = this.connection;
105 if (connection != null) {
106 List<Sound> sounds = connection.getSounds();
107 if (sounds != null) {
111 } catch (CommunicationException e) {
112 // do nothing, causing exception is already logged
113 } catch (ConfigurationException e) {
114 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getRawMessage());
116 return PushoverAccountConfiguration.DEFAULT_SOUNDS;
120 * Returns a preconfigured {@link PushoverMessageBuilder}.
122 * @param message the message
123 * @return a {@link PushoverMessageBuilder} instance
125 public PushoverMessageBuilder getDefaultPushoverMessageBuilder(String message) {
126 PushoverMessageBuilder builder = PushoverMessageBuilder.getInstance(config.apikey, config.user)
127 .withMessage(message) //
128 .withTitle(config.title) //
129 .withRetry(config.retry) //
130 .withExpire(config.expire);
131 // specify format if defined
132 switch (config.format) {
133 case PushoverMessageBuilder.MESSAGE_KEY_HTML:
134 builder.withHtmlFormatting();
136 case PushoverMessageBuilder.MESSAGE_KEY_MONOSPACE:
137 builder.withMonospaceFormatting();
141 // add sound, if defined
142 if (!DEFAULT_SOUND.equals(config.sound)) {
143 builder.withSound(config.sound);
148 public boolean sendMessage(PushoverMessageBuilder messageBuilder) {
149 PushoverAPIConnection connection = this.connection;
150 if (connection != null) {
152 return connection.sendMessage(messageBuilder);
153 } catch (CommunicationException e) {
154 // do nothing, causing exception is already logged
155 } catch (ConfigurationException e) {
156 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getRawMessage());
160 throw new IllegalArgumentException("PushoverAPIConnection is null!");
164 public String sendPriorityMessage(PushoverMessageBuilder messageBuilder) {
165 PushoverAPIConnection connection = this.connection;
166 if (connection != null) {
168 return connection.sendPriorityMessage(messageBuilder);
169 } catch (CommunicationException e) {
170 // do nothing, causing exception is already logged
171 } catch (ConfigurationException e) {
172 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getRawMessage());
176 throw new IllegalArgumentException("PushoverAPIConnection is null!");
180 public boolean cancelPriorityMessage(String receipt) {
181 PushoverAPIConnection connection = this.connection;
182 if (connection != null) {
184 return connection.cancelPriorityMessage(receipt);
185 } catch (CommunicationException e) {
186 // do nothing, causing exception is already logged
187 } catch (ConfigurationException e) {
188 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getRawMessage());
192 throw new IllegalArgumentException("PushoverAPIConnection is null!");
196 @SuppressWarnings("null")
197 private void asyncValidateUser() {
199 connection.validateUser();
200 updateStatus(ThingStatus.ONLINE);
201 } catch (CommunicationException | ConfigurationException e) {
202 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getRawMessage());