added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.enigma2-${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-enigma2" description="Enigma2 Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.enigma2/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,180 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.actions;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.enigma2.handler.Enigma2Handler;
import org.openhab.binding.enigma2.internal.Enigma2BindingConstants;
import org.openhab.core.automation.annotation.ActionInput;
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;
/**
* This is the automation engine actions handler service for the
* enigma2 actions.
*
* @author Guido Dolfen - Initial contribution
*/
@ThingActionsScope(name = "enigma2")
@NonNullByDefault
public class Enigma2Actions implements ThingActions, IEnigma2Actions {
private @Nullable Enigma2Handler handler;
@Override
public void setThingHandler(@Nullable ThingHandler handler) {
this.handler = (Enigma2Handler) handler;
}
@Override
public @Nullable Enigma2Handler getThingHandler() {
return this.handler;
}
@Override
@RuleAction(label = "@text/actions.enigma2.send-rc-button.label", description = "@text/actions.enigma2.send-rc-button.description")
@SuppressWarnings("null")
public void sendRcCommand(
@ActionInput(name = "rcButton", label = "@text/actions-input.enigma2.rc-button.label", description = "@text/actions-input.enigma2.rc-button.description") String rcButton) {
handler.sendRcCommand(rcButton);
}
@Override
@RuleAction(label = "@text/actions.enigma2.send-info.label", description = "@text/actions.enigma2.send-info.description")
@SuppressWarnings("null")
public void sendInfo(
@ActionInput(name = "text", label = "@text/actions-input.enigma2.text.label", description = "@text/actions-input.enigma2.text.description") String text) {
handler.sendInfo(Enigma2BindingConstants.MESSAGE_TIMEOUT, text);
}
@Override
@RuleAction(label = "@text/actions.enigma2.send-info.label", description = "@text/actions.enigma2.send-info.description")
@SuppressWarnings("null")
public void sendInfo(
@ActionInput(name = "text", label = "@text/actions-input.enigma2.text.label", description = "@text/actions-input.enigma2.text.description") String text,
@ActionInput(name = "timeout", label = "@text/actions-input.enigma2.timeout.label", description = "@text/actions-input.enigma2.timeout.description") int timeout) {
handler.sendInfo(timeout, text);
}
@Override
@RuleAction(label = "@text/actions.enigma2.send-warning.label", description = "@text/actions.enigma2.send-warning.description")
@SuppressWarnings("null")
public void sendWarning(
@ActionInput(name = "text", label = "@text/actions-input.enigma2.text.label", description = "@text/actions-input.enigma2.text.description") String text) {
handler.sendWarning(Enigma2BindingConstants.MESSAGE_TIMEOUT, text);
}
@Override
@RuleAction(label = "@text/actions.enigma2.send-warning.label", description = "@text/actions.enigma2.send-warning.description")
@SuppressWarnings("null")
public void sendWarning(
@ActionInput(name = "text", label = "@text/actions-input.enigma2.text.label", description = "@text/actions-input.enigma2.text.description") String text,
@ActionInput(name = "timeout", label = "@text/actions-input.enigma2.timeout.label", description = "@text/actions-input.enigma2.timeout.description") int timeout) {
handler.sendWarning(timeout, text);
}
@Override
@RuleAction(label = "@text/actions.enigma2.send-error.label", description = "@text/actions.enigma2.send-error.description")
@SuppressWarnings("null")
public void sendError(
@ActionInput(name = "text", label = "@text/actions-input.enigma2.text.label", description = "@text/actions-input.enigma2.text.description") String text) {
handler.sendError(Enigma2BindingConstants.MESSAGE_TIMEOUT, text);
}
@Override
@RuleAction(label = "@text/actions.enigma2.send-error.label", description = "@text/actions.enigma2.send-error.description")
@SuppressWarnings("null")
public void sendError(
@ActionInput(name = "text", label = "@text/actions-input.enigma2.text.label", description = "@text/actions-input.enigma2.text.description") String text,
@ActionInput(name = "timeout", label = "@text/actions-input.enigma2.timeout.label", description = "@text/actions-input.enigma2.timeout.description") int timeout) {
handler.sendError(timeout, text);
}
@Override
@RuleAction(label = "@text/actions.enigma2.send-error.label", description = "@text/actions.enigma2.send-question.description")
@SuppressWarnings("null")
public void sendQuestion(
@ActionInput(name = "text", label = "@text/actions-input.enigma2.text.label", description = "@text/actions-input.enigma2.text.description") String text) {
handler.sendQuestion(Enigma2BindingConstants.MESSAGE_TIMEOUT, text);
}
@Override
@RuleAction(label = "@text/actions.enigma2.send-error.label", description = "@text/actions.enigma2.send-question.description")
@SuppressWarnings("null")
public void sendQuestion(
@ActionInput(name = "text", label = "@text/actions-input.enigma2.text.label", description = "@text/actions-input.enigma2.text.description") String text,
@ActionInput(name = "timeout", label = "@text/actions-input.enigma2.timeout.label", description = "@text/actions-input.enigma2.timeout.description") int timeout) {
handler.sendQuestion(timeout, text);
}
// delegation methods for "legacy" rule support
public static void sendRcCommand(@Nullable ThingActions actions, String rcButton) {
invokeMethodOf(actions).sendRcCommand(rcButton);
}
public static void sendInfo(@Nullable ThingActions actions, String info) {
invokeMethodOf(actions).sendInfo(info);
}
public static void sendInfo(@Nullable ThingActions actions, String info, int timeout) {
invokeMethodOf(actions).sendInfo(info, timeout);
}
public static void sendWarning(@Nullable ThingActions actions, String warning) {
invokeMethodOf(actions).sendWarning(warning);
}
public static void sendWarning(@Nullable ThingActions actions, String warning, int timeout) {
invokeMethodOf(actions).sendWarning(warning, timeout);
}
public static void sendError(@Nullable ThingActions actions, String error) {
invokeMethodOf(actions).sendError(error);
}
public static void sendError(@Nullable ThingActions actions, String error, int timeout) {
invokeMethodOf(actions).sendError(error, timeout);
}
public static void sendQuestion(@Nullable ThingActions actions, String text) {
invokeMethodOf(actions).sendQuestion(text);
}
public static void sendQuestion(@Nullable ThingActions actions, String text, int timeout) {
invokeMethodOf(actions).sendQuestion(text, timeout);
}
private static IEnigma2Actions invokeMethodOf(@Nullable ThingActions actions) {
if (actions == null) {
throw new IllegalArgumentException("actions cannot be null");
}
if (actions.getClass().getName().equals(Enigma2Actions.class.getName())) {
if (actions instanceof IEnigma2Actions) {
return (IEnigma2Actions) actions;
} else {
return (IEnigma2Actions) Proxy.newProxyInstance(IEnigma2Actions.class.getClassLoader(),
new Class[] { IEnigma2Actions.class }, (Object proxy, Method method, Object[] args) -> {
Method m = actions.getClass().getDeclaredMethod(method.getName(),
method.getParameterTypes());
return m.invoke(actions, args);
});
}
}
throw new IllegalArgumentException("Actions is not an instance of Enigma2Actions");
}
}

View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.actions;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link IEnigma2Actions} defines the interface for all thing actions supported by the binding.
*
* @author Guido Dolfen - Initial contribution
*/
@NonNullByDefault
public interface IEnigma2Actions {
void sendRcCommand(String rcButton);
void sendInfo(String text);
void sendInfo(String text, int timeout);
void sendWarning(String text);
void sendWarning(String text, int timeout);
void sendError(String text);
void sendError(String text, int timeout);
void sendQuestion(String text);
void sendQuestion(String text, int timeout);
}

View File

@@ -0,0 +1,302 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.handler;
import static org.openhab.binding.enigma2.internal.Enigma2BindingConstants.*;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.enigma2.actions.Enigma2Actions;
import org.openhab.binding.enigma2.internal.Enigma2Client;
import org.openhab.binding.enigma2.internal.Enigma2Configuration;
import org.openhab.binding.enigma2.internal.Enigma2RemoteKey;
import org.openhab.core.library.types.*;
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;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link Enigma2Handler} is responsible for handling commands, which are
* sent to one of the channels.
*
* @author Guido Dolfen - Initial contribution
*/
@NonNullByDefault
public class Enigma2Handler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(Enigma2Handler.class);
private Enigma2Configuration configuration = new Enigma2Configuration();
private Optional<Enigma2Client> enigma2Client = Optional.empty();
private @Nullable ScheduledFuture<?> refreshJob;
private LocalDateTime lastAnswerTime = LocalDateTime.now();
public Enigma2Handler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
configuration = getConfigAs(Enigma2Configuration.class);
if (configuration.host.isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "host must not be empty");
} else if (configuration.timeout <= 0 || configuration.timeout > 300) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"timeout must be between 0 and 300 seconds");
} else if (configuration.refreshInterval <= 0 || configuration.refreshInterval > 3600) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"refreshInterval must be between 0 and 3600 seconds");
}
enigma2Client = Optional.of(new Enigma2Client(configuration.host, configuration.user, configuration.password,
configuration.timeout));
refreshJob = scheduler.scheduleWithFixedDelay(this::refresh, 2, configuration.refreshInterval,
TimeUnit.SECONDS);
}
private void refresh() {
getEnigma2Client().ifPresent(client -> {
boolean online = client.refresh();
if (online) {
updateStatus(ThingStatus.ONLINE);
updateState(CHANNEL_POWER, client.isPower() ? OnOffType.ON : OnOffType.OFF);
updateState(CHANNEL_MUTE, client.isMute() ? OnOffType.ON : OnOffType.OFF);
updateState(CHANNEL_VOLUME, new PercentType(client.getVolume()));
updateState(CHANNEL_CHANNEL, new StringType(client.getChannel()));
updateState(CHANNEL_TITLE, new StringType(client.getTitle()));
updateState(CHANNEL_DESCRIPTION, new StringType(client.getDescription()));
if (lastAnswerTime.isBefore(client.getLastAnswerTime())) {
lastAnswerTime = client.getLastAnswerTime();
updateState(CHANNEL_ANSWER, new StringType(client.getAnswer()));
}
} else {
updateStatus(ThingStatus.OFFLINE);
}
});
}
@Override
public void dispose() {
ScheduledFuture<?> job = this.refreshJob;
if (job != null) {
job.cancel(true);
}
this.refreshJob = null;
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("handleCommand({},{})", channelUID, command);
getEnigma2Client().ifPresent(client -> {
switch (channelUID.getId()) {
case CHANNEL_POWER:
handlePower(channelUID, command, client);
break;
case CHANNEL_CHANNEL:
handleChannel(channelUID, command, client);
break;
case CHANNEL_MEDIA_PLAYER:
handleMediaPlayer(channelUID, command);
break;
case CHANNEL_MEDIA_STOP:
handleMediaStop(channelUID, command);
break;
case CHANNEL_MUTE:
handleMute(channelUID, command, client);
break;
case CHANNEL_VOLUME:
handleVolume(channelUID, command, client);
break;
case CHANNEL_TITLE:
handleTitle(channelUID, command, client);
break;
case CHANNEL_DESCRIPTION:
handleDescription(channelUID, command, client);
break;
case CHANNEL_ANSWER:
handleAnswer(channelUID, command, client);
break;
default:
logger.debug("Channel {} is not supported", channelUID);
break;
}
});
}
private void handleVolume(ChannelUID channelUID, Command command, Enigma2Client client) {
if (command instanceof RefreshType) {
client.refreshVolume();
updateState(channelUID, new PercentType(client.getVolume()));
} else if (command instanceof PercentType) {
client.setVolume(((PercentType) command).intValue());
} else if (command instanceof DecimalType) {
client.setVolume(((DecimalType) command).intValue());
} else {
logger.info("Channel {} only accepts PercentType, DecimalType, RefreshType. Type was {}.", channelUID,
command.getClass());
}
}
private void handleMute(ChannelUID channelUID, Command command, Enigma2Client client) {
if (command instanceof RefreshType) {
client.refreshVolume();
updateState(channelUID, client.isMute() ? OnOffType.ON : OnOffType.OFF);
} else if (OnOffType.ON.equals(command)) {
client.setMute(true);
} else if (OnOffType.OFF.equals(command)) {
client.setMute(false);
} else {
logger.info("Channel {} only accepts OnOffType, RefreshType. Type was {}.", channelUID, command.getClass());
}
}
private void handleAnswer(ChannelUID channelUID, Command command, Enigma2Client client) {
if (command instanceof RefreshType) {
client.refreshAnswer();
if (lastAnswerTime.isBefore(client.getLastAnswerTime())) {
lastAnswerTime = client.getLastAnswerTime();
updateState(channelUID, new StringType(client.getAnswer()));
}
} else {
logger.info("Channel {} only accepts RefreshType. Type was {}.", channelUID, command.getClass());
}
}
private void handleMediaStop(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
return;
} else if (command instanceof OnOffType) {
sendRcCommand(Enigma2RemoteKey.STOP);
} else {
logger.info("Channel {} only accepts OnOffType, RefreshType. Type was {}.", channelUID, command.getClass());
}
}
private void handleMediaPlayer(ChannelUID channelUID, Command command) {
if (RefreshType.REFRESH == command) {
return;
} else if (PlayPauseType.PLAY == command) {
sendRcCommand(Enigma2RemoteKey.PLAY);
} else if (PlayPauseType.PAUSE == command) {
sendRcCommand(Enigma2RemoteKey.PAUSE);
} else if (NextPreviousType.NEXT == command) {
sendRcCommand(Enigma2RemoteKey.FAST_FORWARD);
} else if (NextPreviousType.PREVIOUS == command) {
sendRcCommand(Enigma2RemoteKey.FAST_BACKWARD);
} else {
logger.info("Channel {} only accepts PlayPauseType, NextPreviousType, RefreshType. Type was {}.",
channelUID, command.getClass());
}
}
private void handleChannel(ChannelUID channelUID, Command command, Enigma2Client client) {
if (command instanceof RefreshType) {
client.refreshChannel();
updateState(channelUID, new StringType(client.getChannel()));
} else if (command instanceof StringType) {
client.setChannel(command.toString());
} else {
logger.info("Channel {} only accepts StringType, RefreshType. Type was {}.", channelUID,
command.getClass());
}
}
private void handleTitle(ChannelUID channelUID, Command command, Enigma2Client client) {
if (command instanceof RefreshType) {
client.refreshEpg();
updateState(channelUID, new StringType(client.getTitle()));
} else {
logger.info("Channel {} only accepts RefreshType. Type was {}.", channelUID, command.getClass());
}
}
private void handleDescription(ChannelUID channelUID, Command command, Enigma2Client client) {
if (command instanceof RefreshType) {
client.refreshEpg();
updateState(channelUID, new StringType(client.getDescription()));
} else {
logger.info("Channel {} only accepts RefreshType. Type was {}.", channelUID, command.getClass());
}
}
private void handlePower(ChannelUID channelUID, Command command, Enigma2Client client) {
if (RefreshType.REFRESH == command) {
client.refreshPower();
updateState(channelUID, client.isPower() ? OnOffType.ON : OnOffType.OFF);
} else if (OnOffType.ON == command) {
client.setPower(true);
} else if (OnOffType.OFF == command) {
client.setPower(false);
} else {
logger.info("Channel {} only accepts OnOffType, RefreshType. Type was {}.", channelUID, command.getClass());
}
}
public void sendRcCommand(String rcButton) {
logger.debug("sendRcCommand({})", rcButton);
try {
Enigma2RemoteKey remoteKey = Enigma2RemoteKey.valueOf(rcButton);
sendRcCommand(remoteKey);
} catch (IllegalArgumentException ex) {
logger.warn("{} is not a valid value for button - available are: {}", rcButton,
Stream.of(Enigma2RemoteKey.values()).map(b -> b.name()).collect(Collectors.joining(", ")));
}
}
private void sendRcCommand(Enigma2RemoteKey remoteKey) {
getEnigma2Client().ifPresent(client -> client.sendRcCommand(remoteKey.getValue()));
}
public void sendInfo(int timeout, String text) {
getEnigma2Client().ifPresent(client -> client.sendInfo(timeout, text));
}
public void sendWarning(int timeout, String text) {
getEnigma2Client().ifPresent(client -> client.sendWarning(timeout, text));
}
public void sendError(int timeout, String text) {
getEnigma2Client().ifPresent(client -> client.sendError(timeout, text));
}
public void sendQuestion(int timeout, String text) {
getEnigma2Client().ifPresent(client -> client.sendQuestion(timeout, text));
}
@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(Enigma2Actions.class);
}
/**
* Getter for Test-Injection
*
* @return Enigma2Client.
*/
Optional<Enigma2Client> getEnigma2Client() {
return enigma2Client;
}
}

View File

@@ -0,0 +1,56 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.internal;
import java.util.Collections;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link Enigma2BindingConstants} class defines common constants, which are
* used across the whole binding.
*
* @author Guido Dolfen - Initial contribution
*/
@NonNullByDefault
public class Enigma2BindingConstants {
private static final String BINDING_ID = "enigma2";
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_DEVICE = new ThingTypeUID(BINDING_ID, "device");
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections.singleton(THING_TYPE_DEVICE);
// List of all Channel ids
public static final String CHANNEL_VOLUME = "volume";
public static final String CHANNEL_POWER = "power";
public static final String CHANNEL_MUTE = "mute";
public static final String CHANNEL_CHANNEL = "channel";
public static final String CHANNEL_TITLE = "title";
public static final String CHANNEL_DESCRIPTION = "description";
public static final String CHANNEL_MEDIA_PLAYER = "mediaPlayer";
public static final String CHANNEL_MEDIA_STOP = "mediaStop";
public static final String CHANNEL_ANSWER = "answer";
// List of all configuration parameters
public static final String CONFIG_HOST = "host";
public static final String CONFIG_USER = "user";
public static final String CONFIG_PASSWORD = "password";
public static final String CONFIG_REFRESH = "refreshInterval";
public static final String CONFIG_TIMEOUT = "timeout";
public static final int MESSAGE_TIMEOUT = 30;
}

View File

@@ -0,0 +1,351 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.internal;
import java.io.IOException;
import java.io.StringReader;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.lang.StringUtils;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.util.UrlEncoded;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* The {@link Enigma2Client} class is responsible for communicating with the Enigma2 device.
*
* @see <a href=
* "https://github.com/E2OpenPlugins/e2openplugin-OpenWebif/wiki/OpenWebif-API-documentation">OpenWebif-API-documentation</a>
*
* @author Guido Dolfen - Initial contribution
*/
@NonNullByDefault
public class Enigma2Client {
private final Logger logger = LoggerFactory.getLogger(Enigma2Client.class);
static final String PATH_REMOTE_CONTROL = "/web/remotecontrol?command=";
static final String PATH_POWER = "/web/powerstate";
static final String PATH_VOLUME = "/web/vol";
static final String PATH_SET_VOLUME = "/web/vol?set=set";
static final String PATH_TOGGLE_MUTE = "/web/vol?set=mute";
static final String PATH_TOGGLE_POWER = "/web/powerstate?newstate=0";
static final String PATH_MESSAGE = "/web/message?type=";
static final String PATH_ALL_SERVICES = "/web/getallservices";
static final String PATH_ZAP = "/web/zap?sRef=";
static final String PATH_CHANNEL = "/web/subservices";
static final String PATH_EPG = "/web/epgservicenow?sRef=";
static final String PATH_ANSWER = "/web/messageanswer?getanswer=now";
static final int TYPE_QUESTION = 0;
static final int TYPE_INFO = 1;
static final int TYPE_WARNING = 2;
static final int TYPE_ERROR = 3;
private final Map<String, @Nullable String> channels = new ConcurrentHashMap<>();
private final String host;
private boolean power;
private String channel = "";
private String title = "";
private String description = "";
private String answer = "";
private int volume = 0;
private boolean mute;
private boolean online;
private boolean initialized;
private boolean asking;
private LocalDateTime lastAnswerTime = LocalDateTime.of(2020, 1, 1, 0, 0); // Date in the past
private final Enigma2HttpClient enigma2HttpClient;
private final DocumentBuilderFactory factory;
public Enigma2Client(String host, @Nullable String user, @Nullable String password, int requestTimeout) {
this.enigma2HttpClient = new Enigma2HttpClient(requestTimeout);
this.factory = DocumentBuilderFactory.newInstance();
if (StringUtils.isNotEmpty(user) && StringUtils.isNotEmpty(password)) {
this.host = "http://" + user + ":" + password + "@" + host;
} else {
this.host = "http://" + host;
}
}
public boolean refresh() {
boolean wasOnline = online;
refreshPower();
if (!wasOnline && online) {
// Only refresh all services if the box changed from offline to online and power is on
// because it is a performance intensive action.
refreshAllServices();
}
refreshChannel();
refreshEpg();
refreshVolume();
refreshAnswer();
return online;
}
public void refreshPower() {
Optional<Document> document = transmitWithResult(PATH_POWER);
if (document.isPresent()) {
online = true;
processPowerResult(document.get());
} else {
online = false;
power = false;
}
initialized = true;
}
public void refreshAllServices() {
if (power || channels.isEmpty()) {
transmitWithResult(PATH_ALL_SERVICES).ifPresent(this::processAllServicesResult);
}
}
public void refreshChannel() {
if (power) {
transmitWithResult(PATH_CHANNEL).ifPresent(this::processChannelResult);
}
}
public void refreshAnswer() {
if (asking) {
transmitWithResult(PATH_ANSWER).ifPresent(this::processAnswerResult);
}
}
public void refreshVolume() {
if (power) {
transmitWithResult(PATH_VOLUME).ifPresent(this::processVolumeResult);
}
}
public void refreshEpg() {
if (power) {
Optional.ofNullable(channels.get(channel))
.flatMap(name -> transmitWithResult(PATH_EPG + UrlEncoded.encodeString(name)))
.ifPresent(this::processEpgResult);
}
}
private Optional<Document> transmitWithResult(String path) {
try {
Optional<String> xml = transmit(path);
if (xml.isPresent()) {
DocumentBuilder builder = factory.newDocumentBuilder();
return Optional.ofNullable(builder.parse(new InputSource(new StringReader(xml.get()))));
}
return Optional.empty();
} catch (IOException | SAXException | ParserConfigurationException | IllegalArgumentException e) {
if (online || !initialized) {
logger.debug("Error on transmit {}{}.", host, path, e);
}
return Optional.empty();
}
}
private Optional<String> transmit(String path) {
String url = host + path;
try {
logger.debug("Transmitting {}", url);
String result = getEnigma2HttpClient().get(url);
logger.debug("Transmitting result is {}", result);
return Optional.ofNullable(result);
} catch (IOException | IllegalArgumentException e) {
if (online || !initialized) {
logger.debug("Error on transmit {}.", url, e);
}
return Optional.empty();
}
}
public void setMute(boolean mute) {
refreshVolume();
if (this.mute != mute) {
transmitWithResult(PATH_TOGGLE_MUTE).ifPresent(this::processVolumeResult);
}
}
public void setPower(boolean power) {
refreshPower();
if (this.power != power) {
transmitWithResult(PATH_TOGGLE_POWER).ifPresent(this::processPowerResult);
}
}
public void setVolume(int volume) {
transmitWithResult(PATH_SET_VOLUME + volume).ifPresent(this::processVolumeResult);
}
public void setChannel(String name) {
if (channels.containsKey(name)) {
String id = channels.get(name);
transmitWithResult(PATH_ZAP + UrlEncoded.encodeString(id)).ifPresent(document -> channel = name);
} else {
logger.warn("Channel {} not found.", name);
}
}
public void sendRcCommand(int key) {
transmit(PATH_REMOTE_CONTROL + key);
}
public void sendError(int timeout, String text) {
sendMessage(TYPE_ERROR, timeout, text);
}
public void sendWarning(int timeout, String text) {
sendMessage(TYPE_WARNING, timeout, text);
}
public void sendInfo(int timeout, String text) {
sendMessage(TYPE_INFO, timeout, text);
}
public void sendQuestion(int timeout, String text) {
asking = true;
sendMessage(TYPE_QUESTION, timeout, text);
}
private void sendMessage(int type, int timeout, String text) {
transmit(PATH_MESSAGE + type + "&timeout=" + timeout + "&text=" + UrlEncoded.encodeString(text));
}
private void processPowerResult(Document document) {
power = !getBoolean(document, "e2instandby");
if (!power) {
title = "";
description = "";
channel = "";
}
}
private void processChannelResult(Document document) {
channel = getString(document, "e2servicename");
// Add channel-Reference-ID if not known
if (!channels.containsKey(channel)) {
channels.put(channel, getString(document, "e2servicereference"));
}
}
private void processAnswerResult(Document document) {
if (asking) {
boolean state = getBoolean(document, "e2state");
if (state) {
String[] text = getString(document, "e2statetext").split(" ");
answer = text[text.length - 1].replace("!", "");
asking = false;
lastAnswerTime = LocalDateTime.now();
}
}
}
private void processVolumeResult(Document document) {
volume = getInt(document, "e2current");
mute = getBoolean(document, "e2ismuted");
}
private void processEpgResult(Document document) {
title = getString(document, "e2eventtitle");
description = getString(document, "e2eventdescription");
}
private void processAllServicesResult(Document document) {
NodeList bouquetList = document.getElementsByTagName("e2bouquet");
channels.clear();
for (int i = 0; i < bouquetList.getLength(); i++) {
Element bouquet = (Element) bouquetList.item(i);
NodeList serviceList = bouquet.getElementsByTagName("e2service");
for (int j = 0; j < serviceList.getLength(); j++) {
Element service = (Element) serviceList.item(j);
String id = service.getElementsByTagName("e2servicereference").item(0).getTextContent();
String name = service.getElementsByTagName("e2servicename").item(0).getTextContent();
channels.put(name, id);
}
}
}
private String getString(Document document, String elementId) {
return Optional.ofNullable(document.getElementsByTagName(elementId)).map(nodeList -> nodeList.item(0))
.map(Node::getTextContent).map(String::trim).orElse("");
}
private boolean getBoolean(Document document, String elementId) {
return Boolean.parseBoolean(getString(document, elementId));
}
private int getInt(Document document, String elementId) {
try {
return Integer.parseInt(getString(document, elementId));
} catch (NumberFormatException e) {
return 0;
}
}
public int getVolume() {
return volume;
}
public boolean isMute() {
return mute;
}
public boolean isPower() {
return power;
}
public LocalDateTime getLastAnswerTime() {
return lastAnswerTime;
}
public String getChannel() {
return channel;
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
public String getAnswer() {
return answer;
}
public Collection<String> getChannels() {
return channels.keySet();
}
/**
* Getter for Test-Injection
*
* @return HttpGet.
*/
Enigma2HttpClient getEnigma2HttpClient() {
return enigma2HttpClient;
}
}

View File

@@ -0,0 +1,45 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link Enigma2Configuration} class contains fields mapping thing configuration parameters.
*
* @author Guido Dolfen - Initial contribution
*/
@NonNullByDefault
public class Enigma2Configuration {
/**
* Hostname or IP address of the Enigma2 device.
*/
public String host = "";
/**
* The refresh interval in seconds.
*/
public int refreshInterval = 5;
/**
* The refresh interval in seconds.
*/
public int timeout = 5;
/**
* The Username of the Enigma2 Web API.
*/
public String user = "";
/**
* The Password of the Enigma2 Web API.
*/
public String password = "";
}

