mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 07:02:02 +01:00
[pushsafer] Initial Contribution of Pushsafer Binding (#10790)
* Pushsafer binding Signed-off-by: Pushsafer.com (Kevin Siml) <info@appzer.de> * Improvements and comments from code review Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de> * Incorporated comments from review Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de> Co-authored-by: Pushsafer.com (Kevin Siml) <info@appzer.de>
This commit is contained in:
parent
6fc24e4aa4
commit
fc9864f434
@ -237,6 +237,7 @@
|
||||
/bundles/org.openhab.binding.pulseaudio/ @peuter
|
||||
/bundles/org.openhab.binding.pushbullet/ @hakan42
|
||||
/bundles/org.openhab.binding.pushover/ @cweitkamp
|
||||
/bundles/org.openhab.binding.pushsafer/ @appzer @cweitkamp
|
||||
/bundles/org.openhab.binding.qbus/ @QbusKoen
|
||||
/bundles/org.openhab.binding.radiothermostat/ @mlobstein
|
||||
/bundles/org.openhab.binding.regoheatpump/ @crnjan
|
||||
|
@ -1166,6 +1166,11 @@
|
||||
<artifactId>org.openhab.binding.pushover</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.pushsafer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.radiothermostat</artifactId>
|
||||
|
13
bundles/org.openhab.binding.pushsafer/NOTICE
Normal file
13
bundles/org.openhab.binding.pushsafer/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
|
54
bundles/org.openhab.binding.pushsafer/README.md
Normal file
54
bundles/org.openhab.binding.pushsafer/README.md
Normal file
@ -0,0 +1,54 @@
|
||||
# Pushsafer Binding
|
||||
|
||||
The Pushsafer binding allows you to notify mobile devices of a message using the [Pushsafer API](https://www.pushsafer.com/pushapi).
|
||||
To get started you first need to register (a free process) to get a Private Key.
|
||||
Initially you have to register a device with one of the [client apps](https://www.pushsafer.com/apps), to get a device id.
|
||||
|
||||
## Supported Things
|
||||
|
||||
There is only one Thing available - the `pushsafer-account`.
|
||||
You are able to create multiple instances of this Thing to broadcast to different devices or groups with push-notification content and setting.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
| Configuration Parameter | Type | Description |
|
||||
|-------------------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `apikey` | text | Your private-key to access the Pushsafer [Message API](https://www.pushsafer.com/pushapi). **mandatory** |
|
||||
| `user` | text | Your username or email address to validate against the Pushsafer Message API. **mandatory** |
|
||||
| `device` | text | Your device or group id to which device(s) 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: `1`) (see [supported notification sounds](https://www.pushsafer.com/pushapi#api-sound)). |
|
||||
| `vibration` | text | How often the device should vibrate. empty=device default or a number 1-3. |
|
||||
| `icon` | text | The default notification icon on target device (default: `1`) (see [supported notification icons](https://www.pushsafer.com/pushapi#api-icon)). |
|
||||
| `color` | text | The color (hexadecimal) of notification icon (e.g. #FF0000). |
|
||||
| `url` | text | URL or [URL Scheme](https://www.pushsafer.com/url_schemes) send with notification. |
|
||||
| `urlTitle` | text | Title of URL. |
|
||||
| `retry` | integer | The retry parameter specifies how often (in seconds) the Pushsafer 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** |
|
||||
| `confirm` | integer | Integer 10-10800 (10s steps) Time in seconds after which a message should be sent again before it is confirmed. (default: `0`). **advanced** |
|
||||
| `time2live` | integer | Time in minutes, after a message automatically gets purged (default: `0`). **advanced** |
|
||||
| `answer` | integer | 1 = enables reply to push notifications (default: `0`). **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 was sent successfully or not.
|
||||
The parameter `message` is **mandatory**, the `title` parameter defaults to whatever value you defined in the `title` related configuration parameter.
|
||||
|
||||
- `sendPushsaferMessage(String message, @Nullable String title)` - This method is used to send a plain text message.
|
||||
|
||||
- `sendPushsaferHtmlMessage(String message, @Nullable String title)` - This method is used to send a HTML message.
|
||||
|
||||
- `sendPushsaferMonospaceMessage(String message, @Nullable String title)` - This method is used to send a monospace message.
|
||||
|
||||
- `sendPushsaferAttachmentMessage(String message, @Nullable String title, String attachment, @Nullable String contentType, @Nullable String authentication)` - This method is used to send a message with an image attachment. It takes a local path or url to the image attachment (parameter `attachment` **mandatory**), an optional `contentType` to define the content-type of the attachment (default: `"jpeg"`, possible values: `"jpeg"`, `"png"`, `"gif"`) and an optional `authentication` for the given URL to define the authentication if needed (default: `""`, example: `"user:password"`).
|
||||
|
||||
- `sendPushsaferURLMessage(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.
|
||||
|
||||
- `sendPushsaferPriorityMessage(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`).
|
17
bundles/org.openhab.binding.pushsafer/pom.xml
Normal file
17
bundles/org.openhab.binding.pushsafer/pom.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
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.2.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.pushsafer</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Pushsafer Binding</name>
|
||||
|
||||
</project>
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.pushsafer-${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-pushsafer" description="Pushsafer Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.pushsafer/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link PushsaferBindingConstants} class defines common constants, which are used across the whole binding.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushsaferBindingConstants {
|
||||
|
||||
private static final String BINDING_ID = "pushsafer";
|
||||
|
||||
public static final ThingTypeUID PUSHSAFER_ACCOUNT = new ThingTypeUID(BINDING_ID, "pushsafer-account");
|
||||
|
||||
public static final String CONFIG_SOUND = "sound";
|
||||
public static final String CONFIG_ICON = "icon";
|
||||
|
||||
public static final String ALL_DEVICES = "a";
|
||||
public static final String DEFAULT_SOUND = "";
|
||||
public static final String DEFAULT_ICON = "1";
|
||||
public static final String DEFAULT_COLOR = "";
|
||||
public static final String DEFAULT_URL = "";
|
||||
public static final String DEFAULT_URLTITLE = "";
|
||||
public static final String DEFAULT_VIBRATION = "1";
|
||||
public static final int DEFAULT_CONFIRM = 0;
|
||||
public static final boolean DEFAULT_ANSWER = false;
|
||||
public static final int DEFAULT_TIME2LIVE = 0;
|
||||
public static final String DEFAULT_TITLE = "openHAB";
|
||||
}
|
@ -0,0 +1,234 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.internal.actions;
|
||||
|
||||
import static org.openhab.binding.pushsafer.internal.PushsaferBindingConstants.DEFAULT_TITLE;
|
||||
import static org.openhab.binding.pushsafer.internal.connection.PushsaferMessageBuilder.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.pushsafer.internal.connection.PushsaferConfigurationException;
|
||||
import org.openhab.binding.pushsafer.internal.connection.PushsaferMessageBuilder;
|
||||
import org.openhab.binding.pushsafer.internal.handler.PushsaferAccountHandler;
|
||||
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 PushsaferAccountHandler}.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@ThingActionsScope(name = "pushsafer")
|
||||
@NonNullByDefault
|
||||
public class PushsaferActions implements ThingActions {
|
||||
|
||||
private static final String DEFAULT_EMERGENCY_PRIORITY = "2";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(PushsaferActions.class);
|
||||
|
||||
private @NonNullByDefault({}) PushsaferAccountHandler accountHandler;
|
||||
|
||||
@RuleAction(label = "@text/sendPushsaferMessageActionLabel", description = "@text/sendPushsaferMessageActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendPushsaferMessageActionOutputLabel", description = "@text/sendPushsaferMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendPushsaferMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendPushsaferMessageActionInputMessageLabel", description = "@text/sendPushsaferMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendPushsaferMessageActionInputTitleLabel", description = "@text/sendPushsaferMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title) {
|
||||
logger.trace("ThingAction 'sendPushsaferMessage' called with value(s): message='{}', title='{}'", message,
|
||||
title);
|
||||
return send(getDefaultPushsaferMessageBuilder(message), title);
|
||||
}
|
||||
|
||||
public static Boolean sendPushsaferMessage(ThingActions actions, String message, @Nullable String title) {
|
||||
return ((PushsaferActions) actions).sendPushsaferMessage(message, title);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendPushsaferURLMessageActionLabel", description = "@text/sendPushsaferURLMessageActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendPushsaferMessageActionOutputLabel", description = "@text/sendPushsaferMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendPushsaferURLMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendPushsaferMessageActionInputMessageLabel", description = "@text/sendPushsaferMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendPushsaferMessageActionInputTitleLabel", description = "@text/sendPushsaferMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title,
|
||||
@ActionInput(name = "url", label = "@text/sendPushsaferMessageActionInputURLLabel", description = "@text/sendPushsaferMessageActionInputURLDescription", type = "java.lang.String", required = true) String url,
|
||||
@ActionInput(name = "urlTitle", label = "@text/sendPushsaferMessageActionInputURLTitleLabel", description = "@text/sendPushsaferMessageActionInputURLTitleDescription", type = "java.lang.String") @Nullable String urlTitle) {
|
||||
logger.trace(
|
||||
"ThingAction 'sendPushsaferURLMessage' 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.");
|
||||
}
|
||||
|
||||
PushsaferMessageBuilder builder = getDefaultPushsaferMessageBuilder(message).withUrl(url);
|
||||
if (urlTitle != null) {
|
||||
builder.withUrl(urlTitle);
|
||||
}
|
||||
return send(builder, title);
|
||||
}
|
||||
|
||||
public static Boolean sendPushsaferURLMessage(ThingActions actions, String message, @Nullable String title,
|
||||
String url, @Nullable String urlTitle) {
|
||||
return ((PushsaferActions) actions).sendPushsaferURLMessage(message, title, url, urlTitle);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendHTMLMessageActionLabel", description = "@text/sendHTMLMessageActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendPushsaferMessageActionOutputLabel", description = "@text/sendPushsaferMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendPushsaferHtmlMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendPushsaferMessageActionInputMessageLabel", description = "@text/sendPushsaferMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendPushsaferMessageActionInputTitleLabel", description = "@text/sendPushsaferMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title) {
|
||||
logger.trace("ThingAction 'sendPushsaferHtmlMessage' called with value(s): message='{}', title='{}'", message,
|
||||
title);
|
||||
return send(getDefaultPushsaferMessageBuilder(message).withHtmlFormatting(), title);
|
||||
}
|
||||
|
||||
public static Boolean sendPushsaferHtmlMessage(ThingActions actions, String message, @Nullable String title) {
|
||||
return ((PushsaferActions) actions).sendPushsaferHtmlMessage(message, title);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendPushsaferMonospaceMessageActionLabel", description = "@text/sendPushsaferMonospaceMessageActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendPushsaferMessageActionOutputLabel", description = "@text/sendPushsaferMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendPushsaferMonospaceMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendPushsaferMessageActionInputMessageLabel", description = "@text/sendPushsaferMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendPushsaferMessageActionInputTitleLabel", description = "@text/sendPushsaferMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title) {
|
||||
logger.trace("ThingAction 'sendPushsaferMonospaceMessage' called with value(s): message='{}', title='{}'",
|
||||
message, title);
|
||||
return send(getDefaultPushsaferMessageBuilder(message).withMonospaceFormatting(), title);
|
||||
}
|
||||
|
||||
public static Boolean sendPushsaferMonospaceMessage(ThingActions actions, String message, @Nullable String title) {
|
||||
return ((PushsaferActions) actions).sendPushsaferMonospaceMessage(message, title);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendPushsaferAttachmentMessageActionLabel", description = "@text/sendPushsaferAttachmentMessageActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendPushsaferMessageActionOutputLabel", description = "@text/sendPushsaferMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendPushsaferAttachmentMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendPushsaferMessageActionInputMessageLabel", description = "@text/sendPushsaferMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendPushsaferMessageActionInputTitleLabel", description = "@text/sendPushsaferMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title,
|
||||
@ActionInput(name = "attachment", label = "@text/sendPushsaferMessageActionInputAttachmentLabel", description = "@text/sendPushsaferMessageActionInputAttachmentDescription", type = "java.lang.String", required = true) String attachment,
|
||||
@ActionInput(name = "contentType", label = "@text/sendPushsaferMessageActionInputContentTypeLabel", description = "@text/sendPushsaferMessageActionInputContentTypeDescription", type = "java.lang.String", defaultValue = DEFAULT_CONTENT_TYPE) @Nullable String contentType,
|
||||
@ActionInput(name = "authentication", label = "@text/sendPushsaferMessageActionInputAuthenticationLabel", description = "@text/sendPushsaferMessageActionInputAuthenticationDescription", type = "java.lang.String", defaultValue = DEFAULT_AUTH) @Nullable String authentication) {
|
||||
logger.trace(
|
||||
"ThingAction 'sendPushsaferAttachmentMessage' called with value(s): message='{}', title='{}', attachment='{}', contentType='{}', authentication='{}'",
|
||||
message, title, attachment, contentType, authentication);
|
||||
if (attachment == null) {
|
||||
throw new IllegalArgumentException("Skip sending message as 'attachment' is null.");
|
||||
}
|
||||
|
||||
PushsaferMessageBuilder builder = getDefaultPushsaferMessageBuilder(message).withAttachment(attachment);
|
||||
if (contentType != null) {
|
||||
builder.withContentType(contentType);
|
||||
}
|
||||
if (authentication != null) {
|
||||
builder.withAuthentication(authentication);
|
||||
}
|
||||
return send(builder, title);
|
||||
}
|
||||
|
||||
public static Boolean sendPushsaferAttachmentMessage(ThingActions actions, String message, @Nullable String title,
|
||||
String attachment, @Nullable String contentType, @Nullable String authentication) {
|
||||
return ((PushsaferActions) actions).sendPushsaferAttachmentMessage(message, title, attachment, contentType,
|
||||
authentication);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendPushsaferPriorityMessageActionLabel", description = "@text/sendPushsaferPriorityMessageActionDescription")
|
||||
public @ActionOutput(name = "receipt", label = "@text/sendPushsaferPriorityMessageActionOutputLabel", description = "@text/sendPushsaferPriorityMessageActionOutputDescription", type = "java.lang.String") String sendPushsaferPriorityMessage(
|
||||
@ActionInput(name = "message", label = "@text/sendPushsaferMessageActionInputMessageLabel", description = "@text/sendPushsaferMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendPushsaferMessageActionInputTitleLabel", description = "@text/sendPushsaferMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title,
|
||||
@ActionInput(name = "priority", label = "@text/sendPushsaferMessageActionInputPriorityLabel", description = "@text/sendPushsaferMessageActionInputPriorityDescription", type = "java.lang.Integer", defaultValue = DEFAULT_EMERGENCY_PRIORITY) @Nullable Integer priority) {
|
||||
logger.trace(
|
||||
"ThingAction 'sendPushsaferPriorityMessage' called with value(s): message='{}', title='{}', priority='{}'",
|
||||
message, title, priority);
|
||||
PushsaferMessageBuilder builder = getDefaultPushsaferMessageBuilder(message)
|
||||
.withPriority(priority == null ? EMERGENCY_PRIORITY : priority.intValue());
|
||||
|
||||
if (title != null) {
|
||||
builder.withTitle(title);
|
||||
}
|
||||
return accountHandler.sendPushsaferPriorityMessage(builder);
|
||||
}
|
||||
|
||||
public static String sendPushsaferPriorityMessage(ThingActions actions, String message, @Nullable String title,
|
||||
@Nullable Integer priority) {
|
||||
return ((PushsaferActions) actions).sendPushsaferPriorityMessage(message, title, priority);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/cancelPushsaferPriorityMessageActionLabel", description = "@text/cancelPushsaferPriorityMessageActionDescription")
|
||||
public @ActionOutput(name = "canceled", label = "@text/cancelPushsaferPriorityMessageActionOutputLabel", description = "@text/cancelPushsaferPriorityMessageActionOutputDescription", type = "java.lang.Boolean") Boolean cancelPushsaferPriorityMessage(
|
||||
@ActionInput(name = "receipt", label = "@text/cancelPushsaferPriorityMessageActionInputReceiptLabel", description = "@text/cancelPushsaferPriorityMessageActionInputReceiptDescription", type = "java.lang.String", required = true) String receipt) {
|
||||
logger.trace("ThingAction 'cancelPushsaferPriorityMessage' called with value(s): '{}'", receipt);
|
||||
if (accountHandler == null) {
|
||||
throw new RuntimeException("PushsaferAccountHandler is null!");
|
||||
}
|
||||
|
||||
if (receipt == null) {
|
||||
throw new IllegalArgumentException("Skip sending message as 'receipt' is null.");
|
||||
}
|
||||
|
||||
return accountHandler.cancelPushsaferPriorityMessage(receipt);
|
||||
}
|
||||
|
||||
public static Boolean cancelPushsaferPriorityMessage(ThingActions actions, String receipt) {
|
||||
return ((PushsaferActions) actions).cancelPushsaferPriorityMessage(receipt);
|
||||
}
|
||||
|
||||
@RuleAction(label = "@text/sendPushsaferMessageToDeviceActionLabel", description = "@text/sendPushsaferMessageToDeviceActionDescription")
|
||||
public @ActionOutput(name = "sent", label = "@text/sendPushsaferMessageActionOutputLabel", description = "@text/sendPushsaferMessageActionOutputDescription", type = "java.lang.Boolean") Boolean sendPushsaferMessageToDevice(
|
||||
@ActionInput(name = "device", label = "@text/sendPushsaferMessageActionInputDeviceLabel", description = "@text/sendPushsaferMessageActionInputDeviceDescription", type = "java.lang.String", required = true) String device,
|
||||
@ActionInput(name = "message", label = "@text/sendPushsaferMessageActionInputMessageLabel", description = "@text/sendPushsaferMessageActionInputMessageDescription", type = "java.lang.String", required = true) String message,
|
||||
@ActionInput(name = "title", label = "@text/sendPushsaferMessageActionInputTitleLabel", description = "@text/sendPushsaferMessageActionInputTitleDescription", type = "java.lang.String", defaultValue = DEFAULT_TITLE) @Nullable String title) {
|
||||
logger.trace(
|
||||
"ThingAction 'sendPushsaferMessageToDevice' 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(getDefaultPushsaferMessageBuilder(message).withDevice(device), title);
|
||||
}
|
||||
|
||||
public static Boolean sendPushsaferMessageToDevice(ThingActions actions, String device, String message,
|
||||
@Nullable String title) {
|
||||
return ((PushsaferActions) actions).sendPushsaferMessageToDevice(device, message, title);
|
||||
}
|
||||
|
||||
private PushsaferMessageBuilder getDefaultPushsaferMessageBuilder(String message) {
|
||||
if (accountHandler == null) {
|
||||
throw new RuntimeException("PushsaferAccountHandler is null!");
|
||||
}
|
||||
|
||||
if (message == null) {
|
||||
throw new IllegalArgumentException("Skip sending message as 'message' is null.");
|
||||
}
|
||||
|
||||
try {
|
||||
return accountHandler.getDefaultPushsaferMessageBuilder(message);
|
||||
} catch (PushsaferConfigurationException e) {
|
||||
throw new IllegalArgumentException(e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean send(PushsaferMessageBuilder builder, @Nullable String title) {
|
||||
if (title != null) {
|
||||
builder.withTitle(title);
|
||||
}
|
||||
return accountHandler.sendPushsaferMessage(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
this.accountHandler = (PushsaferAccountHandler) handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return accountHandler;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.internal.config;
|
||||
|
||||
import static org.openhab.binding.pushsafer.internal.PushsaferBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link PushsaferAccountConfiguration} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushsaferAccountConfiguration {
|
||||
public @Nullable String apikey;
|
||||
public @Nullable String user;
|
||||
public String device = ALL_DEVICES;
|
||||
public String title = DEFAULT_TITLE;
|
||||
public String format = "none";
|
||||
public String sound = DEFAULT_SOUND;
|
||||
public String icon = DEFAULT_ICON;
|
||||
public String color = DEFAULT_COLOR;
|
||||
public String url = DEFAULT_URL;
|
||||
public String urlTitle = DEFAULT_URLTITLE;
|
||||
public boolean answer = DEFAULT_ANSWER;
|
||||
public int confirm = DEFAULT_CONFIRM;
|
||||
public int time2live = DEFAULT_TIME2LIVE;
|
||||
public String vibration = DEFAULT_VIBRATION;
|
||||
public int retry = 300;
|
||||
public int expire = 3600;
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.internal.config;
|
||||
|
||||
import static org.openhab.binding.pushsafer.internal.PushsaferBindingConstants.*;
|
||||
|
||||
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.pushsafer.internal.dto.Icon;
|
||||
import org.openhab.binding.pushsafer.internal.dto.Sound;
|
||||
import org.openhab.binding.pushsafer.internal.handler.PushsaferAccountHandler;
|
||||
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 PushsaferConfigOptionProvider} class contains fields mapping thing configuration parameters.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@Component(service = ConfigOptionProvider.class)
|
||||
@NonNullByDefault
|
||||
public class PushsaferConfigOptionProvider implements ConfigOptionProvider, ThingHandlerService {
|
||||
|
||||
private @Nullable PushsaferAccountHandler accountHandler;
|
||||
|
||||
@Override
|
||||
public @Nullable Collection<ParameterOption> getParameterOptions(URI uri, String param, @Nullable String context,
|
||||
@Nullable Locale locale) {
|
||||
PushsaferAccountHandler localAccountHandler = accountHandler;
|
||||
if (localAccountHandler != null) {
|
||||
if (PUSHSAFER_ACCOUNT.getAsString().equals(uri.getSchemeSpecificPart()) && CONFIG_SOUND.equals(param)) {
|
||||
List<Sound> sounds = localAccountHandler.getSounds();
|
||||
if (!sounds.isEmpty()) {
|
||||
return sounds.stream().map(Sound::getAsParameterOption)
|
||||
.sorted(Comparator.comparing(ParameterOption::getLabel))
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
}
|
||||
if (PUSHSAFER_ACCOUNT.getAsString().equals(uri.getSchemeSpecificPart()) && CONFIG_ICON.equals(param)) {
|
||||
List<Icon> icons = localAccountHandler.getIcons();
|
||||
if (!icons.isEmpty()) {
|
||||
return icons.stream().map(Icon::getAsParameterOption)
|
||||
.sorted(Comparator.comparing(ParameterOption::getLabel))
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
this.accountHandler = (PushsaferAccountHandler) handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return accountHandler;
|
||||
}
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.internal.connection;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
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.pushsafer.internal.config.PushsaferAccountConfiguration;
|
||||
import org.openhab.binding.pushsafer.internal.dto.Icon;
|
||||
import org.openhab.binding.pushsafer.internal.dto.Sound;
|
||||
import org.openhab.core.cache.ExpiringCacheMap;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
/**
|
||||
* The {@link PushsaferAPIConnection} is responsible for handling the connections to Pushsafer Messages API.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushsaferAPIConnection {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(PushsaferAPIConnection.class);
|
||||
|
||||
private static final String VALIDATE_URL = "https://www.pushsafer.com/api-k";
|
||||
private static final String MESSAGE_URL = "https://www.pushsafer.com/api";
|
||||
private static final String CANCEL_MESSAGE_URL = "https://www.pushsafer.com/api-m";
|
||||
private static final String SOUNDS_URL = "https://www.pushsafer.com/api-s";
|
||||
private static final String ICONS_URL = "https://www.pushsafer.com/api-i";
|
||||
|
||||
private final HttpClient httpClient;
|
||||
private final PushsaferAccountConfiguration config;
|
||||
|
||||
private final ExpiringCacheMap<String, String> cache = new ExpiringCacheMap<>(TimeUnit.DAYS.toMillis(1));
|
||||
|
||||
public PushsaferAPIConnection(HttpClient httpClient, PushsaferAccountConfiguration config) {
|
||||
this.httpClient = httpClient;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public boolean validateUser() throws PushsaferCommunicationException, PushsaferConfigurationException {
|
||||
final String localApikey = config.apikey;
|
||||
if (localApikey == null || localApikey.isEmpty()) {
|
||||
throw new PushsaferConfigurationException("@text/offline.conf-error-missing-apikey");
|
||||
}
|
||||
final String localUser = config.user;
|
||||
if (localUser == null || localUser.isEmpty()) {
|
||||
throw new PushsaferConfigurationException("@text/offline.conf-error-missing-user");
|
||||
}
|
||||
|
||||
final String content = get(buildURL(VALIDATE_URL, Map.of(PushsaferMessageBuilder.MESSAGE_KEY_TOKEN, localApikey,
|
||||
PushsaferMessageBuilder.MESSAGE_KEY_USER, localUser)));
|
||||
final JsonObject json = content == null || content.isBlank() ? null
|
||||
: JsonParser.parseString(content).getAsJsonObject();
|
||||
return json == null ? false : getMessageStatus(json);
|
||||
}
|
||||
|
||||
public boolean sendPushsaferMessage(PushsaferMessageBuilder message)
|
||||
throws PushsaferCommunicationException, PushsaferConfigurationException {
|
||||
return getMessageStatus(post(MESSAGE_URL, message.build()));
|
||||
}
|
||||
|
||||
public String sendPushsaferPriorityMessage(PushsaferMessageBuilder message)
|
||||
throws PushsaferCommunicationException, PushsaferConfigurationException {
|
||||
final JsonObject json = JsonParser.parseString(post(MESSAGE_URL, message.build())).getAsJsonObject();
|
||||
return getMessageStatus(json) && json.has("receipt") ? json.get("receipt").getAsString() : "";
|
||||
}
|
||||
|
||||
public boolean cancelPushsaferPriorityMessage(String receipt)
|
||||
throws PushsaferCommunicationException, PushsaferConfigurationException {
|
||||
return getMessageStatus(post(CANCEL_MESSAGE_URL.replace("{receipt}", receipt),
|
||||
PushsaferMessageBuilder.getInstance(config.apikey, config.device).build()));
|
||||
}
|
||||
|
||||
public List<Sound> getSounds() throws PushsaferCommunicationException, PushsaferConfigurationException {
|
||||
final String localApikey = config.apikey;
|
||||
if (localApikey == null || localApikey.isEmpty()) {
|
||||
throw new PushsaferConfigurationException("@text/offline.conf-error-missing-apikey");
|
||||
}
|
||||
|
||||
final Map<String, String> params = new HashMap<>(1);
|
||||
params.put(PushsaferMessageBuilder.MESSAGE_KEY_TOKEN, localApikey);
|
||||
|
||||
final String content = getFromCache(buildURL(SOUNDS_URL, params));
|
||||
final JsonObject json = content == null || content.isBlank() ? null
|
||||
: JsonParser.parseString(content).getAsJsonObject();
|
||||
final JsonObject sounds = json == null || !json.has("sounds") ? null : json.get("sounds").getAsJsonObject();
|
||||
|
||||
return sounds == null ? List.of()
|
||||
: sounds.entrySet().stream().map(entry -> new Sound(entry.getKey(), entry.getValue().getAsString()))
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
public List<Icon> getIcons() throws PushsaferCommunicationException, PushsaferConfigurationException {
|
||||
final String localApikey = config.apikey;
|
||||
if (localApikey == null || localApikey.isEmpty()) {
|
||||
throw new PushsaferConfigurationException("@text/offline.conf-error-missing-apikey");
|
||||
}
|
||||
|
||||
final Map<String, String> params = new HashMap<>(1);
|
||||
params.put(PushsaferMessageBuilder.MESSAGE_KEY_TOKEN, localApikey);
|
||||
|
||||
final String content = getFromCache(buildURL(ICONS_URL, params));
|
||||
final JsonObject json = content == null || content.isBlank() ? null
|
||||
: JsonParser.parseString(content).getAsJsonObject();
|
||||
final JsonObject icons = json == null || !json.has("icons") ? null : json.get("icons").getAsJsonObject();
|
||||
|
||||
return icons == null ? List.of()
|
||||
: icons.entrySet().stream().map(entry -> new Icon(entry.getKey(), entry.getValue().getAsString()))
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
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)
|
||||
throws PushsaferCommunicationException, PushsaferConfigurationException {
|
||||
return cache.putIfAbsentAndGet(url, () -> get(url));
|
||||
}
|
||||
|
||||
private String get(String url) throws PushsaferCommunicationException, PushsaferConfigurationException {
|
||||
return executeRequest(HttpMethod.GET, url, null);
|
||||
}
|
||||
|
||||
private String post(String url, ContentProvider body)
|
||||
throws PushsaferCommunicationException, PushsaferConfigurationException {
|
||||
return executeRequest(HttpMethod.POST, url, body);
|
||||
}
|
||||
|
||||
private String executeRequest(HttpMethod httpMethod, String url, @Nullable ContentProvider body)
|
||||
throws PushsaferCommunicationException, PushsaferConfigurationException {
|
||||
logger.trace("Pushsafer request: {} - URL = '{}'", httpMethod, uglifyApikey(url));
|
||||
try {
|
||||
final Request request = httpClient.newRequest(url).method(httpMethod).timeout(10, TimeUnit.SECONDS);
|
||||
|
||||
if (body != null) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Pushsafer request body: '{}'", body);
|
||||
}
|
||||
request.content(body);
|
||||
}
|
||||
|
||||
final ContentResponse contentResponse = request.send();
|
||||
|
||||
final int httpStatus = contentResponse.getStatus();
|
||||
final String content = contentResponse.getContentAsString();
|
||||
logger.trace("Pushsafer response: status = {}, content = '{}'", httpStatus, content);
|
||||
switch (httpStatus) {
|
||||
case HttpStatus.OK_200:
|
||||
return content;
|
||||
case 250:
|
||||
case HttpStatus.BAD_REQUEST_400:
|
||||
logger.debug("Pushsafer server responded with status code {}: {}", httpStatus, content);
|
||||
throw new PushsaferConfigurationException(getMessageError(content));
|
||||
default:
|
||||
logger.debug("Pushsafer server responded with status code {}: {}", httpStatus, content);
|
||||
throw new PushsaferCommunicationException(content);
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
logger.debug("Exception occurred during execution: {}", e.getLocalizedMessage(), e);
|
||||
throw new PushsaferCommunicationException(e.getLocalizedMessage(), e.getCause());
|
||||
} catch (InterruptedException | TimeoutException e) {
|
||||
logger.debug("Exception occurred during execution: {}", e.getLocalizedMessage(), e);
|
||||
throw new PushsaferCommunicationException(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String uglifyApikey(String url) {
|
||||
return url.replaceAll("(k=)+\\w+", "k=*****");
|
||||
}
|
||||
|
||||
private String getMessageError(String content) {
|
||||
final JsonObject json = JsonParser.parseString(content).getAsJsonObject();
|
||||
final JsonElement errorsElement = json.get("errors");
|
||||
if (errorsElement != null && errorsElement.isJsonArray()) {
|
||||
return errorsElement.getAsJsonArray().toString();
|
||||
}
|
||||
return "@text/offline.conf-error-unknown";
|
||||
}
|
||||
|
||||
private boolean getMessageStatus(String content) {
|
||||
return getMessageStatus(JsonParser.parseString(content).getAsJsonObject());
|
||||
}
|
||||
|
||||
private boolean getMessageStatus(JsonObject json) {
|
||||
return json.has("status") ? json.get("status").getAsInt() == 1 : false;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.internal.connection;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link PushsaferCommunicationException} is a configuration exception for the connections to Pushsafer Messages
|
||||
* API.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushsaferCommunicationException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructs a new exception with null as its detail message.
|
||||
*/
|
||||
public PushsaferCommunicationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message Detail message
|
||||
*/
|
||||
public PushsaferCommunicationException(@Nullable String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause The cause
|
||||
*/
|
||||
public PushsaferCommunicationException(@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 PushsaferCommunicationException(@Nullable String message, @Nullable Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.internal.connection;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link PushsaferConfigurationException} is a configuration exception for the connections to Pushsafer Messages
|
||||
* API.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushsaferConfigurationException extends IllegalArgumentException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructs a new exception with null as its detail message.
|
||||
*/
|
||||
public PushsaferConfigurationException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message.
|
||||
*
|
||||
* @param message Detail message
|
||||
*/
|
||||
public PushsaferConfigurationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified cause.
|
||||
*
|
||||
* @param cause The cause
|
||||
*/
|
||||
public PushsaferConfigurationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new exception with the specified detail message and cause.
|
||||
*
|
||||
* @param message Detail message
|
||||
* @param cause The cause
|
||||
*/
|
||||
public PushsaferConfigurationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
@ -0,0 +1,355 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.internal.connection;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
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.StringContentProvider;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link PushsaferMessageBuilder} builds the body for Pushsafer Messages API requests.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushsaferMessageBuilder {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(PushsaferMessageBuilder.class);
|
||||
|
||||
public static final String MESSAGE_KEY_TOKEN = "k";
|
||||
public static final String MESSAGE_KEY_USER = "u";
|
||||
private static final String MESSAGE_KEY_MESSAGE = "m";
|
||||
private static final String MESSAGE_KEY_TITLE = "t";
|
||||
private static final String MESSAGE_KEY_DEVICE = "d";
|
||||
private static final String MESSAGE_KEY_ICON = "i";
|
||||
private static final String MESSAGE_KEY_COLOR = "c";
|
||||
private static final String MESSAGE_KEY_VIBRATION = "v";
|
||||
private static final String MESSAGE_KEY_PRIORITY = "pr";
|
||||
private static final String MESSAGE_KEY_RETRY = "re";
|
||||
private static final String MESSAGE_KEY_EXPIRE = "ex";
|
||||
private static final String MESSAGE_KEY_URL = "u";
|
||||
private static final String MESSAGE_KEY_URL_TITLE = "ut";
|
||||
private static final String MESSAGE_KEY_SOUND = "s";
|
||||
private static final String MESSAGE_KEY_TIME2LIVE = "l";
|
||||
private static final String MESSAGE_KEY_ANSWER = "a";
|
||||
private static final String MESSAGE_KEY_CONFIRM = "cr";
|
||||
private static final String MESSAGE_KEY_ATTACHMENT = "p";
|
||||
public static final String MESSAGE_KEY_HTML = "html";
|
||||
public static final String MESSAGE_KEY_MONOSPACE = "monospace";
|
||||
|
||||
private static final int MAX_MESSAGE_LENGTH = 4096;
|
||||
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 = 0;
|
||||
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 = "jpeg";
|
||||
public static final String DEFAULT_AUTH = "";
|
||||
|
||||
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 icon;
|
||||
private int confirm;
|
||||
private int time2live;
|
||||
private boolean answer;
|
||||
private @Nullable String color;
|
||||
private @Nullable String vibration;
|
||||
private @Nullable String attachment;
|
||||
private String contentType = DEFAULT_CONTENT_TYPE;
|
||||
private String authentication = DEFAULT_AUTH;
|
||||
private boolean html = false;
|
||||
private boolean monospace = false;
|
||||
|
||||
private PushsaferMessageBuilder(String apikey, String device) throws PushsaferConfigurationException {
|
||||
body.addFieldPart(MESSAGE_KEY_TOKEN, new StringContentProvider(apikey), null);
|
||||
body.addFieldPart(MESSAGE_KEY_DEVICE, new StringContentProvider(device), null);
|
||||
}
|
||||
|
||||
public static PushsaferMessageBuilder getInstance(@Nullable String apikey, @Nullable String device)
|
||||
throws PushsaferConfigurationException {
|
||||
if (apikey == null || apikey.isEmpty()) {
|
||||
throw new PushsaferConfigurationException("@text/offline.conf-error-missing-apikey");
|
||||
}
|
||||
|
||||
if (device == null || device.isEmpty()) {
|
||||
throw new PushsaferConfigurationException("@text/offline.conf-error-missing-device");
|
||||
}
|
||||
|
||||
return new PushsaferMessageBuilder(apikey, device);
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withMessage(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withTitle(String title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withDevice(String device) {
|
||||
this.device = device;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withPriority(int priority) {
|
||||
this.priority = priority;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withRetry(int retry) {
|
||||
this.retry = retry;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withExpire(int expire) {
|
||||
this.expire = expire;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withUrl(String url) {
|
||||
this.url = url;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withUrlTitle(String urlTitle) {
|
||||
this.urlTitle = urlTitle;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withSound(String sound) {
|
||||
this.sound = sound;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withIcon(String icon) {
|
||||
this.icon = icon;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withColor(String color) {
|
||||
this.color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withVibration(String vibration) {
|
||||
this.vibration = vibration;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withAnswer(boolean answer) {
|
||||
this.answer = answer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withTime2live(int time2live) {
|
||||
this.time2live = time2live;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withConfirm(int confirm) {
|
||||
this.confirm = confirm;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withAttachment(String attachment) {
|
||||
this.attachment = attachment;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withContentType(String contentType) {
|
||||
this.contentType = contentType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withAuthentication(String authentication) {
|
||||
this.authentication = authentication;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withHtmlFormatting() {
|
||||
this.html = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PushsaferMessageBuilder withMonospaceFormatting() {
|
||||
this.monospace = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ContentProvider build() throws PushsaferCommunicationException {
|
||||
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 (icon != null) {
|
||||
body.addFieldPart(MESSAGE_KEY_ICON, new StringContentProvider(icon), null);
|
||||
}
|
||||
|
||||
if (color != null) {
|
||||
body.addFieldPart(MESSAGE_KEY_COLOR, new StringContentProvider(color), null);
|
||||
}
|
||||
|
||||
if (vibration != null) {
|
||||
body.addFieldPart(MESSAGE_KEY_VIBRATION, new StringContentProvider(vibration), null);
|
||||
}
|
||||
|
||||
body.addFieldPart(MESSAGE_KEY_CONFIRM, new StringContentProvider(String.valueOf(confirm)), null);
|
||||
|
||||
body.addFieldPart(MESSAGE_KEY_ANSWER, new StringContentProvider(String.valueOf(answer)), null);
|
||||
|
||||
body.addFieldPart(MESSAGE_KEY_TIME2LIVE, new StringContentProvider(String.valueOf(time2live)), null);
|
||||
|
||||
if (attachment != null) {
|
||||
final String encodedString;
|
||||
try {
|
||||
if (attachment.startsWith("http")) {
|
||||
Properties headers = new Properties();
|
||||
headers.put("User-Agent", "Mozilla/5.0");
|
||||
if (!authentication.isBlank()) {
|
||||
headers.put("Authorization", "Basic "
|
||||
+ Base64.getEncoder().encodeToString(authentication.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
String content = HttpUtil.executeUrl("GET", attachment, headers, null, null, 10);
|
||||
if (content == null) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Skip sending the message as content '%s' does not exist.", attachment));
|
||||
}
|
||||
encodedString = "data:" + contentType + ";base64," + content;
|
||||
} else {
|
||||
File file = new File(attachment);
|
||||
if (!file.exists()) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Skip sending the message as file '%s' does not exist.", attachment));
|
||||
}
|
||||
byte[] fileContent = Files.readAllBytes(file.toPath());
|
||||
encodedString = "data:image/" + contentType + ";base64,"
|
||||
+ Base64.getEncoder().encodeToString(fileContent);
|
||||
}
|
||||
body.addFieldPart(MESSAGE_KEY_ATTACHMENT, new StringContentProvider(encodedString), null);
|
||||
} catch (IOException e) {
|
||||
logger.debug("IOException occurred - skip sending message: {}", e.getLocalizedMessage(), e);
|
||||
throw new PushsaferCommunicationException(
|
||||
String.format("Skip sending the message: %s", e.getLocalizedMessage()), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (html) {
|
||||
body.addFieldPart(MESSAGE_KEY_HTML, new StringContentProvider("1"), null);
|
||||
} else if (monospace) {
|
||||
body.addFieldPart(MESSAGE_KEY_MONOSPACE, new StringContentProvider("1"), null);
|
||||
}
|
||||
|
||||
body.close();
|
||||
return body;
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.internal.dto;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.config.core.ParameterOption;
|
||||
|
||||
/**
|
||||
* The {@link Icons} is the Java class used to map the JSON response to an Pushsafer API request..
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Icon {
|
||||
public String icon;
|
||||
public String label;
|
||||
|
||||
public Icon(String icon, String label) {
|
||||
this.icon = icon;
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public ParameterOption getAsParameterOption() {
|
||||
return new ParameterOption(icon, label);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.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 Pushsafer API request.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@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-2021 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.pushsafer.internal.factory;
|
||||
|
||||
import static org.openhab.binding.pushsafer.internal.PushsaferBindingConstants.PUSHSAFER_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.pushsafer.internal.handler.PushsaferAccountHandler;
|
||||
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 PushsaferHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@Component(configurationPid = "binding.pushsafer", service = ThingHandlerFactory.class)
|
||||
@NonNullByDefault
|
||||
public class PushsaferHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(PUSHSAFER_ACCOUNT);
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
@Activate
|
||||
public PushsaferHandlerFactory(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 (PUSHSAFER_ACCOUNT.equals(thingTypeUID)) {
|
||||
return new PushsaferAccountHandler(thing, httpClient);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,246 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.internal.handler;
|
||||
|
||||
import static org.openhab.binding.pushsafer.internal.PushsaferBindingConstants.*;
|
||||
|
||||
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.pushsafer.internal.actions.PushsaferActions;
|
||||
import org.openhab.binding.pushsafer.internal.config.PushsaferAccountConfiguration;
|
||||
import org.openhab.binding.pushsafer.internal.config.PushsaferConfigOptionProvider;
|
||||
import org.openhab.binding.pushsafer.internal.connection.PushsaferAPIConnection;
|
||||
import org.openhab.binding.pushsafer.internal.connection.PushsaferCommunicationException;
|
||||
import org.openhab.binding.pushsafer.internal.connection.PushsaferConfigurationException;
|
||||
import org.openhab.binding.pushsafer.internal.connection.PushsaferMessageBuilder;
|
||||
import org.openhab.binding.pushsafer.internal.dto.Icon;
|
||||
import org.openhab.binding.pushsafer.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 PushsaferAccountHandler} is responsible for handling commands, which are sent to one of the channels.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PushsaferAccountHandler extends BaseThingHandler {
|
||||
|
||||
private static final Collection<Class<? extends ThingHandlerService>> SUPPORTED_THING_ACTIONS = Set
|
||||
.of(PushsaferActions.class, PushsaferConfigOptionProvider.class);
|
||||
|
||||
private final HttpClient httpClient;
|
||||
|
||||
private PushsaferAccountConfiguration config = new PushsaferAccountConfiguration();
|
||||
private @Nullable PushsaferAPIConnection connection;
|
||||
|
||||
public PushsaferAccountHandler(Thing thing, HttpClient httpClient) {
|
||||
super(thing);
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
config = getConfigAs(PushsaferAccountConfiguration.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 PushsaferAPIConnection(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 Pushsafer API.
|
||||
*
|
||||
* @return a list of {@link Sound}s
|
||||
*/
|
||||
public List<Sound> getSounds() {
|
||||
try {
|
||||
return connection != null ? connection.getSounds() : List.of();
|
||||
} catch (PushsaferCommunicationException e) {
|
||||
// do nothing, causing exception is already logged
|
||||
} catch (PushsaferConfigurationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of current icons from the Pushsafer API.
|
||||
*
|
||||
* @return a list of {@link Icon}s
|
||||
*/
|
||||
public List<Icon> getIcons() {
|
||||
try {
|
||||
return connection != null ? connection.getIcons() : List.of();
|
||||
} catch (PushsaferCommunicationException e) {
|
||||
// do nothing, causing exception is already logged
|
||||
} catch (PushsaferConfigurationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
return List.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a preconfigured {@link PushsaferMessageBuilder}.
|
||||
*
|
||||
* @param message the message
|
||||
* @return a {@link PushsaferMessageBuilder} instance
|
||||
*/
|
||||
public PushsaferMessageBuilder getDefaultPushsaferMessageBuilder(String message)
|
||||
throws PushsaferConfigurationException {
|
||||
PushsaferMessageBuilder builder = PushsaferMessageBuilder.getInstance(config.apikey, config.device)
|
||||
.withMessage(message) //
|
||||
.withTitle(config.title) //
|
||||
.withRetry(config.retry) //
|
||||
.withExpire(config.expire);
|
||||
// specify format if defined
|
||||
switch (config.format) {
|
||||
case PushsaferMessageBuilder.MESSAGE_KEY_HTML:
|
||||
builder.withHtmlFormatting();
|
||||
break;
|
||||
case PushsaferMessageBuilder.MESSAGE_KEY_MONOSPACE:
|
||||
builder.withMonospaceFormatting();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// add sound if defined
|
||||
if (!DEFAULT_SOUND.equals(config.sound)) {
|
||||
builder.withSound(config.sound);
|
||||
}
|
||||
// add icon if defined
|
||||
if (!DEFAULT_ICON.equals(config.icon)) {
|
||||
builder.withIcon(config.icon);
|
||||
}
|
||||
// add color if defined
|
||||
if (!DEFAULT_COLOR.equals(config.color)) {
|
||||
builder.withColor(config.color);
|
||||
}
|
||||
// add vibration if defined
|
||||
if (!DEFAULT_VIBRATION.equals(config.vibration)) {
|
||||
builder.withVibration(config.vibration);
|
||||
}
|
||||
// add url if defined
|
||||
if (!DEFAULT_URL.equals(config.url)) {
|
||||
builder.withUrl(config.url);
|
||||
}
|
||||
// add urlTitle if defined
|
||||
if (!DEFAULT_URLTITLE.equals(config.urlTitle)) {
|
||||
builder.withUrlTitle(config.urlTitle);
|
||||
}
|
||||
// add confirm if defined
|
||||
if (DEFAULT_CONFIRM != config.confirm) {
|
||||
builder.withConfirm(config.confirm);
|
||||
}
|
||||
// add answer if defined
|
||||
if (DEFAULT_ANSWER != config.answer) {
|
||||
builder.withAnswer(config.answer);
|
||||
}
|
||||
// add time2live if defined
|
||||
if (DEFAULT_TIME2LIVE != config.time2live) {
|
||||
builder.withTime2live(config.time2live);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
public boolean sendPushsaferMessage(PushsaferMessageBuilder messageBuilder) {
|
||||
if (connection != null) {
|
||||
try {
|
||||
return connection.sendPushsaferMessage(messageBuilder);
|
||||
} catch (PushsaferCommunicationException e) {
|
||||
// do nothing, causing exception is already logged
|
||||
} catch (PushsaferConfigurationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
throw new IllegalArgumentException("PushsaferAPIConnection is null!");
|
||||
}
|
||||
}
|
||||
|
||||
public String sendPushsaferPriorityMessage(PushsaferMessageBuilder messageBuilder) {
|
||||
if (connection != null) {
|
||||
try {
|
||||
return connection.sendPushsaferPriorityMessage(messageBuilder);
|
||||
} catch (PushsaferCommunicationException e) {
|
||||
// do nothing, causing exception is already logged
|
||||
} catch (PushsaferConfigurationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
return "";
|
||||
} else {
|
||||
throw new IllegalArgumentException("PushsaferAPIConnection is null!");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean cancelPushsaferPriorityMessage(String receipt) {
|
||||
if (connection != null) {
|
||||
try {
|
||||
return connection.cancelPushsaferPriorityMessage(receipt);
|
||||
} catch (PushsaferCommunicationException e) {
|
||||
// do nothing, causing exception is already logged
|
||||
} catch (PushsaferConfigurationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
throw new IllegalArgumentException("PushsaferAPIConnection is null!");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("null")
|
||||
private void asyncValidateUser() {
|
||||
try {
|
||||
connection.validateUser();
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} catch (PushsaferCommunicationException | PushsaferConfigurationException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="pushsafer" 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>Pushsafer Binding</name>
|
||||
<description>With Pushsafer you can send & receive push notifications in real time, easily and securely on your
|
||||
iPhone, iPad, Android, Windows mobile or Windows desktop device as well as on your browser (Chrome, Firefox, Opera
|
||||
& Yandex)!</description>
|
||||
|
||||
</binding:binding>
|
@ -0,0 +1,99 @@
|
||||
<?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:pushsafer:pushsafer-account">
|
||||
<parameter name="apikey" type="text" required="true">
|
||||
<context>password</context>
|
||||
<label>Private or Alias Key</label>
|
||||
<description>Your Private or Alias to access the Pushsafer Message API.</description>
|
||||
</parameter>
|
||||
<parameter name="user" type="text" required="true">
|
||||
<label>Username</label>
|
||||
<description>Your username or email address to validate against the Pushsafer Message API.</description>
|
||||
</parameter>
|
||||
<parameter name="device" type="text">
|
||||
<label>Device ID</label>
|
||||
<description>Device ID or Device Group ID to which devices you want to send push-notifications ("a" for all available
|
||||
devices).</description>
|
||||
<default>a</default>
|
||||
</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>1</default>
|
||||
</parameter>
|
||||
<parameter name="vibration" type="text">
|
||||
<label>Vibration</label>
|
||||
<description>How often the device should vibrate. empty=device default or a number 1-3</description>
|
||||
<default>1</default>
|
||||
</parameter>
|
||||
<parameter name="icon" type="text">
|
||||
<label>Notification Icon</label>
|
||||
<description>The default notification icon on target device.</description>
|
||||
<default>1</default>
|
||||
</parameter>
|
||||
<parameter name="color" type="text">
|
||||
<label>Icon Color</label>
|
||||
<description>The color (hexadecimal) of notification icon (e.g. #FF0000).</description>
|
||||
<default></default>
|
||||
</parameter>
|
||||
<parameter name="url" type="text">
|
||||
<label>URL</label>
|
||||
<description>URL or URL Scheme send with notification.</description>
|
||||
</parameter>
|
||||
<parameter name="urlTitle" type="text">
|
||||
<label>URL Title</label>
|
||||
<description>Title of URL.</description>
|
||||
</parameter>
|
||||
<parameter name="retry" type="integer" min="0" max="43200" step="1" unit="m">
|
||||
<advanced>true</advanced>
|
||||
<label>Retry</label>
|
||||
<description>Integer 0-43200: Time in minutes, after a message automatically gets purged.</description>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
<parameter name="expire" type="integer" min="0" max="10800" step="60" unit="s">
|
||||
<advanced>true</advanced>
|
||||
<label>Expire</label>
|
||||
<description>Integer 60-10800 (60s steps): Time in seconds, after the retry/resend should stop.</description>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
<parameter name="confirm" type="integer" min="0" max="10800" step="10" unit="s">
|
||||
<advanced>true</advanced>
|
||||
<label>Confirm</label>
|
||||
<description>Integer 10-10800 (10s steps): Time in seconds after which a message should be sent again before it is
|
||||
confirmed.</description>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
<parameter name="time2live" type="integer" min="0" max="43200" step="1" unit="m">
|
||||
<advanced>true</advanced>
|
||||
<label>Time to Live</label>
|
||||
<description>Time in minutes, after a message automatically gets purged.</description>
|
||||
<default>0</default>
|
||||
</parameter>
|
||||
<parameter name="answer" type="boolean">
|
||||
<advanced>true</advanced>
|
||||
<label>Answer</label>
|
||||
<description>true = Enable reply to push notifications, false otherwise.</description>
|
||||
<default>false</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</config-description:config-descriptions>
|
@ -0,0 +1,56 @@
|
||||
# user defined messages
|
||||
offline.conf-error-missing-apikey = The 'Private Key' parameter must be configured.
|
||||
offline.conf-error-missing-user = The 'Username' parameter must be configured.
|
||||
offline.conf-error-missing-device = The 'Device ID' parameter must be configured.
|
||||
offline.conf-error-unknown = An unknown error occurred.
|
||||
|
||||
# actions
|
||||
sendPushsaferMessageActionLabel = send a plain text message
|
||||
sendPushsaferMessageActionDescription = This method is used to send a plain text message.
|
||||
sendPushsaferMessageActionOutputLabel = Sent
|
||||
sendPushsaferMessageActionOutputDescription = true, if message has been sent successfully
|
||||
sendPushsaferMessageActionInputMessageLabel = Message
|
||||
sendPushsaferMessageActionInputMessageDescription = Message to be sent.
|
||||
sendPushsaferMessageActionInputTitleLabel = Title
|
||||
sendPushsaferMessageActionInputTitleDescription = The title of the message.
|
||||
|
||||
sendPushsaferURLMessageActionLabel = send a plain text message with an URL
|
||||
sendPushsaferURLMessageActionDescription = This method is used to send a message with an URL.
|
||||
sendPushsaferMessageActionInputURLLabel = URL
|
||||
sendPushsaferMessageActionInputURLDescription = A supplementary URL to show with the message.
|
||||
sendPushsaferMessageActionInputURLTitleLabel = URL Title
|
||||
sendPushsaferMessageActionInputURLTitleDescription = 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.
|
||||
|
||||
sendPushsaferMonospaceMessageActionLabel = send a monospace message
|
||||
sendPushsaferMonospaceMessageActionDescription = This method is used to send a monospace message.
|
||||
|
||||
sendPushsaferAttachmentMessageActionLabel = send a plain text message with an image attachment
|
||||
sendPushsaferAttachmentMessageActionDescription = This method is used to send a message with an image attachment.
|
||||
sendPushsaferMessageActionInputAttachmentLabel = Image Attachment
|
||||
sendPushsaferMessageActionInputAttachmentDescription = A local path or url to the image.
|
||||
sendPushsaferMessageActionInputContentTypeLabel = Image Type
|
||||
sendPushsaferMessageActionInputContentTypeDescription = The image type of the attachment. Defaults to "jpeg", possible values "jpeg,png,gif".
|
||||
sendPushsaferMessageActionInputAuthenticationLabel = Authentication
|
||||
sendPushsaferMessageActionInputAuthenticationDescription = Basic access authentication for HTTP(S) requests. Default: "", Example: "user:password".
|
||||
|
||||
sendPushsaferPriorityMessageActionLabel = send a priority message
|
||||
sendPushsaferPriorityMessageActionDescription = This method is used to send a priority message.
|
||||
sendPushsaferPriorityMessageActionOutputLabel = Receipt
|
||||
sendPushsaferPriorityMessageActionOutputDescription = Receipt, if priority message sent successfully.
|
||||
sendPushsaferMessageActionInputPriorityLabel = Priority
|
||||
sendPushsaferMessageActionInputPriorityDescription = Priority to be used. Defaults to 2.
|
||||
|
||||
cancelPushsaferPriorityMessageActionLabel = cancel a priority message
|
||||
cancelPushsaferPriorityMessageActionDescription = This method is used to cancel a priority message.
|
||||
cancelPushsaferPriorityMessageActionOnputLabel = Cancelled
|
||||
cancelPushsaferPriorityMessageActionOnputDescription = true, if message has been cancelled successfully.
|
||||
cancelPushsaferPriorityMessageActionInputReceiptLabel = Receipt
|
||||
cancelPushsaferPriorityMessageActionInputReceiptDescription = Receipt of the message to be canceled.
|
||||
|
||||
sendPushsaferMessageToDeviceActionLabel = send a plain text message to a specific device
|
||||
sendPushsaferMessageToDeviceActionDescription = This method is used to send a message to a specific device.
|
||||
sendPushsaferMessageActionInputDeviceLabel = Device
|
||||
sendPushsaferMessageActionInputDeviceDescription = The name of a specific device (multiple devices may be separated by a comma).
|
@ -0,0 +1,97 @@
|
||||
# binding
|
||||
binding.pushsafer.description = Mit Pushsafer kannst du in Echtzeit, einfach & sicher, Push-Benachrichtigungen auf dein iPhone, iPad, Android, Windows mobile oder Windows Desktop Gerät sowie an deinen Browser (Chrome, Firefox, Opera & Yandex) senden & empfangen!.
|
||||
|
||||
# thing types
|
||||
thing-type.pushsafer.pushsafer-account.label = Pushsafer Konto
|
||||
thing-type.pushsafer.pushsafer-account.description = Ermöglicht den Zugriff auf die Pushsafer Message API.
|
||||
|
||||
# thing type config description
|
||||
thing-type.config.pushsafer.pushsafer-account.apikey.label = Privater oder Alias Schlüssel
|
||||
thing-type.config.pushsafer.pushsafer-account.apikey.description = Privater oder Alias Schlüssel für den Zugriff auf die Pushsafer Message API.
|
||||
thing-type.config.pushsafer.pushsafer-account.user.label = Benutzername oder E-mAil Adresse für den Zugriff auf die Pushsafer Message API.
|
||||
thing-type.config.pushsafer.pushsafer-account.user.description = Benutzername oder E-mAil Adresse .
|
||||
thing-type.config.pushsafer.pushsafer-account.device.label = Geräte ID oder Geräte-Gruppen ID
|
||||
thing-type.config.pushsafer.pushsafer-account.device.description = Geräte ID oder Geräte-Gruppen ID an welche Geräte die Nachrichten gesendet werden sollen.
|
||||
thing-type.config.pushsafer.pushsafer-account.title.label = Titel
|
||||
thing-type.config.pushsafer.pushsafer-account.title.description = Standardtitel der Nachricht.
|
||||
thing-type.config.pushsafer.pushsafer-account.format.label = Format
|
||||
thing-type.config.pushsafer.pushsafer-account.format.description = Standardformat der Nachricht.
|
||||
thing-type.config.pushsafer.pushsafer-account.sound.label = Benachrichtigungs-Ton
|
||||
thing-type.config.pushsafer.pushsafer-account.sound.description = Standardbenachrichtigungs-Ton auf dem Endgerät.
|
||||
thing-type.config.pushsafer.pushsafer-account.vibration.label = Vibration
|
||||
thing-type.config.pushsafer.pushsafer-account.vibration.description = Wie oft das Gerät vibrieren soll. Leer=Geräte-Standard oder 0-3
|
||||
thing-type.config.pushsafer.pushsafer-account.icon.label = Benachrichtigungs-Icon
|
||||
thing-type.config.pushsafer.pushsafer-account.icon.description = Standardbenachrichtigungs-Icon auf dem Endgerät.
|
||||
thing-type.config.pushsafer.pushsafer-account.color.label = Icon Farbe
|
||||
thing-type.config.pushsafer.pushsafer-account.color.description = Standard Farbe des Icons (hexadezimal z.B. #FF0000)
|
||||
thing-type.config.pushsafer.pushsafer-account.url.label = URL
|
||||
thing-type.config.pushsafer.pushsafer-account.url.description = URL oder URL Schema welche mit der Benachrichtigung versendet wird.
|
||||
thing-type.config.pushsafer.pushsafer-account.urlTitle.label = URL Titel
|
||||
thing-type.config.pushsafer.pushsafer-account.urlTitle.description = Titel der URL.
|
||||
thing-type.config.pushsafer.pushsafer-account.retry.label = Wiederholungen
|
||||
thing-type.config.pushsafer.pushsafer-account.retry.description = Ganzzahl 60-10800 (60er Schritte): Zeit in Sekunden, nach der die Nachricht erneut versendet werden soll.
|
||||
thing-type.config.pushsafer.pushsafer-account.expire.label = Verfall
|
||||
thing-type.config.pushsafer.pushsafer-account.expire.description = Ganzzahl 60-10800: Zeit in Sekunden, nach der das erneute Versenden der Nachrichten gestoppt werden soll.
|
||||
thing-type.config.pushsafer.pushsafer-account.confirm.label = Bestätigung
|
||||
thing-type.config.pushsafer.pushsafer-account.confirm.description = Ganzzahl 10-10800 (10s Schritte) Zeit in Sekunden, nachdem eine Nachricht erneut gesendet werden soll, bis diese bestätigt wird.
|
||||
thing-type.config.pushsafer.pushsafer-account.answer.label = Antworten
|
||||
thing-type.config.pushsafer.pushsafer-account.answer.description = Ermöglicht das Antworten auf Push-Benachrichtigungen. 1 = auf diese Nachricht kann geantwortet werden, 0 = auf diese Nachricht kann nicht geantwortet werden.
|
||||
thing-type.config.pushsafer.pushsafer-account.time2live.label = Time to Live
|
||||
thing-type.config.pushsafer.pushsafer-account.time2live.description = Ganzzahl 0-43200: Zeit in Minuten, nach der die Nachricht automatisch gelöscht wird. 0 oder leer = nicht automatisch löschen.
|
||||
|
||||
# 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.
|
||||
offline.conf-error-missing-device = Der Parameter 'device' muss konfiguriert werden.
|
||||
offline.conf-error-unknown = Ein unbekannter Fehler ist aufgetreten.
|
||||
|
||||
# actions
|
||||
sendPushsaferMessageActionLabel = eine Textnachricht senden
|
||||
sendPushsaferMessageActionDescription = Action zum Versenden einer Textnachricht.
|
||||
sendPushsaferMessageActionOutputLabel = Gesendet
|
||||
sendPushsaferMessageActionOutputDescription = true, wenn die Nachricht erfolgreich versendet wurde.
|
||||
sendPushsaferMessageActionInputMessageLabel = Nachricht
|
||||
sendPushsaferMessageActionInputMessageDescription = Die Nachricht.
|
||||
sendPushsaferMessageActionInputTitleLabel = Titel
|
||||
sendPushsaferMessageActionInputTitleDescription = Titel der Nachricht.
|
||||
|
||||
sendPushsaferURLMessageActionLabel = eine Textnachricht mit URL senden
|
||||
sendPushsaferURLMessageActionDescription = Action zum Versenden einer Textnachricht mit einer URL.
|
||||
sendPushsaferMessageActionInputURLLabel = URL
|
||||
sendPushsaferMessageActionInputURLDescription = Eine zusätzliche URL, die mit der Nachricht angezeigt werden soll.
|
||||
sendPushsaferMessageActionInputURLTitleLabel = URL Title
|
||||
sendPushsaferMessageActionInputURLTitleDescription = Ein Titel für die URL, andernfalls wird nur die URL angezeigt.
|
||||
|
||||
sendHTMLMessageActionLabel = eine HTML-Nachricht senden
|
||||
sendHTMLMessageActionDescription = Action zum Versenden einer HTML-Nachricht.
|
||||
|
||||
sendPushsaferMonospaceMessageActionLabel = eine monospace-Nachricht senden
|
||||
sendPushsaferMonospaceMessageActionDescription = Action zum Versenden einer monospace-Nachricht.
|
||||
|
||||
sendPushsaferAttachmentMessageActionLabel = eine Textnachricht mit Bild-Anhang senden
|
||||
sendPushsaferAttachmentMessageActionDescription = Action zum Versenden einer Textnachricht mit Bild-Anhang.
|
||||
sendPushsaferMessageActionInputAttachmentLabel = Bild-Anhang
|
||||
sendPushsaferMessageActionInputAttachmentDescription = Lokaler Pfad oder URL zum Anhang.
|
||||
sendPushsaferMessageActionInputContentTypeLabel = Bild-Typ
|
||||
sendPushsaferMessageActionInputContentTypeDescription = Der Bild-Typ für den Anhang. Default: "jpeg", mögliche Werte "jpeg,png,gif".
|
||||
sendPushsaferMessageActionInputAuthenticationLabel = Authentifizierung
|
||||
sendPushsaferMessageActionInputAuthenticationDescription = Basisauthentifizierung für HTTP(S) Aufrufe. Default: "", Beispiel: "user:passwort".
|
||||
|
||||
sendPushsaferPriorityMessageActionLabel = eine Prioritätsnachricht senden
|
||||
sendPushsaferPriorityMessageActionDescription = Action zum Versenden einer Prioritätsnachricht.
|
||||
sendPushsaferPriorityMessageActionOutputLabel = Receipt
|
||||
sendPushsaferPriorityMessageActionOutputDescription = ID der Prioritätsnachricht, wenn diese erfolgreich versendet wurde.
|
||||
sendPushsaferMessageActionInputPriorityLabel = Priorität
|
||||
sendPushsaferMessageActionInputPriorityDescription = Die Priorität. Default: 2.
|
||||
|
||||
cancelPushsaferPriorityMessageActionLabel = eine Prioritätsnachricht annullieren
|
||||
cancelPushsaferPriorityMessageActionDescription = Action zum Annullieren einer Prioritätsnachricht.
|
||||
cancelPushsaferPriorityMessageActionOnputLabel = Annulliert
|
||||
cancelPushsaferPriorityMessageActionOnputDescription = true, wenn die Prioritätsnachricht erfolgreich annulliert wurde.
|
||||
cancelPushsaferPriorityMessageActionInputReceiptLabel = Receipt
|
||||
cancelPushsaferPriorityMessageActionInputReceiptDescription = Die ID der Prioritätsnachricht.
|
||||
|
||||
sendPushsaferMessageToDeviceActionLabel = eine Nachricht an ein Endgerät
|
||||
sendPushsaferMessageToDeviceActionDescription = Action zum Versenden einer Nachricht an ein Endgerät.
|
||||
sendPushsaferMessageActionInputDeviceLabel = Endgerät
|
||||
sendPushsaferMessageActionInputDeviceDescription = 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="pushsafer"
|
||||
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="pushsafer-account">
|
||||
<label>Pushsafer Account</label>
|
||||
<description>Provides access to the Pushsafer Messages API.</description>
|
||||
|
||||
<representation-property>apikey</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:pushsafer:pushsafer-account"/>
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,166 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.pushsafer.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.pushsafer.internal.connection.PushsaferConfigurationException;
|
||||
import org.openhab.binding.pushsafer.internal.connection.PushsaferMessageBuilder;
|
||||
import org.openhab.binding.pushsafer.internal.handler.PushsaferAccountHandler;
|
||||
import org.openhab.core.thing.binding.ThingActions;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PushsaferActions}.
|
||||
*
|
||||
* @author Kevin Siml - Initial contribution, forked from Christoph Weitkamp
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@MockitoSettings(strictness = Strictness.WARN)
|
||||
public class PushsaferActionsTest {
|
||||
|
||||
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 PushsaferAccountHandler mockPushsaferAccountHandler;
|
||||
|
||||
private PushsaferActions pushsaferThingActions;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws PushsaferConfigurationException {
|
||||
pushsaferThingActions = new PushsaferActions();
|
||||
|
||||
when(mockPushsaferAccountHandler.getDefaultPushsaferMessageBuilder(any()))
|
||||
.thenReturn(PushsaferMessageBuilder.getInstance("key", "user"));
|
||||
when(mockPushsaferAccountHandler.sendPushsaferMessage(any())).thenReturn(Boolean.TRUE);
|
||||
when(mockPushsaferAccountHandler.sendPushsaferPriorityMessage(any())).thenReturn(RECEIPT);
|
||||
}
|
||||
|
||||
// sendPushsaferMessage
|
||||
@Test
|
||||
public void testSendMessageThingActionsIsNotPushsaferThingActions() {
|
||||
assertThrows(ClassCastException.class,
|
||||
() -> PushsaferActions.sendPushsaferMessage(thingActionsStub, MESSAGE, TITLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMessageThingHandlerIsNull() {
|
||||
assertThrows(RuntimeException.class,
|
||||
() -> PushsaferActions.sendPushsaferMessage(pushsaferThingActions, MESSAGE, TITLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMessageWithoutTitle() {
|
||||
pushsaferThingActions.setThingHandler(mockPushsaferAccountHandler);
|
||||
boolean sent = PushsaferActions.sendPushsaferMessage(pushsaferThingActions, MESSAGE, null);
|
||||
assertThat(sent, is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendMessage() {
|
||||
pushsaferThingActions.setThingHandler(mockPushsaferAccountHandler);
|
||||
boolean sent = PushsaferActions.sendPushsaferMessage(pushsaferThingActions, MESSAGE, TITLE);
|
||||
assertThat(sent, is(true));
|
||||
}
|
||||
|
||||
// sendPushsaferURLMessage
|
||||
@Test
|
||||
public void testSendURLMessageThingActionsIsNotPushsaferThingActions() {
|
||||
assertThrows(ClassCastException.class,
|
||||
() -> PushsaferActions.sendPushsaferURLMessage(thingActionsStub, MESSAGE, TITLE, URL, URL_TITLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendURLMessageThingHandlerIsNull() {
|
||||
assertThrows(RuntimeException.class,
|
||||
() -> PushsaferActions.sendPushsaferURLMessage(pushsaferThingActions, MESSAGE, TITLE, URL, URL_TITLE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendURLMessageWithoutTitle() {
|
||||
pushsaferThingActions.setThingHandler(mockPushsaferAccountHandler);
|
||||
boolean sent = PushsaferActions.sendPushsaferURLMessage(pushsaferThingActions, MESSAGE, null, URL, URL_TITLE);
|
||||
assertThat(sent, is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendURLMessageWithoutURLTitle() {
|
||||
pushsaferThingActions.setThingHandler(mockPushsaferAccountHandler);
|
||||
boolean sent = PushsaferActions.sendPushsaferURLMessage(pushsaferThingActions, MESSAGE, TITLE, URL, null);
|
||||
assertThat(sent, is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendURLMessage() {
|
||||
pushsaferThingActions.setThingHandler(mockPushsaferAccountHandler);
|
||||
boolean sent = PushsaferActions.sendPushsaferURLMessage(pushsaferThingActions, MESSAGE, TITLE, URL, URL_TITLE);
|
||||
assertThat(sent, is(true));
|
||||
}
|
||||
|
||||
// sendPushsaferPriorityMessage
|
||||
@Test
|
||||
public void testSendPriorityMessageThingActionsIsNotPushsaferThingActions() {
|
||||
assertThrows(ClassCastException.class, () -> PushsaferActions.sendPushsaferPriorityMessage(thingActionsStub,
|
||||
MESSAGE, TITLE, PushsaferMessageBuilder.EMERGENCY_PRIORITY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendPriorityMessageThingHandlerIsNull() {
|
||||
assertThrows(RuntimeException.class, () -> PushsaferActions.sendPushsaferPriorityMessage(pushsaferThingActions,
|
||||
MESSAGE, TITLE, PushsaferMessageBuilder.EMERGENCY_PRIORITY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendPriorityMessageWithoutTitle() {
|
||||
pushsaferThingActions.setThingHandler(mockPushsaferAccountHandler);
|
||||
String receipt = PushsaferActions.sendPushsaferPriorityMessage(pushsaferThingActions, MESSAGE, null,
|
||||
PushsaferMessageBuilder.EMERGENCY_PRIORITY);
|
||||
assertThat(receipt, is(RECEIPT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendPriorityMessage() {
|
||||
pushsaferThingActions.setThingHandler(mockPushsaferAccountHandler);
|
||||
String receipt = PushsaferActions.sendPushsaferPriorityMessage(pushsaferThingActions, MESSAGE, TITLE,
|
||||
PushsaferMessageBuilder.EMERGENCY_PRIORITY);
|
||||
assertThat(receipt, is(RECEIPT));
|
||||
}
|
||||
}
|
@ -269,7 +269,7 @@
|
||||
<module>org.openhab.binding.pulseaudio</module>
|
||||
<module>org.openhab.binding.pushbullet</module>
|
||||
<module>org.openhab.binding.pushover</module>
|
||||
<module>org.openhab.binding.qbus</module>
|
||||
<module>org.openhab.binding.pushsafer</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