[yioremote] Fixed reconnection and thing creation issues (#8596)
Signed-off-by: Michael Loercher <MichaelLoercher@web.de>
This commit is contained in:
parent
4e72980c6c
commit
4b91bfcfa0
|
@ -8,7 +8,7 @@ Since this binding allows actual you to trigger IR send/receive actions on YIO D
|
||||||
|
|
||||||
## Supported Things
|
## Supported Things
|
||||||
|
|
||||||
* Thing Type ID: `yioremotedock`
|
* Thing Type ID: `yioRemoteDock`
|
||||||
|
|
||||||
The following are the configurations available to each of the bridges/things:
|
The following are the configurations available to each of the bridges/things:
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ rule "yioremote Action Example"
|
||||||
when
|
when
|
||||||
...
|
...
|
||||||
then
|
then
|
||||||
val actions = getActions("yioremote", "yioremote:yioremotedock:livingroom")
|
val actions = getActions("yioremote", "yioremote:yioRemoteDock:livingroom")
|
||||||
if (actions === null)
|
if (actions === null)
|
||||||
{
|
{
|
||||||
......
|
......
|
||||||
|
@ -58,22 +58,20 @@ end
|
||||||
.things
|
.things
|
||||||
|
|
||||||
```
|
```
|
||||||
yioremote:yioremotedock:livingroom [ host="192.168.178.21", accesstoken="0" ]
|
yioremote:yioRemoteDock:livingroom [ host="xxx.xxx.xxx.xxx", accesstoken="0" ]
|
||||||
```
|
```
|
||||||
|
|
||||||
.items
|
.items
|
||||||
|
|
||||||
```
|
```
|
||||||
String sendircode "IR CODE [%s]" {channel="yioremote:yioremotedock:livingroom:input# sendircode"}
|
Switch receiverswitch "IR recieving switch" {channel="yioremote:yioRemoteDock:livingroom:input# receiverswitch"}
|
||||||
Switch receiverswitch "IR recieving switch" {channel="yioremote:yioremotedock:livingroom:input# receiverswitch"}
|
String status "YIO Dock status[%s]" {channel="yioremote:yioRemoteDock:livingroom:output# status"}
|
||||||
String status "YIO Dock status[%s]" {channel="yioremote:yioremotedock:livingroom:output# status"}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
.sitemap
|
.sitemap
|
||||||
|
|
||||||
```
|
```
|
||||||
sitemap Basic label="YIO Dock" {
|
sitemap Basic label="YIO Dock" {
|
||||||
Text item= sendircode
|
|
||||||
Switch item= receiverswitch
|
Switch item= receiverswitch
|
||||||
Text item= status
|
Text item= status
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,9 @@ public class YIOremoteBindingConstants {
|
||||||
AUTHENTICATION_FAILED,
|
AUTHENTICATION_FAILED,
|
||||||
AUTHENTICATION_COMPLETE,
|
AUTHENTICATION_COMPLETE,
|
||||||
CONNECTION_FAILED,
|
CONNECTION_FAILED,
|
||||||
CONNECTION_ESTABLISHED;
|
CONNECTION_ESTABLISHED,
|
||||||
|
COMMUNICATION_ERROR,
|
||||||
|
RECONNECTION_PROCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static enum YioRemoteMessages {
|
public static enum YioRemoteMessages {
|
||||||
|
@ -45,7 +47,7 @@ public class YIOremoteBindingConstants {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of all Thing Type UIDs
|
// List of all Thing Type UIDs
|
||||||
public static final ThingTypeUID THING_TYPE_YIOREMOTEDOCK = new ThingTypeUID(BINDING_ID, "yioremotedock");
|
public static final ThingTypeUID THING_TYPE_YIOREMOTEDOCK = new ThingTypeUID(BINDING_ID, "yioRemoteDock");
|
||||||
|
|
||||||
// List of all Channel Groups Group Channel ids
|
// List of all Channel Groups Group Channel ids
|
||||||
public static final String GROUP_INPUT = "input";
|
public static final String GROUP_INPUT = "input";
|
||||||
|
|
|
@ -69,6 +69,7 @@ public class YIOremoteDockHandler extends BaseThingHandler {
|
||||||
private @Nullable URI websocketAddress;
|
private @Nullable URI websocketAddress;
|
||||||
private YioRemoteDockHandleStatus yioRemoteDockActualStatus = YioRemoteDockHandleStatus.UNINITIALIZED_STATE;
|
private YioRemoteDockHandleStatus yioRemoteDockActualStatus = YioRemoteDockHandleStatus.UNINITIALIZED_STATE;
|
||||||
private @Nullable Future<?> webSocketPollingJob;
|
private @Nullable Future<?> webSocketPollingJob;
|
||||||
|
private @Nullable Future<?> webSocketReconnectionPollingJob;
|
||||||
public String receivedMessage = "";
|
public String receivedMessage = "";
|
||||||
private JsonObject recievedJson = new JsonObject();
|
private JsonObject recievedJson = new JsonObject();
|
||||||
private boolean heartBeat = false;
|
private boolean heartBeat = false;
|
||||||
|
@ -119,7 +120,10 @@ public class YIOremoteDockHandler extends BaseThingHandler {
|
||||||
switch (yioRemoteDockActualStatus) {
|
switch (yioRemoteDockActualStatus) {
|
||||||
case CONNECTION_ESTABLISHED:
|
case CONNECTION_ESTABLISHED:
|
||||||
case AUTHENTICATION_PROCESS:
|
case AUTHENTICATION_PROCESS:
|
||||||
authenticate();
|
authenticateWebsocket();
|
||||||
|
break;
|
||||||
|
case COMMUNICATION_ERROR:
|
||||||
|
reconnectWebsocket();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -132,13 +136,15 @@ public class YIOremoteDockHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onError() {
|
public void onClose() {
|
||||||
if (webSocketPollingJob != null) {
|
reconnectWebsocket();
|
||||||
webSocketPollingJob.cancel(true);
|
}
|
||||||
}
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable cause) {
|
||||||
|
yioRemoteDockActualStatus = YioRemoteDockHandleStatus.COMMUNICATION_ERROR;
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
"Connection lost no ping from YIO DOCK");
|
"Communication lost no ping from YIO DOCK");
|
||||||
updateState(GROUP_OUTPUT, STATUS_STRING_CHANNEL, UnDefType.UNDEF);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -174,8 +180,9 @@ public class YIOremoteDockHandler extends BaseThingHandler {
|
||||||
heartBeat = true;
|
heartBeat = true;
|
||||||
success = true;
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
if (irCodeSendHandler.getCode().equalsIgnoreCase("\"0;0x0;0;0\"")) {
|
if (irCodeSendHandler.getCode().equalsIgnoreCase("0;0x0;0;0")) {
|
||||||
logger.debug("Send heartBeat Code success");
|
logger.debug("Send heartBeat Code success");
|
||||||
|
receivedStatus = "Send heartBeat Code success";
|
||||||
} else {
|
} else {
|
||||||
receivedStatus = "Send IR Code failure";
|
receivedStatus = "Send IR Code failure";
|
||||||
}
|
}
|
||||||
|
@ -242,8 +249,12 @@ public class YIOremoteDockHandler extends BaseThingHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
if (webSocketPollingJob != null) {
|
disposeWebsocketPollingJob();
|
||||||
webSocketPollingJob.cancel(true);
|
if (webSocketReconnectionPollingJob != null) {
|
||||||
|
if (!webSocketReconnectionPollingJob.isCancelled() && webSocketReconnectionPollingJob != null) {
|
||||||
|
webSocketReconnectionPollingJob.cancel(true);
|
||||||
|
}
|
||||||
|
webSocketReconnectionPollingJob = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +298,7 @@ public class YIOremoteDockHandler extends BaseThingHandler {
|
||||||
updateState(id, new StringType(value));
|
updateState(id, new StringType(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void authenticate() {
|
private void authenticateWebsocket() {
|
||||||
switch (yioRemoteDockActualStatus) {
|
switch (yioRemoteDockActualStatus) {
|
||||||
case CONNECTION_ESTABLISHED:
|
case CONNECTION_ESTABLISHED:
|
||||||
authenticationMessageHandler.setToken(localConfig.accessToken);
|
authenticationMessageHandler.setToken(localConfig.accessToken);
|
||||||
|
@ -298,13 +309,15 @@ public class YIOremoteDockHandler extends BaseThingHandler {
|
||||||
if (authenticationOk) {
|
if (authenticationOk) {
|
||||||
yioRemoteDockActualStatus = YioRemoteDockHandleStatus.AUTHENTICATION_COMPLETE;
|
yioRemoteDockActualStatus = YioRemoteDockHandleStatus.AUTHENTICATION_COMPLETE;
|
||||||
updateStatus(ThingStatus.ONLINE);
|
updateStatus(ThingStatus.ONLINE);
|
||||||
webSocketPollingJob = scheduler.scheduleWithFixedDelay(this::pollingWebsocket, 0, 30,
|
webSocketPollingJob = scheduler.scheduleWithFixedDelay(this::pollingWebsocketJob, 0, 150,
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
} else {
|
} else {
|
||||||
yioRemoteDockActualStatus = YioRemoteDockHandleStatus.AUTHENTICATION_FAILED;
|
yioRemoteDockActualStatus = YioRemoteDockHandleStatus.AUTHENTICATION_FAILED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
disposeWebsocketPollingJob();
|
||||||
|
yioRemoteDockActualStatus = YioRemoteDockHandleStatus.COMMUNICATION_ERROR;
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
"Connection lost no ping from YIO DOCK");
|
"Connection lost no ping from YIO DOCK");
|
||||||
updateState(GROUP_OUTPUT, STATUS_STRING_CHANNEL, UnDefType.UNDEF);
|
updateState(GROUP_OUTPUT, STATUS_STRING_CHANNEL, UnDefType.UNDEF);
|
||||||
|
@ -312,7 +325,16 @@ public class YIOremoteDockHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pollingWebsocket() {
|
private void disposeWebsocketPollingJob() {
|
||||||
|
if (webSocketPollingJob != null) {
|
||||||
|
if (!webSocketPollingJob.isCancelled() && webSocketPollingJob != null) {
|
||||||
|
webSocketPollingJob.cancel(true);
|
||||||
|
}
|
||||||
|
webSocketPollingJob = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pollingWebsocketJob() {
|
||||||
switch (yioRemoteDockActualStatus) {
|
switch (yioRemoteDockActualStatus) {
|
||||||
case AUTHENTICATION_COMPLETE:
|
case AUTHENTICATION_COMPLETE:
|
||||||
if (getAndResetHeartbeat()) {
|
if (getAndResetHeartbeat()) {
|
||||||
|
@ -321,19 +343,16 @@ public class YIOremoteDockHandler extends BaseThingHandler {
|
||||||
logger.debug("heartBeat ok");
|
logger.debug("heartBeat ok");
|
||||||
sendMessage(YioRemoteMessages.HEARTBEAT_MESSAGE, "");
|
sendMessage(YioRemoteMessages.HEARTBEAT_MESSAGE, "");
|
||||||
} else {
|
} else {
|
||||||
yioRemoteDockActualStatus = YioRemoteDockHandleStatus.CONNECTION_FAILED;
|
yioRemoteDockActualStatus = YioRemoteDockHandleStatus.COMMUNICATION_ERROR;
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
"Connection lost no ping from YIO DOCK");
|
"Connection lost no ping from YIO DOCK");
|
||||||
updateState(GROUP_OUTPUT, STATUS_STRING_CHANNEL, UnDefType.UNDEF);
|
disposeWebsocketPollingJob();
|
||||||
if (webSocketPollingJob != null) {
|
reconnectWebsocket();
|
||||||
webSocketPollingJob.cancel(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (webSocketPollingJob != null) {
|
disposeWebsocketPollingJob();
|
||||||
webSocketPollingJob.cancel(true);
|
yioRemoteDockActualStatus = YioRemoteDockHandleStatus.COMMUNICATION_ERROR;
|
||||||
}
|
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
"Connection lost no ping from YIO DOCK");
|
"Connection lost no ping from YIO DOCK");
|
||||||
updateState(GROUP_OUTPUT, STATUS_STRING_CHANNEL, UnDefType.UNDEF);
|
updateState(GROUP_OUTPUT, STATUS_STRING_CHANNEL, UnDefType.UNDEF);
|
||||||
|
@ -347,6 +366,55 @@ public class YIOremoteDockHandler extends BaseThingHandler {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reconnectWebsocket() {
|
||||||
|
if (webSocketReconnectionPollingJob == null) {
|
||||||
|
webSocketReconnectionPollingJob = scheduler.scheduleWithFixedDelay(this::reconnectWebsocketJob, 0, 30,
|
||||||
|
TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reconnectWebsocketJob() {
|
||||||
|
switch (yioRemoteDockActualStatus) {
|
||||||
|
case COMMUNICATION_ERROR:
|
||||||
|
logger.debug("Reconnecting YIORemoteHandler");
|
||||||
|
try {
|
||||||
|
disposeWebsocketPollingJob();
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
|
"Connection lost no ping from YIO DOCK");
|
||||||
|
yioremoteDockwebSocketClient.closeWebsocketSession();
|
||||||
|
webSocketClient.stop();
|
||||||
|
yioRemoteDockActualStatus = YioRemoteDockHandleStatus.RECONNECTION_PROCESS;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.debug("Connection error {}", e.getMessage());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
websocketAddress = new URI("ws://" + localConfig.host + ":946");
|
||||||
|
yioRemoteDockActualStatus = YioRemoteDockHandleStatus.AUTHENTICATION_PROCESS;
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR,
|
||||||
|
"Initialize web socket failed: " + e.getMessage());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
webSocketClient.start();
|
||||||
|
webSocketClient.connect(yioremoteDockwebSocketClient, websocketAddress,
|
||||||
|
yioremoteDockwebSocketClientrequest);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.debug("Connection error {}", e.getMessage());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AUTHENTICATION_COMPLETE:
|
||||||
|
if (webSocketReconnectionPollingJob != null) {
|
||||||
|
if (!webSocketReconnectionPollingJob.isCancelled() && webSocketReconnectionPollingJob != null) {
|
||||||
|
webSocketReconnectionPollingJob.cancel(true);
|
||||||
|
}
|
||||||
|
webSocketReconnectionPollingJob = null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void sendMessage(YioRemoteMessages messageType, String messagePayload) {
|
public void sendMessage(YioRemoteMessages messageType, String messagePayload) {
|
||||||
switch (messageType) {
|
switch (messageType) {
|
||||||
case AUTHENTICATE_MESSAGE:
|
case AUTHENTICATE_MESSAGE:
|
||||||
|
|
|
@ -17,6 +17,8 @@ import java.io.IOException;
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.eclipse.jetty.websocket.api.Session;
|
import org.eclipse.jetty.websocket.api.Session;
|
||||||
|
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||||
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||||
|
@ -61,7 +63,25 @@ public class Websocket {
|
||||||
public void onError(Throwable cause) {
|
public void onError(Throwable cause) {
|
||||||
logger.warn("WebSocketError {}", cause.getMessage());
|
logger.warn("WebSocketError {}", cause.getMessage());
|
||||||
if (websocketHandler != null) {
|
if (websocketHandler != null) {
|
||||||
websocketHandler.onError();
|
websocketHandler.onError(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnWebSocketClose
|
||||||
|
public void onClose(int statusCode, String reason) {
|
||||||
|
if (statusCode != StatusCode.NORMAL) {
|
||||||
|
logger.debug("WebSocket Connection closed: {} - {}", statusCode, reason);
|
||||||
|
}
|
||||||
|
if (session != null) {
|
||||||
|
if (!session.isOpen()) {
|
||||||
|
if (session != null) {
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session = null;
|
||||||
|
}
|
||||||
|
if (websocketHandler != null) {
|
||||||
|
websocketHandler.onClose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,4 +94,10 @@ public class Websocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void closeWebsocketSession() {
|
||||||
|
if (session != null) {
|
||||||
|
session.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,9 @@ public interface WebsocketInterface {
|
||||||
|
|
||||||
public void onConnect(boolean connected);
|
public void onConnect(boolean connected);
|
||||||
|
|
||||||
|
public void onClose();
|
||||||
|
|
||||||
public void onMessage(String decodedmessage);
|
public void onMessage(String decodedmessage);
|
||||||
|
|
||||||
public void onError();
|
public void onError(Throwable cause);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue