added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.minecraft-${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-minecraft" description="Minecraft Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature>openhab-transport-mdns</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.minecraft/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 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.minecraft.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link MinecraftBinding} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class MinecraftBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "minecraft";
|
||||
|
||||
public static final int SERVER_RECONNECT = 30; // Seconds to wait before reconnect
|
||||
|
||||
public static final String PARAMETER_HOSTNAME = "hostname";
|
||||
public static final String PARAMETER_PORT = "port";
|
||||
|
||||
public static final String TYPE_ID_SERVER = "server";
|
||||
public static final String TYPE_ID_PLAYER = "player";
|
||||
public static final String TYPE_ID_SIGN = "redstoneSign";
|
||||
|
||||
public static final String CHANNEL_PLAYERS = "players";
|
||||
public static final String CHANNEL_MAX_PLAYERS = "maxPlayers";
|
||||
public static final String CHANNEL_ONLINE = "online";
|
||||
|
||||
public static final String CHANNEL_PLAYER_ONLINE = "playerOnline";
|
||||
public static final String CHANNEL_PLAYER_LEVEL = "playerLevel";
|
||||
public static final String CHANNEL_PLAYER_LEVEL_PERCENTAGE = "playerExperiencePercentage";
|
||||
public static final String CHANNEL_PLAYER_TOTAL_EXPERIENCE = "playerTotalExperience";
|
||||
public static final String CHANNEL_PLAYER_HEALTH = "playerHealth";
|
||||
public static final String CHANNEL_PLAYER_WALK_SPEED = "playerWalkSpeed";
|
||||
public static final String CHANNEL_PLAYER_LOCATION = "playerLocation";
|
||||
public static final String CHANNEL_PLAYER_GAME_MODE = "playerGameMode";
|
||||
|
||||
public static final String CHANNEL_SIGN_ACTIVE = "signActive";
|
||||
|
||||
public static final String PARAMETER_PLAYER_NAME = "playerName";
|
||||
|
||||
public static final String PARAMETER_SIGN_NAME = "signName";
|
||||
|
||||
public static final ThingTypeUID THING_TYPE_SERVER = new ThingTypeUID(BINDING_ID, TYPE_ID_SERVER);
|
||||
public static final ThingTypeUID THING_TYPE_PLAYER = new ThingTypeUID(BINDING_ID, TYPE_ID_PLAYER);
|
||||
public static final ThingTypeUID THING_TYPE_SIGN = new ThingTypeUID(BINDING_ID, TYPE_ID_SIGN);
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 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.minecraft.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.openhab.binding.minecraft.internal.handler.MinecraftPlayerHandler;
|
||||
import org.openhab.binding.minecraft.internal.handler.MinecraftServerHandler;
|
||||
import org.openhab.binding.minecraft.internal.handler.MinecraftSignHandler;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
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;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link MinecraftHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.minecraft")
|
||||
public class MinecraftHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(MinecraftHandlerFactory.class);
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = new HashSet<>();
|
||||
|
||||
static {
|
||||
SUPPORTED_THING_TYPES_UIDS.add(MinecraftBindingConstants.THING_TYPE_SERVER);
|
||||
SUPPORTED_THING_TYPES_UIDS.add(MinecraftBindingConstants.THING_TYPE_PLAYER);
|
||||
SUPPORTED_THING_TYPES_UIDS.add(MinecraftBindingConstants.THING_TYPE_SIGN);
|
||||
}
|
||||
|
||||
private static List<MinecraftServerHandler> minecraftServers = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (thingTypeUID.equals(MinecraftBindingConstants.THING_TYPE_SERVER)) {
|
||||
MinecraftServerHandler serverHandler = new MinecraftServerHandler((Bridge) thing);
|
||||
minecraftServers.add(serverHandler);
|
||||
return serverHandler;
|
||||
} else if (thingTypeUID.equals(MinecraftBindingConstants.THING_TYPE_PLAYER)) {
|
||||
MinecraftPlayerHandler playerHandler = new MinecraftPlayerHandler(thing);
|
||||
return playerHandler;
|
||||
} else if (thingTypeUID.equals(MinecraftBindingConstants.THING_TYPE_SIGN)) {
|
||||
MinecraftSignHandler signHandler = new MinecraftSignHandler(thing);
|
||||
return signHandler;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeHandler(ThingHandler thingHandler) {
|
||||
minecraftServers.remove(thingHandler);
|
||||
super.removeHandler(thingHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all Minecraft handlers created.
|
||||
*
|
||||
* @return the Minecraft handlers created,
|
||||
*/
|
||||
public static List<MinecraftServerHandler> getMinecraftServers() {
|
||||
LOGGER.debug("getMinecraftServers {}", minecraftServers.size());
|
||||
return new ArrayList<>(minecraftServers);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.minecraft.internal.config;
|
||||
|
||||
/**
|
||||
* Configuration settings for a {@link org.openhab.binding.minecraft.internal.handler.MinecraftPlayerHandler}.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class PlayerConfig {
|
||||
private String playerName = "";
|
||||
|
||||
/**
|
||||
* Get name of player.
|
||||
*
|
||||
* @return player name
|
||||
*/
|
||||
public String getName() {
|
||||
return playerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the player name.
|
||||
*
|
||||
* @param player name
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.playerName = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* 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.minecraft.internal.config;
|
||||
|
||||
/**
|
||||
* Configuration settings for a {@link org.openhab.binding.minecraft.internal.handler.MinecraftServerHandler}.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class ServerConfig {
|
||||
private int port = 10692;
|
||||
private String hostname = "127.0.0.1";
|
||||
|
||||
/**
|
||||
* Get port used to connect to server.
|
||||
*
|
||||
* @return server port
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the port used to connect to server.
|
||||
*
|
||||
* @param port server port
|
||||
*/
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get host used to connect to server.
|
||||
*
|
||||
* @return server host
|
||||
*/
|
||||
public String getHostname() {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the host used to connect to server.
|
||||
*
|
||||
* @param port host port
|
||||
*/
|
||||
public void setHostname(String hostname) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.minecraft.internal.config;
|
||||
|
||||
/**
|
||||
* Configuration settings for a {@link org.openhab.binding.minecraft.internal.handler.MinecraftSignHandler}.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class SignConfig {
|
||||
private String signName = "";
|
||||
|
||||
/**
|
||||
* Get text of sign to monitor.
|
||||
*
|
||||
* @return sign text
|
||||
*/
|
||||
public String getName() {
|
||||
return signName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sign text to listen for.
|
||||
*
|
||||
* @param sign text.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.signName = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* 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.minecraft.internal.discovery;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.openhab.binding.minecraft.internal.MinecraftBindingConstants;
|
||||
import org.openhab.binding.minecraft.internal.MinecraftHandlerFactory;
|
||||
import org.openhab.binding.minecraft.internal.config.ServerConfig;
|
||||
import org.openhab.binding.minecraft.internal.handler.MinecraftServerHandler;
|
||||
import org.openhab.binding.minecraft.internal.message.data.PlayerData;
|
||||
import org.openhab.binding.minecraft.internal.message.data.SignData;
|
||||
import org.openhab.binding.minecraft.internal.server.ServerConnection;
|
||||
import org.openhab.binding.minecraft.internal.util.Pair;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.functions.Func1;
|
||||
import rx.schedulers.Schedulers;
|
||||
import rx.subscriptions.CompositeSubscription;
|
||||
|
||||
/**
|
||||
* Handles discovery of Minecraft server, players and signs.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.minecraft")
|
||||
public class MinecraftDiscoveryService extends AbstractDiscoveryService {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(MinecraftDiscoveryService.class);
|
||||
|
||||
private static final int DISCOVER_TIMEOUT_SECONDS = 60;
|
||||
|
||||
private CompositeSubscription subscription;
|
||||
|
||||
public MinecraftDiscoveryService() {
|
||||
super(Collections.singleton(MinecraftBindingConstants.THING_TYPE_SERVER), DISCOVER_TIMEOUT_SECONDS, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
logger.debug("Starting Minecraft discovery scan");
|
||||
discoverServers();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void stopScan() {
|
||||
logger.debug("Stopping Minecraft discovery scan");
|
||||
stopDiscovery();
|
||||
super.stopScan();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start scanning for players and signs on servers.
|
||||
*/
|
||||
private void discoverServers() {
|
||||
subscription = new CompositeSubscription();
|
||||
|
||||
Observable<ServerConnection> serverRx = serversConnectRx().cache();
|
||||
|
||||
Subscription playerSubscription = subscribePlayersRx(serverRx);
|
||||
Subscription signsSubscription = subscribeSignsRx(serverRx);
|
||||
|
||||
subscription.add(playerSubscription);
|
||||
subscription.add(signsSubscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe for sign updates
|
||||
*
|
||||
* @param serverRx server stream
|
||||
* @return subscription for listening to sign events.
|
||||
*/
|
||||
private Subscription subscribeSignsRx(Observable<ServerConnection> serverRx) {
|
||||
return serverRx
|
||||
.flatMap(connection -> connection.getSocketHandler().getSignsRx().distinct(), (connection, signs) -> {
|
||||
return new Pair<>(connection, signs);
|
||||
}).subscribe(conectionSignPair -> {
|
||||
for (SignData sign : conectionSignPair.second) {
|
||||
submitSignDiscoveryResults(conectionSignPair.first.getThingUID(), sign);
|
||||
}
|
||||
}, e -> logger.error("Error while scanning for signs", e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to player updates
|
||||
*
|
||||
* @param serverRx server stream
|
||||
* @return subscription for listening to player events.
|
||||
*/
|
||||
private Subscription subscribePlayersRx(Observable<ServerConnection> serverRx) {
|
||||
return serverRx
|
||||
.flatMap(socketHandler -> socketHandler.getSocketHandler().getPlayersRx().distinct(),
|
||||
(connection, players) -> new Pair<>(connection, players))
|
||||
.subscribeOn(Schedulers.newThread()).subscribe(conectionPlayerPair -> {
|
||||
for (PlayerData player : conectionPlayerPair.second) {
|
||||
submitPlayerDiscoveryResults(conectionPlayerPair.first.getThingUID(), player.getName());
|
||||
}
|
||||
}, e -> logger.error("Error while scanning for players", e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Teardown subscribers and stop searching for players and signs.
|
||||
*/
|
||||
private void stopDiscovery() {
|
||||
if (subscription != null && !subscription.isUnsubscribed()) {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all servers that have been added as observable.
|
||||
*
|
||||
* @return observable emitting server objects.
|
||||
*/
|
||||
private Observable<ServerConnection> serversConnectRx() {
|
||||
return Observable.from(MinecraftHandlerFactory.getMinecraftServers())
|
||||
.flatMap(new Func1<MinecraftServerHandler, Observable<ServerConnection>>() {
|
||||
@Override
|
||||
public Observable<ServerConnection> call(MinecraftServerHandler server) {
|
||||
ServerConfig config = server.getServerConfig();
|
||||
return ServerConnection.create(server.getThing().getUID(), config.getHostname(),
|
||||
config.getPort());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit the discovered Devices to the Smarthome inbox,
|
||||
*
|
||||
* @param bridgeUID
|
||||
* @param name name of the player
|
||||
*/
|
||||
private void submitPlayerDiscoveryResults(ThingUID bridgeUID, String name) {
|
||||
String id = deviceNameToId(name);
|
||||
ThingUID uid = new ThingUID(MinecraftBindingConstants.THING_TYPE_PLAYER, bridgeUID, id);
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(MinecraftBindingConstants.PARAMETER_PLAYER_NAME, name);
|
||||
thingDiscovered(DiscoveryResultBuilder.create(uid).withProperties(properties).withBridge(bridgeUID)
|
||||
.withLabel(name).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit the discovered Signs to the Smarthome inbox,
|
||||
*
|
||||
* @param bridgeUID
|
||||
* @param sign data describing sign
|
||||
*/
|
||||
private void submitSignDiscoveryResults(ThingUID bridgeUID, SignData sign) {
|
||||
String id = deviceNameToId(sign.getName());
|
||||
ThingUID uid = new ThingUID(MinecraftBindingConstants.THING_TYPE_SIGN, bridgeUID, id);
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(MinecraftBindingConstants.PARAMETER_SIGN_NAME, sign.getName());
|
||||
thingDiscovered(DiscoveryResultBuilder.create(uid).withProperties(properties).withBridge(bridgeUID)
|
||||
.withLabel(sign.getName()).build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup device name so it can be used as id.
|
||||
*
|
||||
* @param name the name of device.
|
||||
* @return id of device.
|
||||
*/
|
||||
private String deviceNameToId(String name) {
|
||||
if (name == null) {
|
||||
return "";
|
||||
}
|
||||
return name.replaceAll("[^a-zA-Z0-9]+", "");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 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.minecraft.internal.discovery;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.jmdns.ServiceInfo;
|
||||
|
||||
import org.openhab.binding.minecraft.internal.MinecraftBindingConstants;
|
||||
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;
|
||||
|
||||
/**
|
||||
* The {@link MinecraftMDNSDiscoveryParticipant} is responsible for discovering Minecraft servers
|
||||
* {@link MDNSDiscoveryService}.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
@Component(immediate = true)
|
||||
public class MinecraftMDNSDiscoveryParticipant implements MDNSDiscoveryParticipant {
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
||||
return Collections.singleton(MinecraftBindingConstants.THING_TYPE_SERVER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceType() {
|
||||
return "_http._tcp.local.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscoveryResult createResult(ServiceInfo service) {
|
||||
if (service.getName().equals("wc-minecraft")) {
|
||||
ThingUID uid = getThingUID(service);
|
||||
|
||||
if (uid != null) {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
int port = service.getPort();
|
||||
String host = service.getInetAddresses()[0].getHostAddress();
|
||||
|
||||
properties.put(MinecraftBindingConstants.PARAMETER_HOSTNAME, host);
|
||||
properties.put(MinecraftBindingConstants.PARAMETER_PORT, port);
|
||||
|
||||
return DiscoveryResultBuilder.create(uid).withProperties(properties)
|
||||
.withRepresentationProperty(uid.getId()).withLabel("Minecraft Server (" + host + ")").build();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if service is a minecraft server.
|
||||
*
|
||||
* @param service the service to check.
|
||||
* @return true if minecraft server, else false.
|
||||
*/
|
||||
private boolean isMinecraftServer(ServiceInfo service) {
|
||||
return (service != null && service.getType() != null && service.getType().equals(getServiceType()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThingUID getThingUID(ServiceInfo service) {
|
||||
if (isMinecraftServer(service) && service.getInetAddresses().length > 0) {
|
||||
String host = service.getInetAddresses()[0].getHostAddress();
|
||||
host = host.replace('.', '_');
|
||||
|
||||
return new ThingUID(MinecraftBindingConstants.THING_TYPE_SERVER, host);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* 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.minecraft.internal.handler;
|
||||
|
||||
import org.openhab.binding.minecraft.internal.MinecraftBindingConstants;
|
||||
import org.openhab.binding.minecraft.internal.config.PlayerConfig;
|
||||
import org.openhab.binding.minecraft.internal.message.OHMessage;
|
||||
import org.openhab.binding.minecraft.internal.message.data.PlayerData;
|
||||
import org.openhab.binding.minecraft.internal.message.data.commands.PlayerCommandData;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PointType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
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.ThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
|
||||
/**
|
||||
* The {@link MinecraftPlayerHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class MinecraftPlayerHandler extends BaseThingHandler {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(MinecraftPlayerHandler.class);
|
||||
|
||||
private Subscription playerSubscription;
|
||||
private MinecraftServerHandler bridgeHandler;
|
||||
private PlayerConfig config;
|
||||
private Gson gson = new GsonBuilder().create();
|
||||
|
||||
public MinecraftPlayerHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
this.bridgeHandler = getBridgeHandler();
|
||||
this.config = getThing().getConfiguration().as(PlayerConfig.class);
|
||||
|
||||
if (bridgeHandler == null || getThing().getBridgeUID() == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No bridge configured");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
hookupListeners(bridgeHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
if (!playerSubscription.isUnsubscribed()) {
|
||||
playerSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
private void hookupListeners(MinecraftServerHandler bridgeHandler) {
|
||||
playerSubscription = bridgeHandler.getPlayerRx().doOnNext(players -> {
|
||||
boolean playerOnline = false;
|
||||
for (PlayerData player : players) {
|
||||
if (config.getName().equals(player.getName())) {
|
||||
playerOnline = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
State onlineState = playerOnline ? OnOffType.ON : OnOffType.OFF;
|
||||
updateState(MinecraftBindingConstants.CHANNEL_PLAYER_ONLINE, onlineState);
|
||||
}).flatMap(players -> Observable.from(players)).filter(player -> config.getName().equals(player.getName()))
|
||||
.subscribe(player -> updatePlayerState(player));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the state of player
|
||||
*
|
||||
* @param player the player to update
|
||||
*/
|
||||
private void updatePlayerState(PlayerData player) {
|
||||
State playerLevel = new DecimalType(player.getLevel());
|
||||
State playerLevelPercentage = new DecimalType(player.getExperience());
|
||||
State playerTotalExperience = new DecimalType(player.getTotalExperience());
|
||||
State playerHealth = new DecimalType(player.getHealth());
|
||||
State playerWalkSpeed = new DecimalType(player.getWalkSpeed());
|
||||
DecimalType longitude = new DecimalType(player.getLocation().getX());
|
||||
DecimalType latitude = new DecimalType(player.getLocation().getY());
|
||||
DecimalType altitude = new DecimalType(player.getLocation().getY());
|
||||
State playerLocation = new PointType(latitude, longitude, altitude);
|
||||
State playerGameMode = new StringType(player.getGameMode());
|
||||
|
||||
updateState(MinecraftBindingConstants.CHANNEL_PLAYER_LEVEL_PERCENTAGE, playerLevelPercentage);
|
||||
updateState(MinecraftBindingConstants.CHANNEL_PLAYER_TOTAL_EXPERIENCE, playerTotalExperience);
|
||||
updateState(MinecraftBindingConstants.CHANNEL_PLAYER_LEVEL, playerLevel);
|
||||
updateState(MinecraftBindingConstants.CHANNEL_PLAYER_HEALTH, playerHealth);
|
||||
updateState(MinecraftBindingConstants.CHANNEL_PLAYER_WALK_SPEED, playerWalkSpeed);
|
||||
updateState(MinecraftBindingConstants.CHANNEL_PLAYER_LOCATION, playerLocation);
|
||||
updateState(MinecraftBindingConstants.CHANNEL_PLAYER_GAME_MODE, playerGameMode);
|
||||
}
|
||||
|
||||
private String getPlayerName() {
|
||||
return config.getName();
|
||||
}
|
||||
|
||||
private synchronized MinecraftServerHandler getBridgeHandler() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null) {
|
||||
logger.debug("Required bridge not defined for device {}.", getThing().getUID());
|
||||
return null;
|
||||
} else {
|
||||
return getBridgeHandler(bridge);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized MinecraftServerHandler getBridgeHandler(Bridge bridge) {
|
||||
MinecraftServerHandler bridgeHandler = null;
|
||||
|
||||
ThingHandler handler = bridge.getHandler();
|
||||
if (handler instanceof MinecraftServerHandler) {
|
||||
bridgeHandler = (MinecraftServerHandler) handler;
|
||||
} else {
|
||||
logger.debug("No available bridge handler found yet. Bridge: {} .", bridge.getUID());
|
||||
bridgeHandler = null;
|
||||
}
|
||||
return bridgeHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(String channelID, State state) {
|
||||
ChannelUID channelUID = new ChannelUID(this.getThing().getUID(), channelID);
|
||||
updateState(channelUID, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a player command to server.
|
||||
*
|
||||
* @param type the type of command to send
|
||||
* @param playerName the name of the player to target
|
||||
* @param value the related to command
|
||||
*/
|
||||
private void sendPlayerCommand(String type, String playerName, String value) {
|
||||
PlayerCommandData playerCommand = new PlayerCommandData(type, playerName, value);
|
||||
JsonElement serializedCommand = gson.toJsonTree(playerCommand);
|
||||
logger.debug("Command: {}", serializedCommand);
|
||||
bridgeHandler.sendMessage(new OHMessage(OHMessage.MESSAGE_TYPE_PLAYER_COMMANDS, serializedCommand));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
switch (channelUID.getId()) {
|
||||
case MinecraftBindingConstants.CHANNEL_PLAYER_HEALTH:
|
||||
sendPlayerCommand(PlayerCommandData.COMMAND_PLAYER_HEALTH, getPlayerName(), command.toString());
|
||||
break;
|
||||
case MinecraftBindingConstants.CHANNEL_PLAYER_LEVEL:
|
||||
sendPlayerCommand(PlayerCommandData.COMMAND_PLAYER_LEVEL, getPlayerName(), command.toString());
|
||||
break;
|
||||
case MinecraftBindingConstants.CHANNEL_PLAYER_WALK_SPEED:
|
||||
sendPlayerCommand(PlayerCommandData.COMMAND_PLAYER_WALK_SPEED, getPlayerName(), command.toString());
|
||||
break;
|
||||
case MinecraftBindingConstants.CHANNEL_PLAYER_GAME_MODE:
|
||||
sendPlayerCommand(PlayerCommandData.COMMAND_PLAYER_GAME_MODE, getPlayerName(), command.toString());
|
||||
break;
|
||||
case MinecraftBindingConstants.CHANNEL_PLAYER_LOCATION:
|
||||
sendPlayerCommand(PlayerCommandData.COMMAND_PLAYER_LOCATION, getPlayerName(), command.toString());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* 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.minecraft.internal.handler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.openhab.binding.minecraft.internal.MinecraftBindingConstants;
|
||||
import org.openhab.binding.minecraft.internal.config.ServerConfig;
|
||||
import org.openhab.binding.minecraft.internal.message.OHMessage;
|
||||
import org.openhab.binding.minecraft.internal.message.data.PlayerData;
|
||||
import org.openhab.binding.minecraft.internal.message.data.ServerData;
|
||||
import org.openhab.binding.minecraft.internal.message.data.SignData;
|
||||
import org.openhab.binding.minecraft.internal.server.ServerConnection;
|
||||
import org.openhab.binding.minecraft.internal.util.RetryWithDelay;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
import rx.subscriptions.CompositeSubscription;
|
||||
|
||||
/**
|
||||
* The {@link MinecraftServerHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class MinecraftServerHandler extends BaseBridgeHandler {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(MinecraftServerHandler.class);
|
||||
|
||||
private ServerConfig config;
|
||||
|
||||
private Observable<ServerConnection> serverConnectionRX;
|
||||
private ServerConnection connection;
|
||||
private CompositeSubscription subscription;
|
||||
|
||||
public MinecraftServerHandler(Bridge bridge) {
|
||||
super(bridge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
subscription = new CompositeSubscription();
|
||||
config = getConfigAs(ServerConfig.class);
|
||||
logger.info("Initializing MinecraftHandler");
|
||||
connectToServer();
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get server configuration
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ServerConfig getServerConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly connect to server.
|
||||
* Reconnects when connection is lost
|
||||
*/
|
||||
private void connectToServer() {
|
||||
String host = config.getHostname();
|
||||
int port = config.getPort();
|
||||
|
||||
serverConnectionRX = ServerConnection.create(getThing().getUID(), host, port)
|
||||
.doOnNext(item -> updateOnlineState(true)).doOnError(e -> updateOnlineState(false))
|
||||
.retryWhen(new RetryWithDelay(1, TimeUnit.MINUTES)).repeat().replay(1).refCount();
|
||||
|
||||
Subscription serverUpdateSubscription = serverConnectionRX
|
||||
.flatMap(connection -> connection.getSocketHandler().getServerRx())
|
||||
.subscribe(serverData -> updateServerState(serverData));
|
||||
|
||||
Subscription serverConnectionSubscription = serverConnectionRX.subscribe(connection -> {
|
||||
this.connection = connection;
|
||||
});
|
||||
|
||||
subscription.add(serverUpdateSubscription);
|
||||
subscription.add(serverConnectionSubscription);
|
||||
}
|
||||
|
||||
public Observable<List<SignData>> getSignsRx() {
|
||||
return serverConnectionRX.switchMap(connection -> connection.getSocketHandler().getSignsRx());
|
||||
}
|
||||
|
||||
public Observable<List<PlayerData>> getPlayerRx() {
|
||||
return serverConnectionRX.switchMap(connection -> connection.getSocketHandler().getPlayersRx());
|
||||
}
|
||||
|
||||
/**
|
||||
* Update online state of server
|
||||
*
|
||||
* @param isOnline true if server is online
|
||||
*/
|
||||
private void updateOnlineState(boolean isOnline) {
|
||||
State onlineState = isOnline ? OnOffType.ON : OnOffType.OFF;
|
||||
updateState(MinecraftBindingConstants.CHANNEL_ONLINE, onlineState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update state of minecraft server
|
||||
*
|
||||
* @param serverData
|
||||
*/
|
||||
private void updateServerState(ServerData serverData) {
|
||||
State playersState = new DecimalType(serverData.getPlayers());
|
||||
State maxPlayersState = new DecimalType(serverData.getMaxPlayers());
|
||||
|
||||
updateState(MinecraftBindingConstants.CHANNEL_PLAYERS, playersState);
|
||||
updateState(MinecraftBindingConstants.CHANNEL_MAX_PLAYERS, maxPlayersState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message to server.
|
||||
* Does nothing if no connection is established.
|
||||
*
|
||||
* @param message the message to send
|
||||
* @return true if message was sent.
|
||||
*/
|
||||
public boolean sendMessage(OHMessage message) {
|
||||
if (connection != null) {
|
||||
connection.sendMessage(message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Disposing minecraft server thing");
|
||||
|
||||
if (subscription != null) {
|
||||
subscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* 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.minecraft.internal.handler;
|
||||
|
||||
import org.openhab.binding.minecraft.internal.MinecraftBindingConstants;
|
||||
import org.openhab.binding.minecraft.internal.config.SignConfig;
|
||||
import org.openhab.binding.minecraft.internal.message.OHMessage;
|
||||
import org.openhab.binding.minecraft.internal.message.data.SignData;
|
||||
import org.openhab.binding.minecraft.internal.message.data.commands.SignCommandData;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
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.ThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.Subscription;
|
||||
|
||||
/**
|
||||
* The {@link MinecraftSignHandler} is responsible for handling commands, which are
|
||||
* sent to one of the channels.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class MinecraftSignHandler extends BaseThingHandler {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(MinecraftSignHandler.class);
|
||||
|
||||
private MinecraftServerHandler bridgeHandler;
|
||||
private Subscription signSubscription;
|
||||
private SignConfig config;
|
||||
|
||||
private Gson gson = new GsonBuilder().create();
|
||||
|
||||
public MinecraftSignHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
this.bridgeHandler = getBridgeHandler();
|
||||
this.config = getThing().getConfiguration().as(SignConfig.class);
|
||||
|
||||
if (getThing().getBridgeUID() == null) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "No bridge configured");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
hookupListeners(bridgeHandler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
if (!signSubscription.isUnsubscribed()) {
|
||||
signSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
private String getSignName() {
|
||||
return config.getName();
|
||||
}
|
||||
|
||||
private void hookupListeners(MinecraftServerHandler bridgeHandler) {
|
||||
signSubscription = bridgeHandler.getSignsRx().flatMap(signs -> Observable.from(signs))
|
||||
.filter(sign -> config.getName().equals(sign.getName())).subscribe(sign -> updateSignState(sign));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates sign state of player.
|
||||
*
|
||||
* @param sign the sign to update
|
||||
*/
|
||||
private void updateSignState(SignData sign) {
|
||||
State activeState = sign.getState() ? OnOffType.ON : OnOffType.OFF;
|
||||
updateState(MinecraftBindingConstants.CHANNEL_SIGN_ACTIVE, activeState);
|
||||
}
|
||||
|
||||
private synchronized MinecraftServerHandler getBridgeHandler() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null) {
|
||||
logger.debug("Required bridge not defined for device {}.", getThing().getUID());
|
||||
return null;
|
||||
} else {
|
||||
return getBridgeHandler(bridge);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized MinecraftServerHandler getBridgeHandler(Bridge bridge) {
|
||||
MinecraftServerHandler bridgeHandler = null;
|
||||
|
||||
ThingHandler handler = bridge.getHandler();
|
||||
if (handler instanceof MinecraftServerHandler) {
|
||||
bridgeHandler = (MinecraftServerHandler) handler;
|
||||
} else {
|
||||
logger.debug("No available bridge handler found yet. Bridge: {} .", bridge.getUID());
|
||||
bridgeHandler = null;
|
||||
}
|
||||
return bridgeHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(String channelID, State state) {
|
||||
ChannelUID channelUID = new ChannelUID(this.getThing().getUID(), channelID);
|
||||
updateState(channelUID, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a sign command to server.
|
||||
*
|
||||
* @param type the type of command to send
|
||||
* @param signName the sign that the command targets
|
||||
* @param value the value related to command
|
||||
*/
|
||||
private void sendSignCommand(String type, String signName, String value) {
|
||||
SignCommandData signCommand = new SignCommandData(type, signName, value);
|
||||
JsonElement serializedCommand = gson.toJsonTree(signCommand);
|
||||
bridgeHandler.sendMessage(new OHMessage(OHMessage.MESSAGE_TYPE_SIGN_COMMANDS, serializedCommand));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
switch (channelUID.getId()) {
|
||||
case MinecraftBindingConstants.CHANNEL_SIGN_ACTIVE:
|
||||
Boolean activeState = command == OnOffType.ON ? true : false;
|
||||
sendSignCommand(SignCommandData.COMMAND_SIGN_ACTIVE, getSignName(), activeState.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 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.minecraft.internal.message;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
/**
|
||||
* Message used for communicating with Minecraft server.
|
||||
* Used both for sending and receiving messages.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class OHMessage {
|
||||
|
||||
public static final int MESSAGE_TYPE_PLAYERS = 1;
|
||||
public static final int MESSAGE_TYPE_SERVERS = 2;
|
||||
public static final int MESSAGE_TYPE_SIGNS = 4;
|
||||
public static final int MESSAGE_TYPE_PLAYER_COMMANDS = 3;
|
||||
public static final int MESSAGE_TYPE_SIGN_COMMANDS = 5;
|
||||
|
||||
private int messageType;
|
||||
private JsonElement message;
|
||||
|
||||
/**
|
||||
* Creates a message of type.
|
||||
*
|
||||
* @param messageType the message type.
|
||||
* @param message message data.
|
||||
*/
|
||||
public OHMessage(int messageType, JsonElement message) {
|
||||
this.messageType = messageType;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of message
|
||||
*
|
||||
* @return type of message
|
||||
*/
|
||||
public int getMessageType() {
|
||||
return messageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set message type.
|
||||
*
|
||||
* @param messageType the type of message
|
||||
*/
|
||||
public void setMessageType(int messageType) {
|
||||
this.messageType = messageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get messsage data.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public JsonElement getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message to send.
|
||||
*
|
||||
* @param message
|
||||
*/
|
||||
public void setMessage(JsonElement message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* 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.minecraft.internal.message.data;
|
||||
|
||||
/**
|
||||
* Holds location data for Minecraft objects.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class LocationData {
|
||||
private double x;
|
||||
private double y;
|
||||
private double z;
|
||||
private float pitch;
|
||||
private float yaw;
|
||||
|
||||
/**
|
||||
* Get x position.
|
||||
*
|
||||
* @return x position
|
||||
*/
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get y position.
|
||||
*
|
||||
* @return y position
|
||||
*/
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get z position.
|
||||
*
|
||||
* @return z position
|
||||
*/
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pitch of object
|
||||
*
|
||||
* @return pitch of object.
|
||||
*/
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get yaw of object
|
||||
*
|
||||
* @return yaw of object
|
||||
*/
|
||||
public float getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* 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.minecraft.internal.message.data;
|
||||
|
||||
/**
|
||||
* Object representing Minecraft player.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class PlayerData {
|
||||
|
||||
protected String displayName;
|
||||
protected String name;
|
||||
protected int level;
|
||||
protected int totalExperience;
|
||||
protected float experience;
|
||||
protected double health;
|
||||
protected float walkSpeed;
|
||||
protected LocationData location;
|
||||
protected String gameMode;
|
||||
|
||||
/**
|
||||
* Get the display name of player.
|
||||
*
|
||||
* @return display name
|
||||
*/
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of player
|
||||
*
|
||||
* @return name of player.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the player level.
|
||||
*
|
||||
* @return level of player
|
||||
*/
|
||||
public int getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total experience of player.
|
||||
*
|
||||
* @return total experience
|
||||
*/
|
||||
public int getTotalExperience() {
|
||||
return totalExperience;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get player experiance.
|
||||
*
|
||||
* @return experiance of player
|
||||
*/
|
||||
public float getExperience() {
|
||||
return experience;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get health of player.
|
||||
*
|
||||
* @return player health
|
||||
*/
|
||||
public double getHealth() {
|
||||
return health;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the walk speed of player.
|
||||
*
|
||||
* @return walk speed of player
|
||||
*/
|
||||
public float getWalkSpeed() {
|
||||
return walkSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get location of player.
|
||||
*
|
||||
* @return location of player
|
||||
*/
|
||||
public LocationData getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the players game mode.
|
||||
*
|
||||
* @return game mode
|
||||
*/
|
||||
public String getGameMode() {
|
||||
return gameMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
PlayerData other = (PlayerData) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!name.equals(other.name)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -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.minecraft.internal.message.data;
|
||||
|
||||
/**
|
||||
* Object representing Minecraft server.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class ServerData {
|
||||
|
||||
private int maxPlayers;
|
||||
private int players;
|
||||
|
||||
/**
|
||||
* Get max number of players.
|
||||
*
|
||||
* @return max number of players.
|
||||
*/
|
||||
public int getMaxPlayers() {
|
||||
return maxPlayers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of players.
|
||||
*
|
||||
* @return number of players.
|
||||
*/
|
||||
public int getPlayers() {
|
||||
return players;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* 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.minecraft.internal.message.data;
|
||||
|
||||
/**
|
||||
* Object representing a tracked Minecraft sign.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class SignData {
|
||||
|
||||
private String name;
|
||||
private boolean state;
|
||||
|
||||
/**
|
||||
* Creates a representation of sign.
|
||||
*
|
||||
* @param name text on sign.
|
||||
* @param state true if powered by redstone else false.
|
||||
*/
|
||||
public SignData(String name, boolean state) {
|
||||
this.name = name;
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* The text on sign.
|
||||
*
|
||||
* @return text name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The active sign of state.
|
||||
*
|
||||
* @return true if powered by redstone
|
||||
*/
|
||||
public boolean getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SignData other = (SignData) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!name.equals(other.name)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -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.minecraft.internal.message.data.commands;
|
||||
|
||||
/**
|
||||
* Object representing Minecraft server.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class PlayerCommandData {
|
||||
|
||||
public static final String COMMAND_PLAYER_HEALTH = "PLAYER_HEALTH";
|
||||
public static final String COMMAND_PLAYER_LEVEL = "PLAYER_LEVEL";
|
||||
public static final String COMMAND_PLAYER_WALK_SPEED = "PLAYER_WALK_SPEED";
|
||||
public static final String COMMAND_PLAYER_GAME_MODE = "PLAYER_GAME_MODE";
|
||||
public static final String COMMAND_PLAYER_LOCATION = "PLAYER_LOCATION";
|
||||
|
||||
private String type;
|
||||
private String playerName;
|
||||
private String value;
|
||||
|
||||
public PlayerCommandData() {
|
||||
}
|
||||
|
||||
public PlayerCommandData(String type, String playerName, String value) {
|
||||
this.type = type;
|
||||
this.playerName = playerName;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of command.
|
||||
*
|
||||
* @return the type of command.
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the player that the command targets.
|
||||
*
|
||||
* @return name of player
|
||||
*/
|
||||
public String getPlayerName() {
|
||||
return playerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The command value sent.
|
||||
*
|
||||
* @return command value.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* 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.minecraft.internal.message.data.commands;
|
||||
|
||||
/**
|
||||
* A command that targets a sign.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class SignCommandData {
|
||||
|
||||
public static final String COMMAND_SIGN_ACTIVE = "COMMAND_SIGN_ACTIVE";
|
||||
|
||||
private String type;
|
||||
private String signName;
|
||||
private String value;
|
||||
|
||||
public SignCommandData() {
|
||||
}
|
||||
|
||||
public SignCommandData(String type, String signName, String value) {
|
||||
this.type = type;
|
||||
this.signName = signName;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of command.
|
||||
*
|
||||
* @return the type of command.
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the sign that the command targets.
|
||||
*
|
||||
* @return name of sign
|
||||
*/
|
||||
public String getSignName() {
|
||||
return signName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The command value sent.
|
||||
*
|
||||
* @return command value.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* 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.minecraft.internal.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.openhab.binding.minecraft.internal.message.OHMessage;
|
||||
import org.openhab.binding.minecraft.internal.message.data.PlayerData;
|
||||
import org.openhab.binding.minecraft.internal.message.data.ServerData;
|
||||
import org.openhab.binding.minecraft.internal.message.data.SignData;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.firebase.tubesock.WebSocketEventHandler;
|
||||
import com.firebase.tubesock.WebSocketException;
|
||||
import com.firebase.tubesock.WebSocketMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.subjects.BehaviorSubject;
|
||||
|
||||
/**
|
||||
* Handles sending and receiving messages from Minecraft server.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class MinecraftSocketHandler implements WebSocketEventHandler {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(MinecraftSocketHandler.class);
|
||||
|
||||
private BehaviorSubject<ServerData> serverRx = BehaviorSubject.create();
|
||||
private BehaviorSubject<List<SignData>> signsRx = BehaviorSubject.<List<SignData>> create();
|
||||
private BehaviorSubject<List<PlayerData>> playersRx = BehaviorSubject.<List<PlayerData>> create();
|
||||
|
||||
private Gson gson = new GsonBuilder().create();
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
logger.info("Connection to minecraft server closed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(WebSocketException e) {
|
||||
logger.error("Server error {}", e.getMessage(), e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen() {
|
||||
logger.info("Connection to minecraft server opened");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLogMessage(String s) {
|
||||
logger.info("Log message: {}", s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocketMessage message) {
|
||||
String msg = message.getText();
|
||||
|
||||
if (msg != null) {
|
||||
OHMessage ohMessage = gson.fromJson(msg, OHMessage.class);
|
||||
int messageType = ohMessage.getMessageType();
|
||||
if (OHMessage.MESSAGE_TYPE_SERVERS == messageType) {
|
||||
ServerData serverData = gson.fromJson(ohMessage.getMessage(), ServerData.class);
|
||||
serverRx.onNext(serverData);
|
||||
} else if (OHMessage.MESSAGE_TYPE_PLAYERS == messageType) {
|
||||
List<PlayerData> playerData = gson.fromJson(ohMessage.getMessage(),
|
||||
new TypeToken<ArrayList<PlayerData>>() {
|
||||
}.getType());
|
||||
playersRx.onNext(playerData);
|
||||
} else if (OHMessage.MESSAGE_TYPE_SIGNS == messageType) {
|
||||
List<SignData> signsData = gson.fromJson(ohMessage.getMessage(), new TypeToken<ArrayList<SignData>>() {
|
||||
}.getType());
|
||||
signsRx.onNext(signsData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get observable emitting server items.
|
||||
*
|
||||
* @return observable emitting server items.
|
||||
*/
|
||||
public Observable<ServerData> getServerRx() {
|
||||
return serverRx.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get observable emitting sign items.
|
||||
*
|
||||
* @return observable emitting sign items.
|
||||
*/
|
||||
public Observable<List<SignData>> getSignsRx() {
|
||||
return signsRx.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get observable emitting player items.
|
||||
*
|
||||
* @return observable emitting player items.
|
||||
*/
|
||||
public Observable<List<PlayerData>> getPlayersRx() {
|
||||
return playersRx.asObservable();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/**
|
||||
* 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.minecraft.internal.server;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.openhab.binding.minecraft.internal.message.OHMessage;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.firebase.tubesock.WebSocket;
|
||||
import com.firebase.tubesock.WebSocketException;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.Observable.OnSubscribe;
|
||||
import rx.Subscriber;
|
||||
import rx.functions.Action0;
|
||||
import rx.subscriptions.Subscriptions;
|
||||
|
||||
/**
|
||||
* Holds information about connection to Minecraft server.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class ServerConnection {
|
||||
|
||||
private String host;
|
||||
private int port;
|
||||
private ThingUID thingUID;
|
||||
private Gson gson = new GsonBuilder().create();
|
||||
|
||||
private MinecraftSocketHandler socketHandler;
|
||||
|
||||
private WebSocket webSocket;
|
||||
|
||||
private ServerConnection(ThingUID thingUID, String host, int port) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.thingUID = thingUID;
|
||||
}
|
||||
|
||||
public class ServerData {
|
||||
public String host;
|
||||
public int port;
|
||||
public ServerConnection connection;
|
||||
|
||||
public ServerData(String host, int port, ServerConnection connection) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.connection = connection;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get host address of server.
|
||||
*
|
||||
* @return server host address.
|
||||
*/
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get port used to communicate to Minecraft server.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get UID of server
|
||||
*
|
||||
* @return server uid.
|
||||
*/
|
||||
public ThingUID getThingUID() {
|
||||
return thingUID;
|
||||
}
|
||||
|
||||
public void sendMessage(OHMessage message) {
|
||||
String serializedMessage = gson.toJson(message);
|
||||
webSocket.send(serializedMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the handler used to handle messages state updates web socket.
|
||||
*
|
||||
* @param handler the websocket handler to use for new connections.
|
||||
*/
|
||||
private void setSocketHandler(MinecraftSocketHandler handler) {
|
||||
socketHandler = handler;
|
||||
}
|
||||
|
||||
private void setWebSocket(WebSocket webSocket) {
|
||||
this.webSocket = webSocket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object used to handle state changes and messages from web socket.
|
||||
*
|
||||
* @return handler for web socket.
|
||||
*/
|
||||
public MinecraftSocketHandler getSocketHandler() {
|
||||
return socketHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Directly connect to server.
|
||||
* Reconnects when connection is lost
|
||||
*/
|
||||
public static Observable<ServerConnection> create(final ThingUID thingUID, final String host, final int port) {
|
||||
final String serverUrl = String.format("ws://%s:%d/stream", host, port);
|
||||
|
||||
return Observable.<ServerConnection> create(new OnSubscribe<ServerConnection>() {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ServerConnection.class);
|
||||
|
||||
@Override
|
||||
public void call(final Subscriber<? super ServerConnection> subscriber) {
|
||||
logger.info("Start connecting to Minecraft server at: {}", serverUrl);
|
||||
if (!subscriber.isUnsubscribed()) {
|
||||
ServerConnection serverConnection = new ServerConnection(thingUID, host, port);
|
||||
MinecraftSocketHandler socketHandler = new MinecraftSocketHandler() {
|
||||
@Override
|
||||
public void onError(WebSocketException e) {
|
||||
subscriber.onError(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
logger.info("Connection to Minecraft server stopped");
|
||||
subscriber.onCompleted();
|
||||
}
|
||||
};
|
||||
|
||||
URI destUri = null;
|
||||
try {
|
||||
destUri = new URI(serverUrl);
|
||||
} catch (URISyntaxException e) {
|
||||
subscriber.onError(e);
|
||||
}
|
||||
final WebSocket websocket = new WebSocket(destUri);
|
||||
websocket.setEventHandler(socketHandler);
|
||||
websocket.connect();
|
||||
|
||||
serverConnection.setSocketHandler(socketHandler);
|
||||
serverConnection.setWebSocket(websocket);
|
||||
subscriber.onNext(serverConnection);
|
||||
|
||||
subscriber.add(Subscriptions.create(new Action0() {
|
||||
@Override
|
||||
public void call() {
|
||||
subscriber.unsubscribe();
|
||||
websocket.close();
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((host == null) ? 0 : host.hashCode());
|
||||
result = prime * result + port;
|
||||
result = prime * result + ((socketHandler == null) ? 0 : socketHandler.hashCode());
|
||||
result = prime * result + ((thingUID == null) ? 0 : thingUID.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ServerConnection other = (ServerConnection) obj;
|
||||
if (host == null) {
|
||||
if (other.host != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!host.equals(other.host)) {
|
||||
return false;
|
||||
}
|
||||
if (port != other.port) {
|
||||
return false;
|
||||
}
|
||||
if (socketHandler == null) {
|
||||
if (other.socketHandler != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!socketHandler.equals(other.socketHandler)) {
|
||||
return false;
|
||||
}
|
||||
if (thingUID == null) {
|
||||
if (other.thingUID != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!thingUID.equals(other.thingUID)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -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.minecraft.internal.util;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Generic pair object.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class Pair<T, R> {
|
||||
|
||||
public final T first;
|
||||
public final R second;
|
||||
|
||||
public Pair(T first, R second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Pair)) {
|
||||
return false;
|
||||
}
|
||||
Pair<?, ?> p = (Pair<?, ?>) obj;
|
||||
return Objects.equals(p.first, first) && Objects.equals(p.second, second);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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.minecraft.internal.util;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.functions.Func1;
|
||||
|
||||
/**
|
||||
* RX operator subscribing to observable with a delay after it has finished.
|
||||
*
|
||||
* @author Mattias Markehed - Initial contribution
|
||||
*/
|
||||
public class RetryWithDelay implements Func1<Observable<? extends Throwable>, Observable<?>> {
|
||||
|
||||
private final int maxRetries;
|
||||
private final long retryDelayMillis;
|
||||
private int retryCount;
|
||||
|
||||
public RetryWithDelay(final long retryDelay, TimeUnit unit) {
|
||||
this(-1, TimeUnit.MILLISECONDS.convert(retryDelay, unit));
|
||||
}
|
||||
|
||||
public RetryWithDelay(final int maxRetries, final long retryDelay, TimeUnit unit) {
|
||||
this(maxRetries, TimeUnit.MILLISECONDS.convert(retryDelay, unit));
|
||||
}
|
||||
|
||||
private RetryWithDelay(final int maxRetries, final long retryDelayMillis) {
|
||||
this.maxRetries = maxRetries;
|
||||
this.retryDelayMillis = retryDelayMillis;
|
||||
this.retryCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<?> call(Observable<? extends Throwable> attempts) {
|
||||
return attempts.flatMap(new Func1<Throwable, Observable<?>>() {
|
||||
@Override
|
||||
public Observable<?> call(Throwable throwable) {
|
||||
if (maxRetries < 0 || ++retryCount < maxRetries) {
|
||||
return Observable.timer(retryDelayMillis, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
return Observable.error(throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="minecraft" 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>Minecraft Binding</name>
|
||||
<description>This binding can integrate Minecraft servers.</description>
|
||||
<author>Mattias Markehed</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,170 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="minecraft"
|
||||
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">
|
||||
|
||||
<bridge-type id="server">
|
||||
<label>Minecraft Bukkit Server</label>
|
||||
<description>Server from which data is being fetched.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="online" typeId="online"/>
|
||||
<channel id="players" typeId="players"/>
|
||||
<channel id="maxPlayers" typeId="maxPlayers"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="hostname" type="text" required="true">
|
||||
<label>Hostname or IP</label>
|
||||
<context>network-address</context>
|
||||
<description>Hostname or IP of the server.</description>
|
||||
</parameter>
|
||||
|
||||
<parameter name="port" type="integer">
|
||||
<label>Port</label>
|
||||
<description>The port on which the server can be accessed.</description>
|
||||
<default>10692</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
<thing-type id="player">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="server"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Player</label>
|
||||
<description>A connected player connected to the Minecraft server.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="playerOnline" typeId="online">
|
||||
<label>Online</label>
|
||||
<description>Online status of the player.</description>
|
||||
</channel>
|
||||
<channel id="playerLevel" typeId="playerLevel"/>
|
||||
<channel id="playerTotalExperience" typeId="playerTotalExperience"/>
|
||||
<channel id="playerExperiencePercentage" typeId="playerExperiencePercentage"/>
|
||||
<channel id="playerHealth" typeId="playerHealth"/>
|
||||
<channel id="playerWalkSpeed" typeId="playerWalkSpeed"/>
|
||||
<channel id="playerLocation" typeId="location"/>
|
||||
<channel id="playerGameMode" typeId="playerGameMode"/>
|
||||
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="playerName" type="text" required="true">
|
||||
<label>Player Name</label>
|
||||
<description>The name of the player.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<thing-type id="redstoneSign">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="server"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Sign</label>
|
||||
<description>A sign with a redstone path under it.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="signActive" typeId="signActive"/>
|
||||
</channels>
|
||||
|
||||
<config-description>
|
||||
<parameter name="signName" type="text" required="true">
|
||||
<label>Sign Name</label>
|
||||
<description>The text on the sign.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<channel-type id="players">
|
||||
<item-type>Number</item-type>
|
||||
<label>Players</label>
|
||||
<description>The number of players on the server.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="maxPlayers">
|
||||
<item-type>Number</item-type>
|
||||
<label>Max Players</label>
|
||||
<description>The maxumum number of players on the server.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="online">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Online</label>
|
||||
<description>Online status of the thing.</description>
|
||||
<category>Switch</category>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="ON">Online</option>
|
||||
<option value="OFF">Offline</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="location">
|
||||
<item-type>Location</item-type>
|
||||
<label>Location</label>
|
||||
<description>The location of the player.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="playerLevel">
|
||||
<item-type>Number</item-type>
|
||||
<label>Level</label>
|
||||
<description>The players current level.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="playerTotalExperience" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Total Experience</label>
|
||||
<description>The total experience of the player.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="playerExperiencePercentage" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Experience</label>
|
||||
<description>Percentage of the experience bar filled for the next level.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="playerHealth">
|
||||
<item-type>Number</item-type>
|
||||
<label>Health</label>
|
||||
<description>The health of player.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="playerWalkSpeed" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Speed</label>
|
||||
<description>The speed of player.</description>
|
||||
<state min="0" max="1" step="0.05" pattern="%.2f"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="playerGameMode" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Game Mode</label>
|
||||
<description>The players current game mode.</description>
|
||||
<state readOnly="false">
|
||||
<options>
|
||||
<option value="CREATIVE">creative</option>
|
||||
<option value="SURVIVAL">survival</option>
|
||||
<option value="ADVENTURE">adventure</option>
|
||||
<option value="SPECTATOR">spectator</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="signActive">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Online</label>
|
||||
<description>Shows if the sign has powered redstone below it.</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
Reference in New Issue
Block a user