View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.internal;
import static org.openhab.binding.enigma2.internal.Enigma2BindingConstants.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.enigma2.handler.Enigma2Handler;
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.Component;
/**
* The {@link Enigma2HandlerFactory} is responsible for creating things and thing
* handlers.
*
* @author Guido Dolfen - Initial contribution
*/
@NonNullByDefault
@Component(configurationPid = "binding.enigma2", service = ThingHandlerFactory.class)
public class Enigma2HandlerFactory extends BaseThingHandlerFactory {
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
@Override
protected @Nullable ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (THING_TYPE_DEVICE.equals(thingTypeUID)) {
return new Enigma2Handler(thing);
}
return null;
}
}

View File

@@ -0,0 +1,42 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.internal;
import java.io.IOException;
import java.util.regex.Pattern;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.io.net.http.HttpUtil;
/**
* The {@link Enigma2HttpClient} class is responsible for sending HTTP-Get requests to the Enigma2 device.
* It is devided from {@link Enigma2Client} for better testing purpose.
*
* @author Guido Dolfen - Initial contribution
*/
@NonNullByDefault
public class Enigma2HttpClient {
public static final Pattern PATTERN = Pattern
.compile("[^\\u0009\\u000A\\u000D\\u0020-\\uD7FF\\uE000-\\uFFFD\\u10000-\\u10FFF]+");
private final int timeout;
public Enigma2HttpClient(int timeout) {
this.timeout = timeout;
}
public String get(String url) throws IOException, IllegalArgumentException {
String xml = HttpUtil.executeUrl("GET", url, timeout * 1000);
// remove some unsupported xml-characters
return PATTERN.matcher(xml).replaceAll("");
}
}

View File

@@ -0,0 +1,87 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* The {@link Enigma2RemoteKey} class defines the remote keys of an enigma2 device
* used across the whole binding.
*
* @author Guido Dolfen - Initial contribution
*/
@NonNullByDefault
public enum Enigma2RemoteKey {
POWER(116),
KEY_0(11),
KEY_1(2),
KEY_2(3),
KEY_3(4),
KEY_4(5),
KEY_5(6),
KEY_6(7),
KEY_7(8),
KEY_8(9),
KEY_9(10),
ARROW_LEFT(412),
ARROW_RIGHT(407),
VOLUME_DOWN(114),
VOLUME_UP(115),
MUTE(113),
CHANNEL_UP(402),
CHANNEL_DOWN(403),
LEFT(105),
RIGHT(106),
UP(103),
DOWN(108),
OK(352),
EXIT(174),
RED(398),
GREEN(399),
YELLOW(400),
BLUE(401),
PLAY(207),
PAUSE(119),
STOP(128),
RECORD(167),
FAST_FORWARD(208),
FAST_BACKWARD(168),
TV(377),
RADIO(385),
AUDIO(392),
VIDEO(393),
TEXT(388),
INFO(358),
MENU(139),
HELP(138),
SUBTITLE(370),
EPG(358);
private final int value;
Enigma2RemoteKey(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}

View File

@@ -0,0 +1,112 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.internal.discovery;
import java.io.IOException;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import javax.jmdns.ServiceInfo;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.enigma2.internal.Enigma2BindingConstants;
import org.openhab.binding.enigma2.internal.Enigma2HttpClient;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.mdns.MDNSDiscoveryParticipant;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link Enigma2DiscoveryParticipant} is responsible processing the
* results of searches for mDNS services of type _http._tcp.local. and finding a webinterface
*
* @author Guido Dolfen - Initial contribution
*/
@NonNullByDefault
@Component(service = MDNSDiscoveryParticipant.class, immediate = true)
public class Enigma2DiscoveryParticipant implements MDNSDiscoveryParticipant {
private final Logger logger = LoggerFactory.getLogger(Enigma2DiscoveryParticipant.class);
@Override
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
return Enigma2BindingConstants.SUPPORTED_THING_TYPES_UIDS;
}
@Override
public @Nullable DiscoveryResult createResult(ServiceInfo info) {
logger.debug("ServiceInfo {}", info);
String ipAddress = getIPAddress(info);
if (ipAddress != null && isEnigma2Device(ipAddress)) {
logger.debug("Enigma2 device discovered: IP-Adress={}, name={}", ipAddress, info.getName());
ThingUID uid = getThingUID(info);
if (uid != null) {
Map<String, Object> properties = new HashMap<>();
properties.put(Enigma2BindingConstants.CONFIG_HOST, ipAddress);
properties.put(Enigma2BindingConstants.CONFIG_REFRESH, 5);
properties.put(Enigma2BindingConstants.CONFIG_TIMEOUT, 5);
return DiscoveryResultBuilder.create(uid).withProperties(properties).withLabel(info.getName()).build();
}
}
return null;
}
@Override
public @Nullable ThingUID getThingUID(ServiceInfo info) {
logger.debug("ServiceInfo {}", info);
String ipAddress = getIPAddress(info);
if (ipAddress != null) {
return new ThingUID(Enigma2BindingConstants.THING_TYPE_DEVICE, ipAddress.replace(".", "_"));
}
return null;
}
@Override
public String getServiceType() {
return "_http._tcp.local.";
}
private boolean isEnigma2Device(String ipAddress) {
try {
return getEnigma2HttpClient().get("http://" + ipAddress + "/web/about").contains("e2enigmaversion");
} catch (IOException ignore) {
return false;
}
}
private @Nullable String getIPAddress(ServiceInfo info) {
InetAddress[] addresses = info.getInet4Addresses();
if (addresses.length > 1) {
logger.debug("Enigma2 device {} reports multiple addresses - using the first one! {}", info.getName(),
addresses);
}
return Stream.of(addresses).findFirst().map(InetAddress::getHostAddress).orElse(null);
}
/**
* Getter for Test-Injection
*
* @return HttpGet.
*/
Enigma2HttpClient getEnigma2HttpClient() {
return new Enigma2HttpClient(5);
}
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="enigma2" 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>Enigma2 Binding</name>
<description>This is the binding for Enigma2.</description>
<author>Guido Dolfen</author>
</binding:binding>

View File

