mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[pushover] Migration of Pushover OH1 action to OH3 binding (#8586)
Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
parent
5d60d6464b
commit
6e0cacab31
@ -201,6 +201,7 @@
|
||||
/bundles/org.openhab.binding.powermax/ @lolodomo
|
||||
/bundles/org.openhab.binding.pulseaudio/ @peuter
|
||||
/bundles/org.openhab.binding.pushbullet/ @hakan42
|
||||
/bundles/org.openhab.binding.pushover/ @cweitkamp
|
||||
/bundles/org.openhab.binding.radiothermostat/ @mlobstein
|
||||
/bundles/org.openhab.binding.regoheatpump/ @crnjan
|
||||
/bundles/org.openhab.binding.revogi/ @andibraeu
|
||||
|
@ -996,6 +996,11 @@
|
||||
<artifactId>org.openhab.binding.pushbullet</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.pushover</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.radiothermostat</artifactId>
|
||||
|
13
bundles/org.openhab.binding.pushover/NOTICE
Normal file
13
bundles/org.openhab.binding.pushover/NOTICE
Normal file
@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
78
bundles/org.openhab.binding.pushover/README.md
Normal file
78
bundles/org.openhab.binding.pushover/README.md
Normal file
@ -0,0 +1,78 @@
|
||||
# Pushover Binding
|
||||
|
||||
The Pushover binding allows you to notify mobile devices of a message using the [Pushover REST API](https://pushover.net/api).
|
||||
To get started you first need to register (a free process) to get an API token.
|
||||
Initially you have to create an application, set its name and optionally upload an icon, and get the API token in return.
|
||||
Once you have the token, you need a user key (or group key) and optionally a device name for each user to which you want to push notifications.
|
||||
|
||||
## Supported Things
|
||||
|
||||
There is only one Thing available - the `pushover-account`.
|
||||
You are able to create multiple instances of this Thing to broadcast to different users, groups or devices.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
| Configuration Parameter | Type | Description |
|
||||
|-------------------------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `apikey` | text | Your API token / key (APP_TOKEN) to access the Pushover Message API. **mandatory** |
|
||||
| `user` | text | Your user key or group key (USER_KEY) to which you want to push notifications. **mandatory** |
|
||||
| `title` | text | The default title of a message (default: `openHAB`). |
|
||||
| `format` | text | The default format (`none`, `HTML` or `monospace`) of a message (default: `none`). |
|
||||
| `sound` | text | The default notification sound on target device (default: `default`) (see [supported notification sounds](https://pushover.net/api#sounds)). |
|
||||
| `retry` | integer | The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user (default: `300`). **advanced** |
|
||||
| `expire` | integer | The expire parameter specifies how long (in seconds) your notification will continue to be retried (default: `3600`). **advanced** |
|
||||
|
||||
The `retry` and `expire` parameters are only used for emergency-priority notifications.
|
||||
|
||||
## Channels
|
||||
|
||||
Currently the binding does not support any Channels.
|
||||
|
||||
## Thing Actions
|
||||
|
||||
All actions return a `Boolean` value to indicate if the message - parameter `message` **mandatory** - was sent successfully or not.
|
||||
The `title` parameter defaults to whatever value you defined in the `title` related configuration parameter.
|
||||
|
||||
`sendMessage(String message, @Nullable String title)` - This method is used to send a plain text message.
|
||||
`sendHtmlMessage(String message, @Nullable String title)` - This method is used to send a HTML message.
|
||||
`sendMonospaceMessage(String message, @Nullable String title)` - This method is used to send a monospace message.
|
||||
`sendAttachmentMessage(String message, @Nullable String title, String attachment, @Nullable String contentType)` - This method is used to send a message with an attachment. It takes a (local) path (`attachment` **mandatory**) to the attachment and an optional parameter `contentType` to define the content-type of the attachment (default: `image/jpeg`).
|
||||
`sendURLMessage(String message, @Nullable String title, String url, @Nullable String urlTitle)` - This method is used to send a message with an URL. A supplementary `url` to show with the message and a `urlTitle` for the URL, otherwise just the URL is shown.
|
||||
`sendMessageToDevice(String device, String message, @Nullable String title)` - This method is used to send a message to a specific device. Parameter `device` **mandatory** is the name of a specific device (multiple devices may be separated by a comma).
|
||||
|
||||
The `sendPriorityMessage` action returns a `String` value (the `receipt`) if the message was sent successfully, otherwise `null`.
|
||||
|
||||
`sendPriorityMessage(String message, @Nullable String title, @Nullable Integer priority)` - This method is used to send a priority message. Parameter `priority` is the priority (`-2`, `-1`, `0`, `1`, `2`) to be used (default: `2`).
|
||||
|
||||
`cancelPriorityMessage` returns a `Boolean` value to indicate if the message was cancelled successfully or not.
|
||||
|
||||
`cancelPriorityMessage(String receipt)` - This method is used to cancel a priority message.
|
||||
|
||||
## Full Example
|
||||
|
||||
demo.things:
|
||||
|
||||
```java
|
||||
Thing pushover:pushover-account:account [ apikey="APP_TOKEN", user="USER_KEY" ]
|
||||
```
|
||||
|
||||
demo.rules:
|
||||
|
||||
```java
|
||||
val actions = getActions("pushover", "pushover:pushover-account:account")
|
||||
// send HTML message
|
||||
actions.sendHtmlMessage("Hello <font color='green'>World</font>!", "openHAB")
|
||||
```
|
||||
|
||||
```java
|
||||
val actions = getActions("pushover", "pushover:pushover-account:account")
|
||||
// send priority message
|
||||
var receipt = actions.sendPriorityMessage("Hello <font color='green'>World</font>!", "openHAB", 3)
|
||||
|
||||
// wait for your cancel condition
|
||||
|
||||
if( receipt !== null ) {
|
||||
actions.cancelPriorityMessage(receipt)
|
||||
receipt = null
|
||||
}
|
||||
```
|
17
bundles/org.openhab.binding.pushover/pom.xml
Normal file
17
bundles/org.openhab.binding.pushover/pom.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.pushover</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Pushover Binding</name>
|
||||
|
||||
</project>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.pushover-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-pushover" description="Pushover Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.pushover/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link PushoverBindingConstants} class defines common constants, which are used across the whole binding.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushoverBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "pushover";
|
||||
|
||||
public static final ThingTypeUID PUSHOVER_ACCOUNT = new ThingTypeUID(BINDING_ID, "pushover-account");
|
||||
|
||||
public static final String CONFIG_SOUND = "sound";
|
||||
|
||||
public static final String DEFAULT_SOUND = "default";
|
||||
public static final String DEFAULT_TITLE = "openHAB";
|
||||
}
|
@ -0,0 +1,220 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal.actions;
|
||||
|
||||
import static org.openhab.binding.pushover.internal.PushoverBindingConstants.DEFAULT_TITLE;
|
||||
import static org.openhab.binding.pushover.internal.connection.PushoverMessageBuilder.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.pushover.internal.connection.PushoverMessageBuilder;
|
||||
import org.openhab.binding.pushover.internal.handler.PushoverAccountHandler;
|
||||
import org.openhab.core.automation.annotation.ActionInput;
|
||||
import org.openhab.core.automation.annotation.ActionOutput;
|
||||
import org.openhab.core.automation.annotation.RuleAction;
|
||||
import org.openhab.core.thing.binding.ThingActions;
|
||||
import org.openhab.core.thing.binding.ThingActionsScope;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Some automation actions to be used with a {@link PushoverAccountHandler}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@ThingActionsScope(name = "pushover")
|
||||
@NonNullByDefault
|
||||
public class PushoverActions implements ThingActions {
|
||||
|
||||
private static final String DEFAULT_EMERGENCY_PRIORITY = "2";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(PushoverActions.class);
|
||||
|
||||
private @NonNullByDefault({}) PushoverAccountHandler accountHandler;
|
||||
|
||||
@RuleAction(label = "@text/sendMessageActionLabel", description = "@text/sendMessageActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendMessageActionOutputLabel", description = "@text/sendMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendMessageActionInputTitleLabel", description = "@text/sendMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title) {
|
||||
logger.trace("ThingAction 'sendMessage' called with value(s): message='{}', title='{}'", message, title);
|
||||
return send(getDefaultPushoverMessageBuilder(message), title);
|
||||
}
|
||||
|
||||
public static Boolean sendMessage(ThingActions actions, String message, @Nullable String title) {
|
||||
return ((PushoverActions) actions).sendMessage(message, title);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendURLMessageActionLabel", description = "@text/sendURLMessageActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendMessageActionOutputLabel", description = "@text/sendMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendURLMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendMessageActionInputTitleLabel", description = "@text/sendMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title,
|
||||
@ActionInput(name = "url", label = "@text/sendMessageActionInputURLLabel", description = "@text/sendMessageActionInputURLDescription", type = "java.lang.String", required = true) String url,
|
||||
@ActionInput(name = "urlTitle", label = "@text/sendMessageActionInputURLTitleLabel", description = "@text/sendMessageActionInputURLTitleDescription", type = "java.lang.String") @Nullable String urlTitle) {
|
||||
logger.trace(
|
||||
"ThingAction 'sendURLMessage' called with value(s): message='{}', url='{}', title='{}', urlTitle='{}'",
|
||||
message, url, title, urlTitle);
|
||||
if (url == null) {
|
||||
throw new IllegalArgumentException("Skip sending message as 'url' is null.");
|
||||
}
|
||||
|
||||
PushoverMessageBuilder builder = getDefaultPushoverMessageBuilder(message).withUrl(url);
|
||||
if (urlTitle != null) {
|
||||
builder.withUrl(urlTitle);
|
||||
}
|
||||
return send(builder, title);
|
||||
}
|
||||
|
||||
public static Boolean sendURLMessage(ThingActions actions, String message, @Nullable String title, String url,
|
||||
@Nullable String urlTitle) {
|
||||
return ((PushoverActions) actions).sendURLMessage(message, title, url, urlTitle);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendHTMLMessageActionLabel", description = "@text/sendHTMLMessageActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendMessageActionOutputLabel", description = "@text/sendMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendHtmlMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendMessageActionInputTitleLabel", description = "@text/sendMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title) {
|
||||
logger.trace("ThingAction 'sendHtmlMessage' called with value(s): message='{}', title='{}'", message, title);
|
||||
return send(getDefaultPushoverMessageBuilder(message).withHtmlFormatting(), title);
|
||||
}
|
||||
|
||||
public static Boolean sendHtmlMessage(ThingActions actions, String message, @Nullable String title) {
|
||||
return ((PushoverActions) actions).sendHtmlMessage(message, title);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendMonospaceMessageActionLabel", description = "@text/sendMonospaceMessageActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendMessageActionOutputLabel", description = "@text/sendMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendMonospaceMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendMessageActionInputTitleLabel", description = "@text/sendMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title) {
|
||||
logger.trace("ThingAction 'sendMonospaceMessage' called with value(s): message='{}', title='{}'", message,
|
||||
title);
|
||||
return send(getDefaultPushoverMessageBuilder(message).withMonospaceFormatting(), title);
|
||||
}
|
||||
|
||||
public static Boolean sendMonospaceMessage(ThingActions actions, String message, @Nullable String title) {
|
||||
return ((PushoverActions) actions).sendMonospaceMessage(message, title);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendAttachmentMessageActionLabel", description = "@text/sendAttachmentMessageActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendMessageActionOutputLabel", description = "@text/sendMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendAttachmentMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendMessageActionInputTitleLabel", description = "@text/sendMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title,
|
||||
@ActionInput(name = "attachment", label = "@text/sendMessageActionInputAttachmentLabel", description = "@text/sendMessageActionInputAttachmentDescription", type = "java.lang.String", required = true) String attachment,
|
||||
@ActionInput(name = "contentType", label = "@text/sendMessageActionInputContentTypeLabel", description = "@text/sendMessageActionInputContentTypeDescription", type = "java.lang.String", defaultValue = DEFAULT_CONTENT_TYPE) @Nullable String contentType) {
|
||||
logger.trace(
|
||||
"ThingAction 'sendAttachmentMessage' called with value(s): message='{}', title='{}', attachment='{}', contentType='{}'",
|
||||
message, title, attachment, contentType);
|
||||
if (attachment == null) {
|
||||
throw new IllegalArgumentException("Skip sending message as 'attachment' is null.");
|
||||
}
|
||||
|
||||
PushoverMessageBuilder builder = getDefaultPushoverMessageBuilder(message).withAttachment(attachment);
|
||||
if (contentType != null) {
|
||||
builder.withContentType(contentType);
|
||||
}
|
||||
return send(builder, title);
|
||||
}
|
||||
|
||||
public static Boolean sendAttachmentMessage(ThingActions actions, String message, @Nullable String title,
|
||||
String attachment, @Nullable String contentType) {
|
||||
return ((PushoverActions) actions).sendAttachmentMessage(message, title, attachment, contentType);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendPriorityMessageActionLabel", description = "@text/sendPriorityMessageActionDescription")
|
||||
public @ActionOutput(name = "receipt", label = "@text/sendPriorityMessageActionOutputLabel", description = "@text/sendPriorityMessageActionOutputDescription", type = "java.lang.String") String sendPriorityMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendMessageActionInputTitleLabel", description = "@text/sendMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title,
|
||||
@ActionInput(name = "priority", label = "@text/sendMessageActionInputPriorityLabel", description = "@text/sendMessageActionInputPriorityDescription", type = "java.lang.Integer", defaultValue = DEFAULT_EMERGENCY_PRIORITY) @Nullable Integer priority) {
|
||||
logger.trace("ThingAction 'sendPriorityMessage' called with value(s): message='{}', title='{}', priority='{}'",
|
||||
message, title, priority);
|
||||
PushoverMessageBuilder builder = getDefaultPushoverMessageBuilder(message)
|
||||
.withPriority(priority == null ? EMERGENCY_PRIORITY : priority.intValue());
|
||||
|
||||
if (title != null) {
|
||||
builder.withTitle(title);
|
||||
}
|
||||
return accountHandler.sendPriorityMessage(builder);
|
||||
}
|
||||
|
||||
public static String sendPriorityMessage(ThingActions actions, String message, @Nullable String title,
|
||||
@Nullable Integer priority) {
|
||||
return ((PushoverActions) actions).sendPriorityMessage(message, title, priority);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/cancelPriorityMessageActionLabel", description = "@text/cancelPriorityMessageActionDescription")
|
||||
public @ActionOutput(name = "canceled", label = "@text/cancelPriorityMessageActionOutputLabel", description = "@text/cancelPriorityMessageActionOutputDescription", type = "java.lang.Boolean") Boolean cancelPriorityMessage(
|
||||
@ActionInput(name = "receipt", label = "@text/cancelPriorityMessageActionInputReceiptLabel", description = "@text/cancelPriorityMessageActionInputReceiptDescription", type = "java.lang.String", required = true) String receipt) {
|
||||
logger.trace("ThingAction 'cancelPriorityMessage' called with value(s): '{}'", receipt);
|
||||
if (accountHandler == null) {
|
||||
throw new RuntimeException("PushoverAccountHandler is null!");
|
||||
}
|
||||
|
||||
if (receipt == null) {
|
||||
throw new IllegalArgumentException("Skip canceling message as 'receipt' is null.");
|
||||
}
|
||||
|
||||
return accountHandler.cancelPriorityMessage(receipt);
|
||||
}
|
||||
|
||||
public static Boolean cancelPriorityMessage(ThingActions actions, String receipt) {
|
||||
return ((PushoverActions) actions).cancelPriorityMessage(receipt);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendMessageToDeviceActionLabel", description = "@text/sendMessageToDeviceActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendMessageActionOutputLabel", description = "@text/sendMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendMessageToDevice(
|
||||
@ActionInput(name = "device", label = "@text/sendMessageActionInputDeviceLabel", description = "@text/sendMessageActionInputDeviceDescription", type = "java.lang.String", required = true) String device,
|
||||
@ActionInput(name = "message", label = "@text/sendMessageActionInputMessageLabel", description = "@text/sendMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendMessageActionInputTitleLabel", description = "@text/sendMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title) {
|
||||
logger.trace("ThingAction 'sendMessageToDevice' called with value(s): device='{}', message='{}', title='{}'",
|
||||
device, message, title);
|
||||
if (device == null) {
|
||||
throw new IllegalArgumentException("Skip sending message as 'device' is null.");
|
||||
}
|
||||
|
||||
return send(getDefaultPushoverMessageBuilder(message).withDevice(device), title);
|
||||
}
|
||||
|
||||
public static Boolean sendMessageToDevice(ThingActions actions, String device, String message,
|
||||
@Nullable String title) {
|
||||
return ((PushoverActions) actions).sendMessageToDevice(device, message, title);
|
||||
}
|
||||
|
||||
private PushoverMessageBuilder getDefaultPushoverMessageBuilder(String message) {
|
||||
if (accountHandler == null) {
|
||||
throw new RuntimeException("PushoverAccountHandler is null!");
|
||||
}
|
||||
|
||||
if (message == null) {
|
||||
throw new IllegalArgumentException("Skip sending message as 'message' is null.");
|
||||
}
|
||||
|
||||
return accountHandler.getDefaultPushoverMessageBuilder(message);
|
||||
}
|
||||
|
||||
private Boolean send(PushoverMessageBuilder builder, @Nullable String title) {
|
||||
if (title != null) {
|
||||
builder.withTitle(title);
|
||||
}
|
||||
return accountHandler.sendMessage(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
this.accountHandler = (PushoverAccountHandler) handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return accountHandler;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal.config;
|
||||
|
||||
import static org.openhab.binding.pushover.internal.PushoverBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link PushoverAccountConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushoverAccountConfiguration {
|
||||
public @Nullable String apikey;
|
||||
public @Nullable String user;
|
||||
public String title = DEFAULT_TITLE;
|
||||
public String format = "none";
|
||||
public String sound = DEFAULT_SOUND;
|
||||
public int retry = 300;
|
||||
public int expire = 3600;
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal.config;
|
||||
|
||||
import static org.openhab.binding.pushover.internal.PushoverBindingConstants.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.pushover.internal.dto.Sound;
|
||||
import org.openhab.binding.pushover.internal.handler.PushoverAccountHandler;
|
||||
import org.openhab.core.config.core.ConfigOptionProvider;
|
||||
import org.openhab.core.config.core.ParameterOption;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* The {@link PushoverConfigOptionProvider} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ConfigOptionProvider.class)
|
||||
public class PushoverConfigOptionProvider implements ConfigOptionProvider, ThingHandlerService {
|
||||
|
||||
private @Nullable PushoverAccountHandler accountHandler;
|
||||
|
||||
@Override
|
||||
public @Nullable Collection<ParameterOption> getParameterOptions(URI uri, String param, @Nullable String context,
|
||||
@Nullable Locale locale) {
|
||||
if (accountHandler != null && PUSHOVER_ACCOUNT.getAsString().equals(uri.getSchemeSpecificPart())
|
||||
&& CONFIG_SOUND.equals(param)) {
|
||||
List<Sound> sounds = accountHandler.getSounds();
|
||||
if (!sounds.isEmpty()) {
|
||||
return sounds.stream().map(Sound::getAsParameterOption)
|
||||
.sorted(Comparator.comparing(ParameterOption::getLabel))
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
this.accountHandler = (PushoverAccountHandler) handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return accountHandler;
|
||||
}
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal.connection;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.api.ContentProvider;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.openhab.binding.pushover.internal.config.PushoverAccountConfiguration;
|
||||
import org.openhab.binding.pushover.internal.dto.Sound;
|
||||
import org.openhab.core.cache.ExpiringCacheMap;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
/**
|
||||
* The {@link PushoverAPIConnection} is responsible for handling the connections to Pushover Messages API.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushoverAPIConnection {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(PushoverAPIConnection.class);
|
||||
|
||||
private static final String VALIDATE_URL = "https://api.pushover.net/1/users/validate.json";
|
||||
private static final String MESSAGE_URL = "https://api.pushover.net/1/messages.json";
|
||||
private static final String CANCEL_MESSAGE_URL = "https://api.pushover.net/1/receipts/{receipt}/cancel.json";
|
||||
private static final String SOUNDS_URL = "https://api.pushover.net/1/sounds.json";
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final PushoverAccountConfiguration config;
|
||||
|
||||
private final ExpiringCacheMap<String, String> cache = new ExpiringCacheMap<>(TimeUnit.DAYS.toMillis(1));
|
||||
|
||||
private final JsonParser parser = new JsonParser();
|
||||
|
||||
public PushoverAPIConnection(HttpClient httpClient, PushoverAccountConfiguration config) {
|
||||
this.httpClient = httpClient;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public boolean validateUser() throws PushoverCommunicationException, PushoverConfigurationException {
|
||||
return getMessageStatus(
|
||||
post(VALIDATE_URL, PushoverMessageBuilder.getInstance(config.apikey, config.user).build()));
|
||||
}
|
||||
|
||||
public boolean sendMessage(PushoverMessageBuilder message)
|
||||
throws PushoverCommunicationException, PushoverConfigurationException {
|
||||
return getMessageStatus(post(MESSAGE_URL, message.build()));
|
||||
}
|
||||
|
||||
public String sendPriorityMessage(PushoverMessageBuilder message)
|
||||
throws PushoverCommunicationException, PushoverConfigurationException {
|
||||
final JsonObject json = parser.parse(post(MESSAGE_URL, message.build())).getAsJsonObject();
|
||||
return getMessageStatus(json) && json.has("receipt") ? json.get("receipt").getAsString() : "";
|
||||
}
|
||||
|
||||
public boolean cancelPriorityMessage(String receipt)
|
||||
throws PushoverCommunicationException, PushoverConfigurationException {
|
||||
return getMessageStatus(post(CANCEL_MESSAGE_URL.replace("{receipt}", receipt),
|
||||
PushoverMessageBuilder.getInstance(config.apikey, config.user).build()));
|
||||
}
|
||||
|
||||
public List<Sound> getSounds() throws PushoverCommunicationException, PushoverConfigurationException {
|
||||
final String localApikey = config.apikey;
|
||||
if (localApikey == null || localApikey.isEmpty()) {
|
||||
throw new PushoverConfigurationException("@text/offline.conf-error-missing-apikey");
|
||||
}
|
||||
|
||||
final Map<String, String> params = new HashMap<>(1);
|
||||
params.put(PushoverMessageBuilder.MESSAGE_KEY_TOKEN, localApikey);
|
||||
|
||||
// TODO do not cache the response, cache the parsed list of sounds
|
||||
final JsonObject json = parser.parse(getFromCache(buildURL(SOUNDS_URL, params))).getAsJsonObject();
|
||||
if (json.has("sounds")) {
|
||||
final JsonObject sounds = json.get("sounds").getAsJsonObject();
|
||||
if (sounds != null) {
|
||||
return Collections.unmodifiableList(sounds.entrySet().stream()
|
||||
.map(entry -> new Sound(entry.getKey(), entry.getValue().getAsString()))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private String buildURL(String url, Map<String, String> requestParams) {
|
||||
return requestParams.keySet().stream().map(key -> key + "=" + encodeParam(requestParams.get(key)))
|
||||
.collect(Collectors.joining("&", url + "?", ""));
|
||||
}
|
||||
|
||||
private String encodeParam(@Nullable String value) {
|
||||
return value == null ? "" : URLEncoder.encode(value, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private @Nullable String getFromCache(String url) {
|
||||
return cache.putIfAbsentAndGet(url, () -> get(url));
|
||||
}
|
||||
|
||||
private String get(String url) throws PushoverCommunicationException, PushoverConfigurationException {
|
||||
return executeRequest(HttpMethod.GET, url, null);
|
||||
}
|
||||
|
||||
private String post(String url, ContentProvider body)
|
||||
throws PushoverCommunicationException, PushoverConfigurationException {
|
||||
return executeRequest(HttpMethod.POST, url, body);
|
||||
}
|
||||
|
||||
private String executeRequest(HttpMethod httpMethod, String url, @Nullable ContentProvider body)
|
||||
throws PushoverCommunicationException, PushoverConfigurationException {
|
||||
logger.trace("Pushover request: {} - URL = '{}'", httpMethod, url);
|
||||
try {
|
||||
final Request request = httpClient.newRequest(url).method(httpMethod).timeout(10, TimeUnit.SECONDS);
|
||||
|
||||
if (body != null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Pushover request body: '{}'", body);
|
||||
}
|
||||
request.content(body);
|
||||
}
|
||||
|
||||
final ContentResponse contentResponse = request.send();
|
||||
|
||||
final int httpStatus = contentResponse.getStatus();
|
||||
final String content = contentResponse.getContentAsString();
|
||||
logger.trace("Pushover response: status = {}, content = '{}'", httpStatus, content);
|
||||
switch (httpStatus) {
|
||||
case HttpStatus.OK_200:
|
||||
return content;
|
||||
case HttpStatus.BAD_REQUEST_400:
|
||||
logger.debug("Pushover server responded with status code {}: {}", httpStatus, content);
|
||||
throw new PushoverConfigurationException(getMessageError(content));
|
||||
default:
|
||||
logger.debug("Pushover server responded with status code {}: {}", httpStatus, content);
|
||||
throw new PushoverCommunicationException(content);
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
logger.debug("Exception occurred during execution: {}", e.getLocalizedMessage(), e);
|
||||
throw new PushoverCommunicationException(e.getLocalizedMessage(), e.getCause());
|
||||
} catch (InterruptedException | TimeoutException e) {
|
||||
logger.debug("Exception occurred during execution: {}", e.getLocalizedMessage(), e);
|
||||
throw new PushoverCommunicationException(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String getMessageError(String content) {
|
||||
final JsonObject json = parser.parse(content).getAsJsonObject();
|
||||
if (json.has("errors")) {
|
||||
final JsonArray errors = json.get("errors").getAsJsonArray();
|
||||
if (errors != null) {
|
||||
return errors.toString();
|
||||
}
|
||||
}
|
||||
return "Unknown error occured.";
|
||||
}
|
||||
|
||||
private boolean getMessageStatus(String content) {
|
||||
final JsonObject json = parser.parse(content).getAsJsonObject();
|
||||
return json.has("status") ? json.get("status").getAsInt() == 1 : false;
|
||||
}
|
||||
|
||||
private boolean getMessageStatus(JsonObject json) {
|
||||
return json.has("status") ? json.get("status").getAsInt() == 1 : false;
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal.connection;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link PushoverCommunicationException} is a configuration exception for the connections to Pushover Messages API.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushoverCommunicationException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructs a new exception with null as its detail message.
|
||||
*/
|
||||
public PushoverCommunicationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message Detail message
|
||||
*/
|
||||
public PushoverCommunicationException(@Nullable String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause The cause
|
||||
*/
|
||||
public PushoverCommunicationException(@Nullable Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* @param message Detail message
|
||||
* @param cause The cause
|
||||
*/
|
||||
public PushoverCommunicationException(@Nullable String message, @Nullable Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal.connection;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link PushoverConfigurationException} is a configuration exception for the connections to Pushover Messages API.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushoverConfigurationException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructs a new exception with null as its detail message.
|
||||
*/
|
||||
public PushoverConfigurationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message Detail message
|
||||
*/
|
||||
public PushoverConfigurationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause The cause
|
||||
*/
|
||||
public PushoverConfigurationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* @param message Detail message
|
||||
* @param cause The cause
|
||||
*/
|
||||
public PushoverConfigurationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,263 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal.connection;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.api.ContentProvider;
|
||||
import org.eclipse.jetty.client.util.MultiPartContentProvider;
|
||||
import org.eclipse.jetty.client.util.PathContentProvider;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link PushoverMessageBuilder} builds the body for Pushover Messages API requests.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushoverMessageBuilder {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(PushoverMessageBuilder.class);
|
||||
|
||||
public static final String MESSAGE_KEY_TOKEN = "token";
|
||||
private static final String MESSAGE_KEY_USER = "user";
|
||||
private static final String MESSAGE_KEY_MESSAGE = "message";
|
||||
private static final String MESSAGE_KEY_TITLE = "title";
|
||||
private static final String MESSAGE_KEY_DEVICE = "device";
|
||||
private static final String MESSAGE_KEY_PRIORITY = "priority";
|
||||
private static final String MESSAGE_KEY_RETRY = "retry";
|
||||
private static final String MESSAGE_KEY_EXPIRE = "expire";
|
||||
private static final String MESSAGE_KEY_URL = "url";
|
||||
private static final String MESSAGE_KEY_URL_TITLE = "url_title";
|
||||
private static final String MESSAGE_KEY_SOUND = "sound";
|
||||
private static final String MESSAGE_KEY_ATTACHMENT = "attachment";
|
||||
public static final String MESSAGE_KEY_HTML = "html";
|
||||
public static final String MESSAGE_KEY_MONOSPACE = "monospace";
|
||||
|
||||
private static final int MAX_MESSAGE_LENGTH = 1024;
|
||||
private static final int MAX_TITLE_LENGTH = 250;
|
||||
private static final int MAX_DEVICE_LENGTH = 25;
|
||||
private static final List<Integer> VALID_PRIORITY_LIST = Arrays.asList(-2, -1, 0, 1, 2);
|
||||
private static final int DEFAULT_PRIORITY = 0;
|
||||
public static final int EMERGENCY_PRIORITY = 2;
|
||||
private static final int MIN_RETRY_SECONDS = 30;
|
||||
private static final int MAX_EXPIRE_SECONDS = 10800;
|
||||
private static final int MAX_URL_LENGTH = 512;
|
||||
private static final int MAX_URL_TITLE_LENGTH = 100;
|
||||
public static final String DEFAULT_CONTENT_TYPE = "image/jpeg";
|
||||
|
||||
private final MultiPartContentProvider body = new MultiPartContentProvider();
|
||||
|
||||
private @Nullable String message;
|
||||
private @Nullable String title;
|
||||
private @Nullable String device;
|
||||
private int priority = DEFAULT_PRIORITY;
|
||||
private int retry = 300;
|
||||
private int expire = 3600;
|
||||
private @Nullable String url;
|
||||
private @Nullable String urlTitle;
|
||||
private @Nullable String sound;
|
||||
private @Nullable String attachment;
|
||||
private String contentType = DEFAULT_CONTENT_TYPE;
|
||||
private boolean html = false;
|
||||
private boolean monospace = false;
|
||||
|
||||
private PushoverMessageBuilder(String apikey, String user) throws PushoverConfigurationException {
|
||||
body.addFieldPart(MESSAGE_KEY_TOKEN, new StringContentProvider(apikey), null);
|
||||
body.addFieldPart(MESSAGE_KEY_USER, new StringContentProvider(user), null);
|
||||
}
|
||||
|
||||
public static PushoverMessageBuilder getInstance(@Nullable String apikey, @Nullable String user)
|
||||
throws PushoverConfigurationException {
|
||||
if (apikey == null || apikey.isEmpty()) {
|
||||
throw new PushoverConfigurationException("@text/offline.conf-error-missing-apikey");
|
||||
}
|
||||
|
||||
if (user == null || user.isEmpty()) {
|
||||
throw new PushoverConfigurationException("@text/offline.conf-error-missing-user");
|
||||
}
|
||||
|
||||
return new PushoverMessageBuilder(apikey, user);
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withMessage(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withTitle(String title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withDevice(String device) {
|
||||
this.device = device;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withPriority(int priority) {
|
||||
this.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withRetry(int retry) {
|
||||
this.retry = retry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withExpire(int expire) {
|
||||
this.expire = expire;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withUrl(String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withUrlTitle(String urlTitle) {
|
||||
this.urlTitle = urlTitle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withSound(String sound) {
|
||||
this.sound = sound;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withAttachment(String attachment) {
|
||||
this.attachment = attachment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withContentType(String contentType) {
|
||||
this.contentType = contentType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withHtmlFormatting() {
|
||||
this.html = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushoverMessageBuilder withMonospaceFormatting() {
|
||||
this.monospace = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContentProvider build() {
|
||||
if (message != null) {
|
||||
if (message.length() > MAX_MESSAGE_LENGTH) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Skip sending the message as 'message' is longer than %d characters.", MAX_MESSAGE_LENGTH));
|
||||
}
|
||||
body.addFieldPart(MESSAGE_KEY_MESSAGE, new StringContentProvider(message), null);
|
||||
}
|
||||
|
||||
if (title != null) {
|
||||
if (title.length() > MAX_TITLE_LENGTH) {
|
||||
throw new IllegalArgumentException(String
|
||||
.format("Skip sending the message as 'title' is longer than %d characters.", MAX_TITLE_LENGTH));
|
||||
}
|
||||
body.addFieldPart(MESSAGE_KEY_TITLE, new StringContentProvider(title), null);
|
||||
}
|
||||
|
||||
if (device != null) {
|
||||
if (device.length() > MAX_DEVICE_LENGTH) {
|
||||
logger.warn("Skip 'device' as it is longer than {} characters. Got: {}.", MAX_DEVICE_LENGTH, device);
|
||||
} else {
|
||||
body.addFieldPart(MESSAGE_KEY_DEVICE, new StringContentProvider(device), null);
|
||||
}
|
||||
}
|
||||
|
||||
if (priority != DEFAULT_PRIORITY) {
|
||||
if (VALID_PRIORITY_LIST.contains(priority)) {
|
||||
body.addFieldPart(MESSAGE_KEY_PRIORITY, new StringContentProvider(String.valueOf(priority)), null);
|
||||
|
||||
if (priority == EMERGENCY_PRIORITY) {
|
||||
if (retry < MIN_RETRY_SECONDS) {
|
||||
logger.warn("Retry value of {} is too small. Using default value of {}.", retry,
|
||||
MIN_RETRY_SECONDS);
|
||||
body.addFieldPart(MESSAGE_KEY_RETRY,
|
||||
new StringContentProvider(String.valueOf(MIN_RETRY_SECONDS)), null);
|
||||
} else {
|
||||
body.addFieldPart(MESSAGE_KEY_RETRY, new StringContentProvider(String.valueOf(retry)), null);
|
||||
}
|
||||
|
||||
if (0 < expire && expire <= MAX_EXPIRE_SECONDS) {
|
||||
body.addFieldPart(MESSAGE_KEY_EXPIRE, new StringContentProvider(String.valueOf(expire)), null);
|
||||
} else {
|
||||
logger.warn("Expire value of {} is invalid. Using default value of {}.", expire,
|
||||
MAX_EXPIRE_SECONDS);
|
||||
body.addFieldPart(MESSAGE_KEY_EXPIRE,
|
||||
new StringContentProvider(String.valueOf(MAX_EXPIRE_SECONDS)), null);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.warn("Invalid 'priority', skipping. Expected: {}. Got: {}.",
|
||||
VALID_PRIORITY_LIST.stream().map(i -> i.toString()).collect(Collectors.joining(",")), priority);
|
||||
}
|
||||
}
|
||||
|
||||
if (url != null) {
|
||||
if (url.length() > MAX_URL_LENGTH) {
|
||||
throw new IllegalArgumentException(String
|
||||
.format("Skip sending the message as 'url' is longer than %d characters.", MAX_URL_LENGTH));
|
||||
}
|
||||
body.addFieldPart(MESSAGE_KEY_URL, new StringContentProvider(url), null);
|
||||
|
||||
if (urlTitle != null) {
|
||||
if (urlTitle.length() > MAX_URL_TITLE_LENGTH) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Skip sending the message as 'urlTitle' is longer than %d characters.",
|
||||
MAX_URL_TITLE_LENGTH));
|
||||
}
|
||||
body.addFieldPart(MESSAGE_KEY_URL_TITLE, new StringContentProvider(urlTitle), null);
|
||||
}
|
||||
}
|
||||
|
||||
if (sound != null) {
|
||||
body.addFieldPart(MESSAGE_KEY_SOUND, new StringContentProvider(sound), null);
|
||||
}
|
||||
|
||||
if (attachment != null) {
|
||||
File file = new File(attachment);
|
||||
if (!file.exists()) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Skip sending the message as file '%s' does not exist.", attachment));
|
||||
}
|
||||
try {
|
||||
body.addFilePart(MESSAGE_KEY_ATTACHMENT, file.getName(),
|
||||
new PathContentProvider(contentType, file.toPath()), null);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException(String.format("Skip sending the message: %s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
if (html) {
|
||||
body.addFieldPart(MESSAGE_KEY_HTML, new StringContentProvider("1"), null);
|
||||
} else if (monospace) {
|
||||
body.addFieldPart(MESSAGE_KEY_MONOSPACE, new StringContentProvider("1"), null);
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.config.core.ParameterOption;
|
||||
|
||||
/**
|
||||
* The {@link Sound} is the Java class used to map the JSON response to an Pushover API request..
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Sound {
|
||||
public String sound;
|
||||
public String label;
|
||||
|
||||
public Sound(String sound, String label) {
|
||||
this.sound = sound;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public ParameterOption getAsParameterOption() {
|
||||
return new ParameterOption(sound, label);
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal.factory;
|
||||
|
||||
import static org.openhab.binding.pushover.internal.PushoverBindingConstants.PUSHOVER_ACCOUNT;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.pushover.internal.handler.PushoverAccountHandler;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link PushoverHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@Component(configurationPid = "binding.pushover", service = ThingHandlerFactory.class)
|
||||
@NonNullByDefault
|
||||
public class PushoverHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(PUSHOVER_ACCOUNT);
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
@Activate
|
||||
public PushoverHandlerFactory(final @Reference HttpClientFactory httpClientFactory) {
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
final ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (PUSHOVER_ACCOUNT.equals(thingTypeUID)) {
|
||||
return new PushoverAccountHandler(thing, httpClient);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal.handler;
|
||||
|
||||
import static org.openhab.binding.pushover.internal.PushoverBindingConstants.DEFAULT_SOUND;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.pushover.internal.actions.PushoverActions;
|
||||
import org.openhab.binding.pushover.internal.config.PushoverAccountConfiguration;
|
||||
import org.openhab.binding.pushover.internal.config.PushoverConfigOptionProvider;
|
||||
import org.openhab.binding.pushover.internal.connection.PushoverAPIConnection;
|
||||
import org.openhab.binding.pushover.internal.connection.PushoverCommunicationException;
|
||||
import org.openhab.binding.pushover.internal.connection.PushoverConfigurationException;
|
||||
import org.openhab.binding.pushover.internal.connection.PushoverMessageBuilder;
|
||||
import org.openhab.binding.pushover.internal.dto.Sound;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* The {@link PushoverAccountHandler} is responsible for handling commands, which are sent to one of the channels.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushoverAccountHandler extends BaseThingHandler {
|
||||
|
||||
private static final Collection<Class<? extends ThingHandlerService>> SUPPORTED_THING_ACTIONS = Set
|
||||
.of(PushoverActions.class, PushoverConfigOptionProvider.class);
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
private @NonNullByDefault({}) PushoverAccountConfiguration config;
|
||||
private @Nullable PushoverAPIConnection connection;
|
||||
|
||||
public PushoverAccountHandler(Thing thing, HttpClient httpClient) {
|
||||
super(thing);
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
config = getConfigAs(PushoverAccountConfiguration.class);
|
||||
|
||||
boolean configValid = true;
|
||||
final String apikey = config.apikey;
|
||||
if (apikey == null || apikey.isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-missing-apikey");
|
||||
configValid = false;
|
||||
}
|
||||
final String user = config.user;
|
||||
if (user == null || user.isEmpty()) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-missing-user");
|
||||
configValid = false;
|
||||
}
|
||||
|
||||
if (configValid) {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
connection = new PushoverAPIConnection(httpClient, config);
|
||||
scheduler.submit(this::asyncValidateUser);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return SUPPORTED_THING_ACTIONS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of current sounds and their descriptions from the Pushover API.
|
||||
*
|
||||
* @return a list of {@link Sound}s
|
||||
*/
|
||||
public List<Sound> getSounds() {
|
||||
return connection != null ? connection.getSounds() : List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a preconfigured {@link PushoverMessageBuilder}.
|
||||
*
|
||||
* @param message the message
|
||||
* @return a {@link PushoverMessageBuilder} instance
|
||||
*/
|
||||
public PushoverMessageBuilder getDefaultPushoverMessageBuilder(String message) {
|
||||
PushoverMessageBuilder builder = PushoverMessageBuilder.getInstance(config.apikey, config.user)
|
||||
.withMessage(message) //
|
||||
.withTitle(config.title) //
|
||||
.withRetry(config.retry) //
|
||||
.withExpire(config.expire);
|
||||
// specify format if defined
|
||||
switch (config.format) {
|
||||
case PushoverMessageBuilder.MESSAGE_KEY_HTML:
|
||||
builder.withHtmlFormatting();
|
||||
break;
|
||||
case PushoverMessageBuilder.MESSAGE_KEY_MONOSPACE:
|
||||
builder.withMonospaceFormatting();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// add sound if defined
|
||||
if (!DEFAULT_SOUND.equals(config.sound)) {
|
||||
builder.withSound(config.sound);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
public boolean sendMessage(PushoverMessageBuilder messageBuilder) {
|
||||
if (connection != null) {
|
||||
return connection.sendMessage(messageBuilder);
|
||||
} else {
|
||||
throw new IllegalArgumentException("PushoverAPIConnection is null!");
|
||||
}
|
||||
}
|
||||
|
||||
public String sendPriorityMessage(PushoverMessageBuilder messageBuilder) {
|
||||
if (connection != null) {
|
||||
return connection.sendPriorityMessage(messageBuilder);
|
||||
} else {
|
||||
throw new IllegalArgumentException("PushoverAPIConnection is null!");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean cancelPriorityMessage(String receipt) {
|
||||
if (connection != null) {
|
||||
return connection.cancelPriorityMessage(receipt);
|
||||
} else {
|
||||
throw new IllegalArgumentException("PushoverAPIConnection is null!");
|
||||
}
|
||||
}
|
||||
|
||||
private void asyncValidateUser() {
|
||||
try {
|
||||
connection.validateUser();
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} catch (PushoverCommunicationException | PushoverConfigurationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="pushover" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>Pushover Binding</name>
|
||||
<description>Pushover - Simple Notifications.</description>
|
||||
|
||||
</binding:binding>
|
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<config-description uri="thing-type:pushover:pushover-account">
|
||||
<parameter name="apikey" type="text" required="true">
|
||||
<context>password</context>
|
||||
<label>API Token / Key</label>
|
||||
<description>Your API token / key (APP_TOKEN) to access the Pushover Message API.</description>
|
||||
</parameter>
|
||||
<parameter name="user" type="text" required="true">
|
||||
<context>password</context>
|
||||
<label>User / Group Key</label>
|
||||
<description>Your user key or group key (USER_KEY) to which you want to push notifications.</description>
|
||||
</parameter>
|
||||
<parameter name="title" type="text">
|
||||
<label>Title</label>
|
||||
<description>The default title of a message.</description>
|
||||
<default>openHAB</default>
|
||||
</parameter>
|
||||
<parameter name="format" type="text">
|
||||
<label>Format</label>
|
||||
<description>The default format of a message.</description>
|
||||
<default>none</default>
|
||||
<options>
|
||||
<option value="none">None</option>
|
||||
<option value="html">HTML</option>
|
||||
<option value="monospace">monospace</option>
|
||||
</options>
|
||||
</parameter>
|
||||
<parameter name="sound" type="text">
|
||||
<label>Notification Sound</label>
|
||||
<description>The default notification sound on target device.</description>
|
||||
<default>default</default>
|
||||
</parameter>
|
||||
<parameter name="retry" type="integer" min="30" unit="s">
|
||||
<advanced>true</advanced>
|
||||
<label>Retry</label>
|
||||
<description>The retry parameter specifies how often the Pushover servers will send the same notification to the
|
||||
user.</description>
|
||||
<default>300</default>
|
||||
</parameter>
|
||||
<parameter name="expire" type="integer" min="0" max="10800" unit="s">
|
||||
<advanced>true</advanced>
|
||||
<label>Expire</label>
|
||||
<description>The expire parameter specifies how long your notification will continue to be retried.</description>
|
||||
<default>3600</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</config-description:config-descriptions>
|
@ -0,0 +1,52 @@
|
||||
# user defined messages
|
||||
offline.conf-error-missing-apikey = The 'apikey' parameter must be configured.
|
||||
offline.conf-error-missing-user = The 'user' parameter must be configured.
|
||||
|
||||
# actions
|
||||
sendMessageActionLabel = send a plain text message
|
||||
sendMessageActionDescription = This method is used to send a plain text message.
|
||||
sendMessageActionOutputLabel = Sent
|
||||
sendMessageActionOutputDescription = true, if message has been sent successfully
|
||||
sendMessageActionInputMessageLabel = Message
|
||||
sendMessageActionInputMessageDescription = Message to be sent.
|
||||
sendMessageActionInputTitleLabel = Title
|
||||
sendMessageActionInputTitleDescription = The title of the message.
|
||||
|
||||
sendURLMessageActionLabel = send a plain text message with an URL
|
||||
sendURLMessageActionDescription = This method is used to send a message with an URL.
|
||||
sendMessageActionInputURLLabel = URL
|
||||
sendMessageActionInputURLDescription = A supplementary URL to show with the message.
|
||||
sendMessageActionInputURLTitleLabel = URL Title
|
||||
sendMessageActionInputURLTitleDescription = A title for the URL, otherwise just the URL is shown.
|
||||
|
||||
sendHTMLMessageActionLabel = send a HTML message
|
||||
sendHTMLMessageActionDescription = This method is used to send a HTML message.
|
||||
|
||||
sendMonospaceMessageActionLabel = send a monospace message
|
||||
sendMonospaceMessageActionDescription = This method is used to send a monospace message.
|
||||
|
||||
sendAttachmentMessageActionLabel = send a plain text message with an attachment
|
||||
sendAttachmentMessageActionDescription = This method is used to send a message with an attachment.
|
||||
sendMessageActionInputAttachmentLabel = Attachment
|
||||
sendMessageActionInputAttachmentDescription = A (local) path to the attachment.
|
||||
sendMessageActionInputContentTypeLabel = Content Type
|
||||
sendMessageActionInputContentTypeDescription = The content type of the attachment. Defaults to "image/jpeg".
|
||||
|
||||
sendPriorityMessageActionLabel = send a priority message
|
||||
sendPriorityMessageActionDescription = This method is used to send a priority message.
|
||||
sendPriorityMessageActionOutputLabel = Receipt
|
||||
sendPriorityMessageActionOutputDescription = Receipt, if priority message sent successfully.
|
||||
sendMessageActionInputPriorityLabel = Priority
|
||||
sendMessageActionInputPriorityDescription = Priority to be used. Defaults to 2.
|
||||
|
||||
cancelPriorityMessageActionLabel = cancel a priority message
|
||||
cancelPriorityMessageActionDescription = This method is used to cancel a priority message.
|
||||
cancelPriorityMessageActionOnputLabel = Cancelled
|
||||
cancelPriorityMessageActionOnputDescription = true, if message has been cancelled successfully.
|
||||
cancelPriorityMessageActionInputReceiptLabel = Receipt
|
||||
cancelPriorityMessageActionInputReceiptDescription = Receipt of the message to be canceled.
|
||||
|
||||
sendMessageToDeviceActionLabel = send a plain text message to a specific device
|
||||
sendMessageToDeviceActionDescription = This method is used to send a message to a specific device.
|
||||
sendMessageActionInputDeviceLabel = Device
|
||||
sendMessageActionInputDeviceDescription = The name of a specific device (multiple devices may be separated by a comma).
|
@ -0,0 +1,75 @@
|
||||
# binding
|
||||
binding.pushover.description = Pushover - Einfache Benachrichtigungen.
|
||||
|
||||
# thing types
|
||||
thing-type.pushover.pushover-account.label = Pushover Konto
|
||||
thing-type.pushover.pushover-account.description = Ermöglicht den Zugriff auf die Pushover Message API.
|
||||
|
||||
# thing type config description
|
||||
thing-type.config.pushover.pushover-account.apikey.label = API Token / Key
|
||||
thing-type.config.pushover.pushover-account.apikey.description = API Token / Schlüssel für den Zugriff auf die Pushover Message API.
|
||||
thing-type.config.pushover.pushover-account.user.label = User / Group Key
|
||||
thing-type.config.pushover.pushover-account.user.description = User / Group Key (USER_KEY) an den / die Nachrichten gesendet werden sollen.
|
||||
thing-type.config.pushover.pushover-account.title.label = Titel
|
||||
thing-type.config.pushover.pushover-account.title.description = Standardtitel der Nachricht.
|
||||
thing-type.config.pushover.pushover-account.format.label = Format
|
||||
thing-type.config.pushover.pushover-account.format.description = Standardformat der Nachricht.
|
||||
thing-type.config.pushover.pushover-account.sound.label = Benachrichtigungston
|
||||
thing-type.config.pushover.pushover-account.sound.description = Standardbenachrichtigungston auf dem Endgerät.
|
||||
thing-type.config.pushover.pushover-account.retry.label = Wiederholungen
|
||||
thing-type.config.pushover.pushover-account.retry.description = Dieser Parameter gibt an, in welchen Abständen eine Prioritätsnachricht wiederholt an den Benutzer gesendet werden soll.
|
||||
thing-type.config.pushover.pushover-account.expire.label = Verfall
|
||||
thing-type.config.pushover.pushover-account.expire.description = Dieser Parameter gibt an, wie lange eine Prioritätsnachricht wiederholt wird.
|
||||
|
||||
# user defined messages
|
||||
offline.conf-error-missing-apikey = Der Parameter 'apikey' muss konfiguriert werden.
|
||||
offline.conf-error-missing-user = Der Parameter 'user' muss konfiguriert werden.
|
||||
|
||||
# actions
|
||||
sendMessageActionLabel = eine Textnachricht senden
|
||||
sendMessageActionDescription = Action zum Versenden einer Textnachricht.
|
||||
sendMessageActionOutputLabel = Gesendet
|
||||
sendMessageActionOutputDescription = true, wenn die Nachricht erfolgreich versendet wurde.
|
||||
sendMessageActionInputMessageLabel = Nachricht
|
||||
sendMessageActionInputMessageDescription = Die Nachricht.
|
||||
sendMessageActionInputTitleLabel = Titel
|
||||
sendMessageActionInputTitleDescription = Titel der Nachricht.
|
||||
|
||||
sendURLMessageActionLabel = eine Textnachricht mit URL senden
|
||||
sendURLMessageActionDescription = Action zum Versenden einer Textnachricht mit einer URL.
|
||||
sendMessageActionInputURLLabel = URL
|
||||
sendMessageActionInputURLDescription = Eine zusätzliche URL, die mit der Nachricht angezeigt werden soll.
|
||||
sendMessageActionInputURLTitleLabel = URL Title
|
||||
sendMessageActionInputURLTitleDescription = Ein Titel für die URL, andernfalls wird nur die URL angezeigt.
|
||||
|
||||
sendHTMLMessageActionLabel = eine HTML-Nachricht senden
|
||||
sendHTMLMessageActionDescription = Action zum Versenden einer HTML-Nachricht.
|
||||
|
||||
sendMonospaceMessageActionLabel = eine monospace-Nachricht senden
|
||||
sendMonospaceMessageActionDescription = Action zum Versenden einer monospace-Nachricht.
|
||||
|
||||
sendAttachmentMessageActionLabel = eine Textnachricht mit Anhang senden
|
||||
sendAttachmentMessageActionDescription = Action zum Versenden einer Textnachricht mit Anhang.
|
||||
sendMessageActionInputAttachmentLabel = Anhang
|
||||
sendMessageActionInputAttachmentDescription = Lokaler Pfad zum Anhang.
|
||||
sendMessageActionInputContentTypeLabel = Content-Type
|
||||
sendMessageActionInputContentTypeDescription = Der Content-Type für den Anhang. Default: "image/jpeg".
|
||||
|
||||
sendPriorityMessageActionLabel = eine Prioritätsnachricht senden
|
||||
sendPriorityMessageActionDescription = Action zum Versenden einer Prioritätsnachricht.
|
||||
sendPriorityMessageActionOutputLabel = Receipt
|
||||
sendPriorityMessageActionOutputDescription = ID der Prioritätsnachricht, wenn diese erfolgreich versendet wurde.
|
||||
sendMessageActionInputPriorityLabel = Priorität
|
||||
sendMessageActionInputPriorityDescription = Die Priorität. Default: 2.
|
||||
|
||||
cancelPriorityMessageActionLabel = eine Prioritätsnachricht annullieren
|
||||
cancelPriorityMessageActionDescription = Action zum Annullieren einer Prioritätsnachricht.
|
||||
cancelPriorityMessageActionOnputLabel = Annulliert
|
||||
cancelPriorityMessageActionOnputDescription = true, wenn die Prioritätsnachricht erfolgreich annulliert wurde.
|
||||
cancelPriorityMessageActionInputReceiptLabel = Receipt
|
||||
cancelPriorityMessageActionInputReceiptDescription = Die ID der Prioritätsnachricht.
|
||||
|
||||
sendMessageToDeviceActionLabel = eine Nachricht an ein Endgerät
|
||||
sendMessageToDeviceActionDescription = Action zum Versenden einer Nachricht an ein Endgerät.
|
||||
sendMessageActionInputDeviceLabel = Endgerät
|
||||
sendMessageActionInputDeviceDescription = Der Name des Endgeräts (mehrere Geräte können durch ein Komma getrennt werden).
|
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="pushover"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<thing-type id="pushover-account">
|
||||
<label>Pushover Account</label>
|
||||
<description>Provides access to the Pushover Messages API.</description>
|
||||
|
||||
<representation-property>apikey</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:pushover:pushover-account"/>
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,190 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.pushover.internal.actions;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
import org.mockito.junit.jupiter.MockitoSettings;
|
||||
import org.mockito.quality.Strictness;
|
||||
import org.openhab.binding.pushover.internal.connection.PushoverMessageBuilder;
|
||||
import org.openhab.binding.pushover.internal.handler.PushoverAccountHandler;
|
||||
import org.openhab.core.thing.binding.ThingActions;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PushoverActions}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
public class PushoverActionsTest {
|
||||
|
||||
private static final String MESSAGE = "My Message";
|
||||
private static final String TITLE = "My Title";
|
||||
private static final String URL = "https://www.test.com";
|
||||
private static final String URL_TITLE = "Some Link";
|
||||
private static final String RECEIPT = "12345";
|
||||
|
||||
@NonNullByDefault
|
||||
private final ThingActions thingActionsStub = new ThingActions() {
|
||||
@Override
|
||||
public void setThingHandler(ThingHandler handler) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private @Mock PushoverAccountHandler mockPushoverAccountHandler;
|
||||
|
||||
private PushoverActions pushoverThingActions;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
pushoverThingActions = new PushoverActions();
|
||||
|
||||
when(mockPushoverAccountHandler.getDefaultPushoverMessageBuilder(any()))
|
||||
.thenReturn(PushoverMessageBuilder.getInstance("key", "user"));
|
||||
when(mockPushoverAccountHandler.sendMessage(any())).thenReturn(Boolean.TRUE);
|
||||
when(mockPushoverAccountHandler.sendPriorityMessage(any())).thenReturn(RECEIPT);
|
||||
when(mockPushoverAccountHandler.cancelPriorityMessage(RECEIPT)).thenReturn(Boolean.TRUE);
|
||||
}
|
||||
|
||||
// sendMessage
|
||||
@Test
|
||||
public void testSendMessageThingActionsIsNotPushoverThingActions() {
|
||||
assertThrows(ClassCastException.class, () -> PushoverActions.sendMessage(thingActionsStub, MESSAGE, TITLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMessageThingHandlerIsNull() {
|
||||
assertThrows(RuntimeException.class, () -> PushoverActions.sendMessage(pushoverThingActions, MESSAGE, TITLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMessageWithoutTitle() {
|
||||
pushoverThingActions.setThingHandler(mockPushoverAccountHandler);
|
||||
boolean sent = PushoverActions.sendMessage(pushoverThingActions, MESSAGE, null);
|
||||
assertThat(sent, is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMessage() {
|
||||
pushoverThingActions.setThingHandler(mockPushoverAccountHandler);
|
||||
boolean sent = PushoverActions.sendMessage(pushoverThingActions, MESSAGE, TITLE);
|
||||
assertThat(sent, is(true));
|
||||
}
|
||||
|
||||
// sendURLMessage
|
||||
@Test
|
||||
public void testSendURLMessageThingActionsIsNotPushoverThingActions() {
|
||||
assertThrows(ClassCastException.class,
|
||||
() -> PushoverActions.sendURLMessage(thingActionsStub, MESSAGE, TITLE, URL, URL_TITLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendURLMessageThingHandlerIsNull() {
|
||||
assertThrows(RuntimeException.class,
|
||||
() -> PushoverActions.sendURLMessage(pushoverThingActions, MESSAGE, TITLE, URL, URL_TITLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendURLMessageWithoutTitle() {
|
||||
pushoverThingActions.setThingHandler(mockPushoverAccountHandler);
|
||||
boolean sent = PushoverActions.sendURLMessage(pushoverThingActions, MESSAGE, null, URL, URL_TITLE);
|
||||
assertThat(sent, is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendURLMessageWithoutURLTitle() {
|
||||
pushoverThingActions.setThingHandler(mockPushoverAccountHandler);
|
||||
boolean sent = PushoverActions.sendURLMessage(pushoverThingActions, MESSAGE, TITLE, URL, null);
|
||||
assertThat(sent, is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendURLMessage() {
|
||||
pushoverThingActions.setThingHandler(mockPushoverAccountHandler);
|
||||
boolean sent = PushoverActions.sendURLMessage(pushoverThingActions, MESSAGE, TITLE, URL, URL_TITLE);
|
||||
assertThat(sent, is(true));
|
||||
}
|
||||
|
||||
// sendPriorityMessage
|
||||
@Test
|
||||
public void testSendPriorityMessageThingActionsIsNotPushoverThingActions() {
|
||||
assertThrows(ClassCastException.class, () -> PushoverActions.sendPriorityMessage(thingActionsStub, MESSAGE,
|
||||
TITLE, PushoverMessageBuilder.EMERGENCY_PRIORITY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendPriorityMessageThingHandlerIsNull() {
|
||||
assertThrows(RuntimeException.class, () -> PushoverActions.sendPriorityMessage(pushoverThingActions, MESSAGE,
|
||||
TITLE, PushoverMessageBuilder.EMERGENCY_PRIORITY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendPriorityMessageWithoutTitle() {
|
||||
pushoverThingActions.setThingHandler(mockPushoverAccountHandler);
|
||||
String receipt = PushoverActions.sendPriorityMessage(pushoverThingActions, MESSAGE, null,
|
||||
PushoverMessageBuilder.EMERGENCY_PRIORITY);
|
||||
assertThat(receipt, is(RECEIPT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendPriorityMessage() {
|
||||
pushoverThingActions.setThingHandler(mockPushoverAccountHandler);
|
||||
String receipt = PushoverActions.sendPriorityMessage(pushoverThingActions, MESSAGE, TITLE,
|
||||
PushoverMessageBuilder.EMERGENCY_PRIORITY);
|
||||
assertThat(receipt, is(RECEIPT));
|
||||
}
|
||||
|
||||
// cancelPriorityMessage
|
||||
@Test
|
||||
public void testCancelPriorityMessageThingActionsIsNotPushoverThingActions() {
|
||||
assertThrows(ClassCastException.class, () -> PushoverActions.cancelPriorityMessage(thingActionsStub, RECEIPT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelPriorityMessageThingHandlerIsNull() {
|
||||
assertThrows(RuntimeException.class,
|
||||
() -> PushoverActions.cancelPriorityMessage(pushoverThingActions, RECEIPT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelPriorityMessageWithValidReceipt() {
|
||||
pushoverThingActions.setThingHandler(mockPushoverAccountHandler);
|
||||
boolean cancelled = PushoverActions.cancelPriorityMessage(pushoverThingActions, RECEIPT);
|
||||
assertThat(cancelled, is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelPriorityMessageWithInvalidReceipt() {
|
||||
pushoverThingActions.setThingHandler(mockPushoverAccountHandler);
|
||||
boolean cancelled = PushoverActions.cancelPriorityMessage(pushoverThingActions, "invalid");
|
||||
assertThat(cancelled, is(false));
|
||||
}
|
||||
}
|
@ -233,6 +233,7 @@
|
||||
<module>org.openhab.binding.powermax</module>
|
||||
<module>org.openhab.binding.pulseaudio</module>
|
||||
<module>org.openhab.binding.pushbullet</module>
|
||||
<module>org.openhab.binding.pushover</module>
|
||||
<module>org.openhab.binding.radiothermostat</module>
|
||||
<module>org.openhab.binding.regoheatpump</module>
|
||||
<module>org.openhab.binding.revogi</module>
|
||||
|
Loading…
Reference in New Issue
Block a user