@@ -0,0 +1,36 @@
# FIXME: please substitute the xx_XX with a proper locale, ie. de_DE
# FIXME: please do not add the file to the repo if you add or change no content
# binding
binding.enigma2.name = Enigma2 Binding
binding.enigma2.description = This is the binding for Enigma2
# thing types
thing-type.enigma2.device.label = Enigma2
thing-type.enigma2.device.description = The Thing represents an Enigma2 device
# thing type config description
thing-type.config.enigma2.host.label = Host Address
thing-type.config.enigma2.host.description = Hostname or IP address of the Enigma2 device
# channel types
channel-type.enigma2.power.label = Power
channel-type.enigma2.power.description = Setting the power to on/off.
# actions
action.enigma2.send-rc-button.label=sendRcCommand
action.enigma2.send-rc-button.description=Send an Remote Control Command
action-input.enigma2.rc-button.label=rcButton
action-input.enigma2.rc-button.description=The Remote Control Button
action.enigma2.send-info.label=sendInfo
action.enigma2.send-info.description=Send an info message to the TV screen
action.enigma2.send-warning.label=sendWarning
action.enigma2.send-warning.description=Send an warning message to the TV screen
action.enigma2.send-error.label=sendError
action.enigma2.send-error.description=Send an error message to the TV screen
action.enigma2.send-question.label=sendQuestion
action.enigma2.send-question.description=Send a question message to the TV screen
action-input.enigma2.text.label=text
action-input.enigma2.text.description=The message text
action-input.enigma2.timeout.label=timeout
action-input.enigma2.timeout.description=The timeout in seconds

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="enigma2"
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="device">
<label>Enigma2</label>
<description>The Thing represents an Enigma2 device</description>
<channels>
<channel id="power" typeId="powerType"/>
<channel id="mute" typeId="muteType"/>
<channel id="volume" typeId="volumeType"/>
<channel id="channel" typeId="channelType"/>
<channel id="title" typeId="titleType"/>
<channel id="description" typeId="descriptionType"/>
<channel id="mediaPlayer" typeId="mediaPlayerType"/>
<channel id="mediaStop" typeId="mediaStopType"/>
<channel id="answer" typeId="answerType"/>
</channels>
<config-description>
<parameter name="host" type="text" required="true">
<context>network-address</context>
<label>Host Address</label>
<description>Hostname or IP address of the Enigma2 device.</description>
</parameter>
<parameter name="refreshInterval" type="integer" required="false" min="1" max="3600" unit="s">
<label>Refresh Interval</label>
<description>The refresh interval in seconds.</description>
<default>5</default>
</parameter>
<parameter name="timeout" type="integer" required="false" min="1" max="300" unit="s">
<label>Timeout</label>
<description>The timeout for reading from the device in seconds.</description>
<default>5</default>
</parameter>
<parameter name="user" type="text" required="false">
<label>Username</label>
<description>The Username of the Enigma2 Web API.</description>
</parameter>
<parameter name="password" type="text" required="false">
<context>password</context>
<label>Password</label>
<description>The Password of the Enigma2 Web API.</description>
</parameter>
</config-description>
</thing-type>
<channel-type id="powerType">
<item-type>Switch</item-type>
<label>Power</label>
<description>Setting the power to on/off.</description>
</channel-type>
<channel-type id="muteType">
<item-type>Switch</item-type>
<label>Mute</label>
<description>Current Mute Setting</description>
<category>SoundVolume</category>
</channel-type>
<channel-type id="volumeType">
<item-type>Dimmer</item-type>
<label>Volume</label>
<description>Current Volume Setting</description>
<category>SoundVolume</category>
<state min="0" max="100" step="5"></state>
</channel-type>
<channel-type id="channelType">
<item-type>String</item-type>
<label>Channel</label>
<description>Current Channel</description>
</channel-type>
<channel-type id="titleType">
<item-type>String</item-type>
<label>Title</label>
<description>Current Title of the current Channel</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="descriptionType">
<item-type>String</item-type>
<label>Description</label>
<description>Current Description of the current Channel</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="mediaPlayerType">
<item-type>Player</item-type>
<label>Media Control</label>
<description>Control media (e.g. audio or video) playback</description>
<category>MediaControl</category>
</channel-type>
<channel-type id="mediaStopType">
<item-type>Switch</item-type>
<label>Stop</label>
<description>Stop Playback</description>
</channel-type>
<channel-type id="answerType">
<item-type>String</item-type>
<label>Answer</label>
<description>Receives an answer to a send question of the device</description>
<state readOnly="true"></state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,184 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.actions;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Before;
import org.junit.Test;
import org.openhab.binding.enigma2.handler.Enigma2Handler;
import org.openhab.binding.enigma2.internal.Enigma2BindingConstants;
/**
* The {@link Enigma2ActionsTest} class is responsible for testing {@link Enigma2Actions}.
*
* @author Guido Dolfen - Initial contribution
*/
@SuppressWarnings("null")
@NonNullByDefault
public class Enigma2ActionsTest {
@Nullable
private Enigma2Actions enigma2Actions;
@Nullable
private Enigma2Handler enigma2Handler;
public static final String SOME_TEXT = "some Text";
@Before
public void setUp() {
enigma2Handler = mock(Enigma2Handler.class);
enigma2Actions = new Enigma2Actions();
enigma2Actions.setThingHandler(enigma2Handler);
}
@Test
public void testGetThingHandler() {
assertThat(enigma2Actions.getThingHandler(), is(enigma2Handler));
}
@Test
public void testSendRcCommand() {
enigma2Actions.sendRcCommand("KEY_1");
verify(enigma2Handler).sendRcCommand("KEY_1");
}
@Test
public void testSendInfo() {
enigma2Actions.sendInfo(SOME_TEXT);
verify(enigma2Handler).sendInfo(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testSendInfoTimeout() {
enigma2Actions.sendInfo(SOME_TEXT, 10);
verify(enigma2Handler).sendInfo(10, SOME_TEXT);
}
@Test
public void testSendError() {
enigma2Actions.sendError(SOME_TEXT);
verify(enigma2Handler).sendError(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testSendErrorTimeout() {
enigma2Actions.sendError(SOME_TEXT, 10);
verify(enigma2Handler).sendError(10, SOME_TEXT);
}
@Test
public void testSendWarning() {
enigma2Actions.sendWarning(SOME_TEXT);
verify(enigma2Handler).sendWarning(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testSendWarningTimeout() {
enigma2Actions.sendWarning(SOME_TEXT, 10);
verify(enigma2Handler).sendWarning(10, SOME_TEXT);
}
@Test
public void testSendQuestion() {
enigma2Actions.sendQuestion(SOME_TEXT);
verify(enigma2Handler).sendQuestion(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testSendQuestionTimeout() {
enigma2Actions.sendQuestion(SOME_TEXT, 10);
verify(enigma2Handler).sendQuestion(10, SOME_TEXT);
}
@Test
public void testSendRcCommandStatic() {
Enigma2Actions.sendRcCommand(enigma2Actions, "KEY_1");
verify(enigma2Handler).sendRcCommand("KEY_1");
}
@Test(expected = IllegalArgumentException.class)
public void testSendRcCommandStaticWithException() {
Enigma2Actions.sendRcCommand(null, "KEY_1");
}
@Test
public void testSendInfoStatic() {
Enigma2Actions.sendInfo(enigma2Actions, SOME_TEXT);
verify(enigma2Handler).sendInfo(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testSendInfoTimeoutStatic() {
Enigma2Actions.sendInfo(enigma2Actions, SOME_TEXT, 10);
verify(enigma2Handler).sendInfo(10, SOME_TEXT);
}
@Test(expected = IllegalArgumentException.class)
public void testSendInfoStaticWithException() {
Enigma2Actions.sendInfo(null, SOME_TEXT);
}
@Test
public void testSendErrorStatic() {
Enigma2Actions.sendError(enigma2Actions, SOME_TEXT);
verify(enigma2Handler).sendError(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testSendErrorTimeoutStatic() {
Enigma2Actions.sendError(enigma2Actions, SOME_TEXT, 10);
verify(enigma2Handler).sendError(10, SOME_TEXT);
}
@Test(expected = IllegalArgumentException.class)
public void testSendErrorStaticWithException() {
Enigma2Actions.sendError(null, SOME_TEXT);
}
@Test
public void testSendWarningStatic() {
Enigma2Actions.sendWarning(enigma2Actions, SOME_TEXT);
verify(enigma2Handler).sendWarning(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testSendWarningTimeoutStatic() {
Enigma2Actions.sendWarning(enigma2Actions, SOME_TEXT, 10);
verify(enigma2Handler).sendWarning(10, SOME_TEXT);
}
@Test(expected = IllegalArgumentException.class)
public void testSendWarningStaticWithException() {
Enigma2Actions.sendWarning(null, SOME_TEXT);
}
@Test
public void testSendQuestionStatic() {
Enigma2Actions.sendQuestion(enigma2Actions, SOME_TEXT);
verify(enigma2Handler).sendQuestion(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testSendQuestionTimeoutStatic() {
Enigma2Actions.sendQuestion(enigma2Actions, SOME_TEXT, 10);
verify(enigma2Handler).sendQuestion(10, SOME_TEXT);
}
@Test(expected = IllegalArgumentException.class)
public void testSendQuestionStaticWithException() {
Enigma2Actions.sendQuestion(null, SOME_TEXT);
}
}

View File

@@ -0,0 +1,381 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.handler;
import static org.eclipse.jdt.annotation.Checks.requireNonNull;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Before;
import org.junit.Test;
import org.openhab.binding.enigma2.actions.Enigma2Actions;
import org.openhab.binding.enigma2.internal.Enigma2BindingConstants;
import org.openhab.binding.enigma2.internal.Enigma2Client;
import org.openhab.binding.enigma2.internal.Enigma2Configuration;
import org.openhab.binding.enigma2.internal.Enigma2RemoteKey;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.*;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.binding.ThingHandlerCallback;
import org.openhab.core.types.RefreshType;
/**
* The {@link Enigma2HandlerTest} class is responsible for testing {@link Enigma2Handler}.
*
* @author Guido Dolfen - Initial contribution
*/
@SuppressWarnings({ "null", "unchecked" })
@NonNullByDefault
public class Enigma2HandlerTest {
public static final String CHANNEL_UID_PREFIX = "enigma2:device:192_168_0_3:";
public static final String SOME_TEXT = "some Text";
@Nullable
private Enigma2Handler enigma2Handler;
@Nullable
private Enigma2Client enigma2Client;
@Nullable
private Thing thing;
@Nullable
private Configuration configuration;
@Nullable
private ThingHandlerCallback callback;
@Before
public void setUp() {
enigma2Client = mock(Enigma2Client.class);
thing = mock(Thing.class);
callback = mock(ThingHandlerCallback.class);
configuration = mock(Configuration.class);
when(thing.getConfiguration()).thenReturn(requireNonNull(configuration));
when(configuration.as(Enigma2Configuration.class)).thenReturn(new Enigma2Configuration());
enigma2Handler = spy(new Enigma2Handler(requireNonNull(thing)));
enigma2Handler.setCallback(callback);
when(enigma2Handler.getEnigma2Client()).thenReturn(Optional.of(requireNonNull(enigma2Client)));
}
@Test
public void testSendRcCommand() {
enigma2Handler.sendRcCommand("KEY_1");
verify(enigma2Client).sendRcCommand(Enigma2RemoteKey.KEY_1.getValue());
}
@Test
public void testSendInfo() {
enigma2Handler.sendInfo(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
verify(enigma2Client).sendInfo(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testSendWarning() {
enigma2Handler.sendWarning(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
verify(enigma2Client).sendWarning(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testSendError() {
enigma2Handler.sendError(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
verify(enigma2Client).sendError(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testSendQuestion() {
enigma2Handler.sendQuestion(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
verify(enigma2Client).sendQuestion(Enigma2BindingConstants.MESSAGE_TIMEOUT, SOME_TEXT);
}
@Test
public void testGetEnigma2Client() {
enigma2Handler = new Enigma2Handler(requireNonNull(thing));
assertThat(enigma2Handler.getEnigma2Client(), is(Optional.empty()));
}
@Test
public void testGetServices() {
enigma2Handler = new Enigma2Handler(requireNonNull(thing));
assertThat(enigma2Handler.getServices(), contains(Enigma2Actions.class));
}
@Test
public void testSendRcCommandUnsupported() {
enigma2Handler.sendRcCommand("KEY_X");
verifyNoInteractions(enigma2Client);
}
@Test
public void testHandleCommandPowerRefreshFalse() {
when(enigma2Client.isPower()).thenReturn(false);
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_POWER);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verify(enigma2Client).refreshPower();
verify(callback).stateUpdated(channelUID, OnOffType.OFF);
}
@Test
public void testHandleCommandPowerRefreshTrue() {
when(enigma2Client.isPower()).thenReturn(true);
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_POWER);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verify(enigma2Client).refreshPower();
verify(callback).stateUpdated(channelUID, OnOffType.ON);
}
@Test
public void testHandleCommandPowerOn() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_POWER);
enigma2Handler.handleCommand(channelUID, OnOffType.ON);
verify(enigma2Client).setPower(true);
}
@Test
public void testHandleCommandPowerOff() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_POWER);
enigma2Handler.handleCommand(channelUID, OnOffType.OFF);
verify(enigma2Client).setPower(false);
}
@Test
public void testHandleCommandPowerUnsupported() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_POWER);
enigma2Handler.handleCommand(channelUID, PlayPauseType.PAUSE);
verifyNoInteractions(enigma2Client);
}
@Test
public void testHandleCommandChannelRefresh() {
when(enigma2Client.getChannel()).thenReturn(SOME_TEXT);
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_CHANNEL);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verify(enigma2Client).refreshChannel();
verify(callback).stateUpdated(channelUID, new StringType(SOME_TEXT));
}
@Test
public void testHandleCommandMuteRefreshFalse() {
when(enigma2Client.isMute()).thenReturn(false);
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MUTE);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verify(enigma2Client).refreshVolume();
verify(callback).stateUpdated(channelUID, OnOffType.OFF);
}
@Test
public void testHandleCommandMuteRefreshTrue() {
when(enigma2Client.isMute()).thenReturn(true);
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MUTE);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verify(enigma2Client).refreshVolume();
verify(callback).stateUpdated(channelUID, OnOffType.ON);
}
@Test
public void testHandleCommandMuteOn() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MUTE);
enigma2Handler.handleCommand(channelUID, OnOffType.ON);
verify(enigma2Client).setMute(true);
}
@Test
public void testHandleCommandMuteOff() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MUTE);
enigma2Handler.handleCommand(channelUID, OnOffType.OFF);
verify(enigma2Client).setMute(false);
}
@Test
public void testHandleCommandMuteUnsupported() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MUTE);
enigma2Handler.handleCommand(channelUID, PlayPauseType.PAUSE);
verifyNoInteractions(enigma2Client);
}
@Test
public void testHandleCommandChannelString() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_CHANNEL);
enigma2Handler.handleCommand(channelUID, new StringType(SOME_TEXT));
verify(enigma2Client).setChannel(SOME_TEXT);
}
@Test
public void testHandleCommandChannelUnsupported() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_CHANNEL);
enigma2Handler.handleCommand(channelUID, PlayPauseType.PAUSE);
verifyNoInteractions(enigma2Client);
}
@Test
public void testHandleCommandMediaPlayerRefresh() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MEDIA_PLAYER);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verifyNoInteractions(enigma2Client);
}
@Test
public void testHandleCommandMediaPlay() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MEDIA_PLAYER);
enigma2Handler.handleCommand(channelUID, PlayPauseType.PLAY);
verify(enigma2Client).sendRcCommand(Enigma2RemoteKey.PLAY.getValue());
}
@Test
public void testHandleCommandMediaPause() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MEDIA_PLAYER);
enigma2Handler.handleCommand(channelUID, PlayPauseType.PAUSE);
verify(enigma2Client).sendRcCommand(Enigma2RemoteKey.PAUSE.getValue());
}
@Test
public void testHandleCommandMediaNext() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MEDIA_PLAYER);
enigma2Handler.handleCommand(channelUID, NextPreviousType.NEXT);
verify(enigma2Client).sendRcCommand(Enigma2RemoteKey.FAST_FORWARD.getValue());
}
@Test
public void testHandleCommandMediaPrevious() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MEDIA_PLAYER);
enigma2Handler.handleCommand(channelUID, NextPreviousType.PREVIOUS);
verify(enigma2Client).sendRcCommand(Enigma2RemoteKey.FAST_BACKWARD.getValue());
}
@Test
public void testHandleCommandMediaPlayerUnsupported() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MEDIA_PLAYER);
enigma2Handler.handleCommand(channelUID, OnOffType.ON);
verifyNoInteractions(enigma2Client);
}
@Test
public void testHandleCommandMediaStopRefresh() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MEDIA_STOP);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verifyNoInteractions(enigma2Client);
}
@Test
public void testHandleCommandMediaStopOn() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MEDIA_STOP);
enigma2Handler.handleCommand(channelUID, OnOffType.ON);
verify(enigma2Client).sendRcCommand(Enigma2RemoteKey.STOP.getValue());
}
@Test
public void testHandleCommandMediaStopOff() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MEDIA_STOP);
enigma2Handler.handleCommand(channelUID, OnOffType.OFF);
verify(enigma2Client).sendRcCommand(Enigma2RemoteKey.STOP.getValue());
}
@Test
public void testHandleCommandMediaStopUnsupported() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_MEDIA_STOP);
enigma2Handler.handleCommand(channelUID, PlayPauseType.PAUSE);
verifyNoInteractions(enigma2Client);
}
@Test
public void testHandleCommandTitleUnsupported() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_TITLE);
enigma2Handler.handleCommand(channelUID, PlayPauseType.PAUSE);
verifyNoInteractions(enigma2Client);
}
@Test
public void testHandleCommandTitleRefresh() {
when(enigma2Client.getTitle()).thenReturn(SOME_TEXT);
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_TITLE);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verify(enigma2Client).refreshEpg();
verify(callback).stateUpdated(channelUID, new StringType(SOME_TEXT));
}
@Test
public void testHandleCommandAnswerUnsupported() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_ANSWER);
enigma2Handler.handleCommand(channelUID, PlayPauseType.PAUSE);
verifyNoInteractions(enigma2Client);
}
@Test
public void testHandleCommandAnswerRefresh() {
when(enigma2Client.getAnswer()).thenReturn(SOME_TEXT);
when(enigma2Client.getLastAnswerTime()).thenReturn(LocalDateTime.now().plus(1, ChronoUnit.SECONDS));
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_ANSWER);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verify(enigma2Client).refreshAnswer();
verify(callback).stateUpdated(channelUID, new StringType(SOME_TEXT));
}
@Test
public void testHandleCommandAnswerRefreshFalse() {
when(enigma2Client.getAnswer()).thenReturn(SOME_TEXT);
when(enigma2Client.getLastAnswerTime()).thenReturn(LocalDateTime.of(2020, 1, 1, 0, 0));
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_ANSWER);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verify(enigma2Client).refreshAnswer();
verifyNoInteractions(callback);
}
@Test
public void testHandleCommandDescriptionUnsupported() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_DESCRIPTION);
enigma2Handler.handleCommand(channelUID, PlayPauseType.PAUSE);
verifyNoInteractions(enigma2Client);
}
@Test
public void testHandleCommandDescriptionRefresh() {
when(enigma2Client.getDescription()).thenReturn(SOME_TEXT);
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_DESCRIPTION);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verify(enigma2Client).refreshEpg();
verify(callback).stateUpdated(channelUID, new StringType(SOME_TEXT));
}
@Test
public void testHandleCommandVolumeRefresh() {
when(enigma2Client.getVolume()).thenReturn(35);
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_VOLUME);
enigma2Handler.handleCommand(channelUID, RefreshType.REFRESH);
verify(enigma2Client).refreshVolume();
verify(callback).stateUpdated(channelUID, new PercentType(35));
}
@Test
public void testHandleCommandVolumePercent() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_VOLUME);
enigma2Handler.handleCommand(channelUID, new PercentType(30));
verify(enigma2Client).setVolume(30);
}
@Test
public void testHandleCommandVolumeDecimal() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_VOLUME);
enigma2Handler.handleCommand(channelUID, new DecimalType(40));
verify(enigma2Client).setVolume(40);
}
@Test
public void testHandleCommandVolumeUnsupported() {
ChannelUID channelUID = new ChannelUID(CHANNEL_UID_PREFIX + Enigma2BindingConstants.CHANNEL_VOLUME);
enigma2Handler.handleCommand(channelUID, PlayPauseType.PAUSE);
verifyNoInteractions(enigma2Client);
}
}

View File

@@ -0,0 +1,323 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.internal;
import static org.eclipse.jdt.annotation.Checks.requireNonNull;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.io.IOException;
import java.time.LocalDateTime;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Before;
import org.junit.Test;
/**
* The {@link Enigma2ClientTest} class is responsible for testing {@link Enigma2Client}.
*
* @author Guido Dolfen - Initial contribution
*/
@SuppressWarnings({ "null" })
@NonNullByDefault
public class Enigma2ClientTest {
public static final String HOST = "http://user:password@localhost:8080";
public static final String SOME_TEXT = "some Text";
public static final String SOME_TEXT_ENCODED = "some+Text";
@Nullable
private Enigma2Client enigma2Client;
@Nullable
private Enigma2HttpClient enigma2HttpClient;
@Before
public void setUp() throws IOException {
enigma2HttpClient = mock(Enigma2HttpClient.class);
enigma2Client = spy(new Enigma2Client("localhost:8080", "user", "password", 5));
when(enigma2Client.getEnigma2HttpClient()).thenReturn(requireNonNull(enigma2HttpClient));
when(enigma2HttpClient.get(anyString())).thenReturn("<emptyResult/>");
}
@Test
public void testSetPowerFalse() throws IOException {
whenStandby("true");
enigma2Client.setPower(false);
verify(enigma2HttpClient).get(HOST + Enigma2Client.PATH_POWER);
verifyNoMoreInteractions(enigma2HttpClient);
}
@Test
public void testSetPower() throws IOException {
whenStandby("true");
enigma2Client.setPower(true);
verify(enigma2HttpClient).get(HOST + Enigma2Client.PATH_TOGGLE_POWER);
}
@Test
public void testSetVolume() throws IOException {
enigma2Client.setVolume(20);
verify(enigma2HttpClient).get(HOST + Enigma2Client.PATH_SET_VOLUME + 20);
}
@Test
public void testSetChannel() throws IOException {
whenStandby("false");
whenAllServices();
enigma2Client.refreshPower();
enigma2Client.refreshAllServices();
enigma2Client.setChannel("Channel 3");
verify(enigma2HttpClient).get(HOST + Enigma2Client.PATH_ZAP + 3);
}
@Test
public void testSetChannelUnknown() throws IOException {
enigma2Client.setChannel("Channel 3");
verifyNoInteractions(enigma2HttpClient);
}
@Test
public void testSetMuteFalse() throws IOException {
whenStandby("false");
whenVolume("10", false);
enigma2Client.refreshPower();
enigma2Client.setMute(false);
verify(enigma2HttpClient).get(HOST + Enigma2Client.PATH_POWER);
verify(enigma2HttpClient).get(HOST + Enigma2Client.PATH_VOLUME);
verifyNoMoreInteractions(enigma2HttpClient);
}
@Test
public void testSetMute() throws IOException {
whenStandby("false");
whenVolume("10", false);
enigma2Client.refreshPower();
enigma2Client.setMute(true);
verify(enigma2HttpClient).get(HOST + Enigma2Client.PATH_TOGGLE_MUTE);
}
@Test
public void testSendRcCommand() throws IOException {
enigma2Client.sendRcCommand(2);
verify(enigma2HttpClient).get(HOST + Enigma2Client.PATH_REMOTE_CONTROL + 2);
}
@Test
public void testSendError() throws IOException {
enigma2Client.sendError(20, SOME_TEXT);
verify(enigma2HttpClient).get(HOST + "/web/message?type=3&timeout=20&text=" + SOME_TEXT_ENCODED);
}
@Test
public void testSendWarning() throws IOException {
enigma2Client.sendWarning(35, SOME_TEXT);
verify(enigma2HttpClient).get(HOST + "/web/message?type=2&timeout=35&text=" + SOME_TEXT_ENCODED);
}
@Test
public void testSendInfo() throws IOException {
enigma2Client.sendInfo(40, SOME_TEXT);
verify(enigma2HttpClient).get(HOST + "/web/message?type=1&timeout=40&text=" + SOME_TEXT_ENCODED);
}
@Test
public void testSendQuestion() throws IOException {
enigma2Client.sendQuestion(50, SOME_TEXT);
verify(enigma2HttpClient).get(HOST + "/web/message?type=0&timeout=50&text=" + SOME_TEXT_ENCODED);
}
@Test
public void testRefreshPowerTrue() throws IOException {
whenStandby(" FALSE ");
enigma2Client.refreshPower();
assertThat(enigma2Client.isPower(), is(true));
}
@Test
public void testRefreshVolumeMuteTrue() throws IOException {
whenStandby("false");
whenVolume("30", true);
enigma2Client.refreshPower();
enigma2Client.refreshVolume();
assertThat(enigma2Client.isMute(), is(true));
assertThat(enigma2Client.getVolume(), is(30));
}
@Test
public void testRefreshVolumeMuteFalse() throws IOException {
whenStandby("false");
whenVolume("30", false);
enigma2Client.refreshPower();
enigma2Client.refreshVolume();
assertThat(enigma2Client.isMute(), is(false));
assertThat(enigma2Client.getVolume(), is(30));
}
@Test
public void testRefreshVolumePowerOff() throws IOException {
enigma2Client.refreshVolume();
assertThat(enigma2Client.isMute(), is(false));
assertThat(enigma2Client.getVolume(), is(0));
}
@Test
public void testRefreshPowerFalse() throws IOException {
whenStandby(" TRUE ");
enigma2Client.refreshPower();
assertThat(enigma2Client.isPower(), is(false));
}
@Test
public void testRefreshPowerOffline() throws IOException {
IOException ioException = new IOException();
when(enigma2HttpClient.get(HOST + Enigma2Client.PATH_POWER)).thenThrow(ioException);
enigma2Client.refreshPower();
assertThat(enigma2Client.isPower(), is(false));
}
@Test
public void testRefreshAllServices() throws IOException {
whenStandby("false");
whenAllServices();
enigma2Client.refreshAllServices();
assertThat(enigma2Client.getChannels(), containsInAnyOrder("Channel 1", "Channel 2", "Channel 3"));
}
@Test
public void testRefreshChannel() throws IOException {
whenStandby("false");
whenChannel("2", "Channel 2");
enigma2Client.refreshPower();
enigma2Client.refreshChannel();
assertThat(enigma2Client.getChannel(), is("Channel 2"));
}
@Test
public void testRefreshEpg() throws IOException {
whenStandby("false");
whenAllServices();
whenChannel("2", "Channel 2");
whenEpg("2", "Title", "Description");
enigma2Client.refreshPower();
enigma2Client.refreshAllServices();
enigma2Client.refreshChannel();
enigma2Client.refreshEpg();
assertThat(enigma2Client.getTitle(), is("Title"));
assertThat(enigma2Client.getDescription(), is("Description"));
}
@Test
public void testRefreshAnswerTimeout() throws IOException {
whenStandby("false");
whenAnswer("False", "Timeout");
enigma2Client.refreshPower();
enigma2Client.refreshAnswer();
assertThat(enigma2Client.getLastAnswerTime().isAfter(LocalDateTime.of(2020, 1, 1, 0, 0)), is(false));
assertThat(enigma2Client.getAnswer(), is(""));
}
@Test
public void testRefreshAnswerNoQuestion() throws IOException {
whenStandby("false");
whenAnswer("True", "Antwort lautet NEIN!");
enigma2Client.refreshPower();
enigma2Client.refreshAnswer();
assertThat(enigma2Client.getLastAnswerTime().isAfter(LocalDateTime.of(2020, 1, 1, 0, 0)), is(false));
assertThat(enigma2Client.getAnswer(), is(""));
}
@Test
public void testRefreshAnswer() throws IOException {
whenStandby("false");
whenAnswer("True", "Antwort lautet NEIN!");
enigma2Client.refreshPower();
enigma2Client.sendQuestion(50, SOME_TEXT);
enigma2Client.refreshAnswer();
assertThat(enigma2Client.getLastAnswerTime().isAfter(LocalDateTime.of(2020, 1, 1, 0, 0)), is(true));
assertThat(enigma2Client.getAnswer(), is("NEIN"));
}
@Test
public void testRefresh() throws IOException {
whenStandby("false");
whenAllServices();
whenVolume("A", false);
whenChannel("1", "Channel 1");
whenEpg("1", "Title", "Description");
assertThat(enigma2Client.refresh(), is(true));
assertThat(enigma2Client.isPower(), is(true));
assertThat(enigma2Client.isMute(), is(false));
assertThat(enigma2Client.getVolume(), is(0));
assertThat(enigma2Client.getChannel(), is("Channel 1"));
assertThat(enigma2Client.getTitle(), is("Title"));
assertThat(enigma2Client.getDescription(), is("Description"));
assertThat(enigma2Client.getChannels(), containsInAnyOrder("Channel 1", "Channel 2", "Channel 3"));
}
@Test
public void testRefreshOffline() throws IOException {
IOException ioException = new IOException();
when(enigma2HttpClient.get(HOST + Enigma2Client.PATH_POWER)).thenThrow(ioException);
assertThat(enigma2Client.refresh(), is(false));
assertThat(enigma2Client.isPower(), is(false));
assertThat(enigma2Client.isMute(), is(false));
assertThat(enigma2Client.getVolume(), is(0));
assertThat(enigma2Client.getChannel(), is(""));
assertThat(enigma2Client.getTitle(), is(""));
assertThat(enigma2Client.getDescription(), is(""));
assertThat(enigma2Client.getChannels().isEmpty(), is(true));
}
@Test
public void testGetEnigma2HttpClient() {
enigma2Client = new Enigma2Client("http://localhost:8080", null, null, 5);
assertThat(enigma2Client.getEnigma2HttpClient(), is(notNullValue()));
}
private void whenVolume(String volume, boolean mute) throws IOException {
when(enigma2HttpClient.get(HOST + Enigma2Client.PATH_VOLUME)).thenReturn(
"<e2volume><e2current>" + volume + "</e2current><e2ismuted>" + mute + "</e2ismuted></e2volume>");
}
private void whenEpg(String id, String title, String description) throws IOException {
when(enigma2HttpClient.get(HOST + Enigma2Client.PATH_EPG + id)).thenReturn("<e2event><e2eventtitle>" + title
+ "</e2eventtitle><e2eventdescription>" + description + "</e2eventdescription></e2event>");
}
private void whenAnswer(String state, String answer) throws IOException {
when(enigma2HttpClient.get(HOST + Enigma2Client.PATH_ANSWER)).thenReturn("<e2simplexmlresult><e2state>" + state
+ "</e2state><e2statetext>" + answer + "</e2statetext></e2simplexmlresult>");
}
private void whenStandby(String standby) throws IOException {
when(enigma2HttpClient.get(HOST + Enigma2Client.PATH_POWER))
.thenReturn("<e2powerstate><e2instandby>" + standby + "</e2instandby></e2powerstate>");
}
private void whenChannel(String id, String name) throws IOException {
when(enigma2HttpClient.get(HOST + Enigma2Client.PATH_CHANNEL)).thenReturn(
"<e2servicelist><e2service><e2servicereference>" + id + "</e2servicereference><e2servicename>" + name
+ "</e2servicename></e2service></e2servicelist>");
}
private void whenAllServices() throws IOException {
when(enigma2HttpClient.get(HOST + Enigma2Client.PATH_ALL_SERVICES))
.thenReturn("<e2servicelistrecursive>" + "<e2bouquet>" + "<e2servicelist>" + "<e2service>"
+ "<e2servicereference>1</e2servicereference>" + "<e2servicename>Channel 1</e2servicename>"
+ "</e2service>" + "<e2service>" + "<e2servicereference>2</e2servicereference>"
+ "<e2servicename>Channel 2</e2servicename>" + "</e2service>" + "</e2servicelist>"
+ "</e2bouquet>" + "<e2bouquet>" + "<e2servicelist>" + "<e2service>"
+ "<e2servicereference>3</e2servicereference>" + "<e2servicename>Channel 3</e2servicename>"
+ "</e2service>" + "</e2servicelist>" + "</e2bouquet>" + "</e2servicelistrecursive>");
}
}

View File

@@ -0,0 +1,67 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.internal;
import static org.eclipse.jdt.annotation.Checks.requireNonNull;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.openhab.binding.enigma2.internal.Enigma2BindingConstants.THING_TYPE_DEVICE;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Test;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
/**
* The {@link Enigma2HandlerFactoryTest} class is responsible for testing {@link Enigma2HandlerFactory}.
*
* @author Guido Dolfen - Initial contribution
*/
@SuppressWarnings("null")
@NonNullByDefault
public class Enigma2HandlerFactoryTest {
@Nullable
private Thing thing;
@Nullable
private Configuration configuration;
@Test
public void testSupportsThingType() {
assertThat(new Enigma2HandlerFactory().supportsThingType(Enigma2BindingConstants.THING_TYPE_DEVICE), is(true));
}
@Test
public void testSupportsThingTypeFalse() {
assertThat(new Enigma2HandlerFactory().supportsThingType(new ThingTypeUID("any", "device")), is(false));
}
@Test
public void testCreateHandlerNull() {
thing = mock(Thing.class);
assertThat(new Enigma2HandlerFactory().createHandler(requireNonNull(thing)), is(nullValue()));
}
@Test
public void testCreateHandler() {
thing = mock(Thing.class);
configuration = mock(Configuration.class);
when(thing.getConfiguration()).thenReturn(requireNonNull(configuration));
when(configuration.as(Enigma2Configuration.class)).thenReturn(new Enigma2Configuration());
when(thing.getThingTypeUID()).thenReturn(THING_TYPE_DEVICE);
assertThat(new Enigma2HandlerFactory().createHandler(requireNonNull(thing)), is(notNullValue()));
}
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.internal;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.Test;
/**
* The {@link Enigma2RemoteKeyTest} class is responsible for testing {@link Enigma2RemoteKey}.
*
* @author Guido Dolfen - Initial contribution
*/
@NonNullByDefault
public class Enigma2RemoteKeyTest {
@Test
public void testGetValue() {
assertThat(Enigma2RemoteKey.ARROW_LEFT.getValue(), is(412));
}
}

View File

@@ -0,0 +1,112 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.enigma2.internal.discovery;
import static org.eclipse.jdt.annotation.Checks.requireNonNull;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.when;
import java.net.Inet4Address;
import java.net.InetAddress;
import javax.jmdns.ServiceInfo;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.Before;
import org.junit.Test;
import org.openhab.binding.enigma2.internal.Enigma2BindingConstants;
import org.openhab.binding.enigma2.internal.Enigma2HttpClient;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.thing.ThingUID;
/**
* The {@link Enigma2DiscoveryParticipantTest} class is responsible for testing {@link Enigma2DiscoveryParticipant}.
*
* @author Guido Dolfen - Initial contribution
*/
@SuppressWarnings({ "null" })
@NonNullByDefault
public class Enigma2DiscoveryParticipantTest {
@Nullable
private ServiceInfo serviceInfo;
@Nullable
private Enigma2HttpClient enigma2HttpClient;
@Nullable
private Enigma2DiscoveryParticipant enigma2DiscoveryParticipant;
@Before
public void setUp() {
enigma2HttpClient = mock(Enigma2HttpClient.class);
serviceInfo = mock(ServiceInfo.class);
enigma2DiscoveryParticipant = spy(new Enigma2DiscoveryParticipant());
when(enigma2DiscoveryParticipant.getEnigma2HttpClient()).thenReturn(requireNonNull(enigma2HttpClient));
}
@Test
public void testGetSupportedThingTypeUIDs() {
assertThat(enigma2DiscoveryParticipant.getSupportedThingTypeUIDs(),
contains(Enigma2BindingConstants.THING_TYPE_DEVICE));
}
@Test
public void testGetServiceType() {
assertThat(enigma2DiscoveryParticipant.getServiceType(), is("_http._tcp.local."));
}
@Test
public void testCreateResult() throws Exception {
when(serviceInfo.getName()).thenReturn("enigma2");
when(enigma2HttpClient.get("http://192.168.10.3/web/about"))
.thenReturn("<e2abouts><e2about><e2enigmaversion>2020-01-11</e2enigmaversion></e2about></e2abouts>");
when(serviceInfo.getInet4Addresses())
.thenReturn(new Inet4Address[] { (Inet4Address) InetAddress.getAllByName("192.168.10.3")[0] });
DiscoveryResult discoveryResult = enigma2DiscoveryParticipant.createResult(requireNonNull(serviceInfo));
assertThat(discoveryResult, is(notNullValue()));
assertThat(discoveryResult.getLabel(), is("enigma2"));
assertThat(discoveryResult.getThingUID(),
is(new ThingUID(Enigma2BindingConstants.THING_TYPE_DEVICE, "192_168_10_3")));
assertThat(discoveryResult.getProperties(), is(notNullValue()));
assertThat(discoveryResult.getProperties(), hasEntry(Enigma2BindingConstants.CONFIG_HOST, "192.168.10.3"));
assertThat(discoveryResult.getProperties(), hasEntry(Enigma2BindingConstants.CONFIG_REFRESH, 5));
assertThat(discoveryResult.getProperties(), hasEntry(Enigma2BindingConstants.CONFIG_TIMEOUT, 5));
}
@Test
public void testCreateResultNotFound() throws Exception {
when(enigma2HttpClient.get("http://192.168.10.3/web/about")).thenReturn("any");
when(serviceInfo.getInet4Addresses())
.thenReturn(new Inet4Address[] { (Inet4Address) InetAddress.getAllByName("192.168.10.3")[0] });
assertThat(enigma2DiscoveryParticipant.createResult(requireNonNull(serviceInfo)), is(nullValue()));
}
@Test
public void testGetThingUID() throws Exception {
when(serviceInfo.getInet4Addresses())
.thenReturn(new Inet4Address[] { (Inet4Address) InetAddress.getAllByName("192.168.10.3")[0] });
assertThat(enigma2DiscoveryParticipant.getThingUID(requireNonNull(serviceInfo)),
is(new ThingUID(Enigma2BindingConstants.THING_TYPE_DEVICE, "192_168_10_3")));
}
@Test
public void testGetThingUIDTwoAddresses() throws Exception {
when(serviceInfo.getName()).thenReturn("enigma2");
Inet4Address[] addresses = { (Inet4Address) InetAddress.getAllByName("192.168.10.3")[0],
(Inet4Address) InetAddress.getAllByName("192.168.10.4")[0] };
when(serviceInfo.getInet4Addresses()).thenReturn(addresses);
assertThat(enigma2DiscoveryParticipant.getThingUID(requireNonNull(serviceInfo)),
is(new ThingUID(Enigma2BindingConstants.THING_TYPE_DEVICE, "192_168_10_3")));
}
}