edusperoni/nativescript-mqtt

Connection Lost after a minute

Opened this issue · 35 comments

Connection is getting lost after few minutes of active, I tried reinitialising the mqttclient but continously connecting and lost connection as below

'Connection lost: AMQJS0008I Socket closed.'
JS: 'initialized connection'
JS: 'mqtt init called'
JS: 'connecting...'
JS: 'Connection success!'
JS: 'Connection lost: AMQJS0008I Socket closed.'
JS: 'initialized connection'
JS: 'mqtt init called'
JS: 'connecting...'
JS: 'Connection success!'
JS: 'Connection lost: AMQJS0008I Socket closed.'
JS: 'initialized connection'
JS: 'mqtt init called'
JS: 'connecting...'
JS: 'Connection success!'
JS: 'Connection lost: AMQJS0008I Socket closed.'
JS: 'initialized connection'
JS: 'mqtt init called'
JS: 'connecting...'
JS: 'Connection success!'
JS: 'Connection lost: AMQJS0008I Socket closed.'
JS: 'initialized connection'
JS: 'mqtt init called'
JS: 'connecting...'
JS: 'Connection success!'
JS: 'Connection lost: AMQJS0008I Socket closed.'
JS: 'initialized connection'
JS: 'mqtt init called'
JS: 'connecting...'
JS: 'Connection success!'
JS: 'Connection lost: AMQJS0008I Socket closed.'
JS: 'initialized connection'
JS: 'mqtt init called'
JS: 'connecting...'

Which platform(s) does your issue occur on?

  • Android versions - tested on 5 & 6

Please, provide the following version numbers that your issue occurs with:

  • CLI: 5.2.0
  • Cross-platform modules: 4.1.0
  • Runtime(s): 5.2.1
  • Plugin(s):
    {
    "description": "NativeScript Application",
    "license": "SEE LICENSE IN ",
    "readme": "NativeScript Application",
    "repository": "",
    "nativescript": {
    "id": "com.clofus.messenger",
    "tns-android": {
    "version": "5.2.1"
    }
    },
    "dependencies": {
    "axios": "^0.18.0",
    "moment": "^2.22.2",
    "nativescript-autocomplete": "^1.0.0",
    "nativescript-camera": "^4.0.2",
    "nativescript-checkbox": "^3.0.3",
    "nativescript-filterable-listpicker": "^2.0.2",
    "nativescript-fonticon": "^1.1.1",
    "nativescript-imagecropper": "^1.0.4",
    "nativescript-loading-indicator": "^2.4.0",
    "nativescript-mqtt": "JScearcy/nativescript-mqtt#master",
    "nativescript-paypal-checkout": "^2.1.0",
    "nativescript-pulltorefresh": "^2.1.1",
    "nativescript-push-notifications": "^1.1.4",
    "nativescript-theme-core": "^1.0.4",
    "nativescript-ui-autocomplete": "^3.7.1",
    "nativescript-ui-listview": "^3.5.7",
    "nativescript-vue": "^1.3.1",
    "nativescript-websockets": "^1.5.0",
    "tns-core-modules": "^4.1.0",
    "vue-router": "^3.0.1"
    },
    "devDependencies": {
    "babel-traverse": "6.26.0",
    "babel-types": "6.26.0",
    "babylon": "6.18.0",
    "lazy": "1.0.11"
    },
    "author": "Clofus Innovations Pvt Ltd LLC"
    }

Please, tell us how to recreate the issue in as much detail as possible.

It is a simple project that connects to EMQ MQTT broker, the connection works but doesnot stay connected no longer than a minute time and even reconnecting it constantly fails

Is there any code involved?

const MQTTCommon = require("nativescript-mqtt/common");
var gencode = function () {
    function s4() {
        return Math.floor((1 + Math.random()) * 0x10000)
            .toString(16)
            .substring(1);
    }
    return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}

module.exports = {
    config: {
        mqtt_client: null,
        surprise: false,
        mqtt_username: "",
        mqtt_password: "",
        topics: [],
        mqtt_clientOptions: {
            host: "192.168.1.19",
            port: 8083,
            clientId: gencode(),
            path: '/mqtt',
            useSSL: false
        }
    },
    init: function (callback) {

        console.log('initialized connection');
        this.mqtt_clientOptions = this.config.mqtt_clientOptions;


        let self = this;

        this.mqtt_client = new MQTTClient(this.mqtt_clientOptions);

        this.mqtt_client.onConnectionFailure.on(function (err) {
            console.log("Connection failed: " + err);
            self.init();
        });

        this.mqtt_client.onConnectionSuccess.on(function () {
            console.log("Connection success!");
            if (callback) callback();
            else self.resubscribe();
        });

        this.mqtt_client.onConnectionLost.on(function (err) {
            console.log("Connection lost: " + err);
            self.init();
        });

        // this.mqtt_client.onMessageArrived.on(function (message) {
        //     console.log("Message received: " + JSON.parse(message.payload).message);
        // });


        console.log("mqtt init called");
        this.connect();
    },
    connect: function () {
        console.log("connecting...");
        try {
            this.mqtt_client.connect(this.config.mqtt_username, this.config.mqtt_password);
        }
        catch (e) {
            console.log("Caught error: " + e);
        }
    },
    getClient: function () {
        return this.mqtt_client;
    },
    subscribe: function (topic) {
        const self = this;
        if (self.mqtt_client.connected) {
            console.log('subscribe to ' + topic);
            if (self.config.topics.indexOf(topic) == -1) {
                try {
                    self.config.topics.push(topic);
                    this.mqtt_client.subscribe(topic);
                }
                catch (e) {
                    console.log("Caught error: " + e);
                }
            }
        }
    },
    resubscribe: function () {
        const self = this;
        if (self.mqtt_client.connected) {
            console.log('re-subscribing all');
            for (var i = 0; i < this.config.topics.length; i++) {
                var element = this.config.topics[i];
                try {
                    this.mqtt_client.subscribe(element);
                    console.log('resubscribed to ', element);
                }
                catch (e) {
                    console.log("Caught error: " + e);
                }
            }
        }
    },
    publish: function (message) {
        console.log("message", message);
        // var mqtt_message = new MQTTCommon.Message(message);
        try {
            console.log('message published to ' + message.topic);
            this.mqtt_client.publish(message);
        }
        catch (e) {
            console.log("Caught error: " + e);
        }
    }
}

I'm seeing this behavior as well.

Do subsequent connections fail after a minute or instantly?

Subsequent connections fail as well. For me, I'm also seeing this in my broker logs:

1551832536: Client my-test-client has exceeded timeout, disconnecting.
1551832536: Socket error on client my-test-client, disconnecting.

Do they fail after a minute or instantly?

They fail after what appears to be about 2.5 minutes.

Here is the complete broker log from the time the client connects to the time it disconnects. "my-test-client" is the client ID of my NativeScript app.

1551836600: New client connected from ::ffff:172.17.0.1 as my-test-client (c1, k60, u'').
1551836600: No will message specified.
1551836600: Sending CONNACK to my-test-client (0, 0)
1551836600: Received SUBSCRIBE from my-test-client
1551836600: 	/device/test-device-id-1/updated (QoS 0)
1551836600: my-test-client 0 /device/test-device-id-1/updated
1551836600: Sending SUBACK to my-test-client
1551836605: Received PINGREQ from mqttjs_a77046d5
1551836605: Sending PINGRESP to mqttjs_a77046d5
1551836607: Received PINGREQ from mqttjs_8227a3cb
1551836607: Sending PINGRESP to mqttjs_8227a3cb
1551836615: Received PINGREQ from mosqsub|6138-Darrells-M
1551836615: Sending PINGRESP to mosqsub|6138-Darrells-M
1551836630: Received PINGREQ from mqttjs_f4fd3342
1551836630: Sending PINGRESP to mqttjs_f4fd3342
1551836658: Received PINGREQ from mqttjs_78ec9a9d
1551836658: Sending PINGRESP to mqttjs_78ec9a9d
1551836660: Received PINGREQ from my-test-client
1551836660: Sending PINGRESP to my-test-client
1551836665: Received PINGREQ from mqttjs_a77046d5
1551836665: Sending PINGRESP to mqttjs_a77046d5
1551836667: Received PINGREQ from mqttjs_8227a3cb
1551836667: Sending PINGRESP to mqttjs_8227a3cb
1551836675: Received PINGREQ from mosqsub|6138-Darrells-M
1551836675: Sending PINGRESP to mosqsub|6138-Darrells-M
1551836690: Received PINGREQ from mqttjs_f4fd3342
1551836690: Sending PINGRESP to mqttjs_f4fd3342
1551836718: Received PINGREQ from mqttjs_78ec9a9d
1551836718: Sending PINGRESP to mqttjs_78ec9a9d
1551836725: Received PINGREQ from mqttjs_a77046d5
1551836725: Sending PINGRESP to mqttjs_a77046d5
1551836727: Received PINGREQ from mqttjs_8227a3cb
1551836727: Sending PINGRESP to mqttjs_8227a3cb
1551836735: Received PINGREQ from mosqsub|6138-Darrells-M
1551836735: Sending PINGRESP to mosqsub|6138-Darrells-M
1551836750: Received PINGREQ from mqttjs_f4fd3342
1551836750: Sending PINGRESP to mqttjs_f4fd3342
1551836751: Client my-test-client has exceeded timeout, disconnecting.
1551836751: Socket error on client my-test-client, disconnecting.

I'll update the plugin this week to expose more options from paho-mqtt, including a trace option to better debug this issue. This could be an issue with the keepalive, which is also not being exposed.

For the time being, you can try reconnecting whenever the connection stops (which is what I'm doing)

I actually already exposed keepAliveInterval in my testing. I also set up calls to start/get/stop traceLog with a reduced keepAliveInterval of 5. Here is the output of getTraceLog() if its any help:

CONSOLE LOG file:///app/status-view-model.js:56:16: Client.startTrace
CONSOLE LOG file:///app/status-view-model.js:56:16:   "2019-03-06T02:13:11.338Z"
CONSOLE LOG file:///app/status-view-model.js:56:16:   "@VERSION@-@BUILDLEVEL@"
CONSOLE LOG file:///app/status-view-model.js:56:16: Client.connect
CONSOLE LOG file:///app/status-view-model.js:56:16:   {"userName":"","password":"******","useSSL":false,"keepAliveInterval":5,"mqttVersionExplicit":false,"mqttVersion":4,"cleanSession":true}
CONSOLE LOG file:///app/status-view-model.js:56:16:   null
CONSOLE LOG file:///app/status-view-model.js:56:16:   false
CONSOLE LOG file:///app/status-view-model.js:56:16: Client._socket_send
CONSOLE LOG file:///app/status-view-model.js:56:16:   {"type":1,"userName":"","password":"******","useSSL":false,"keepAliveInterval":5,"mqttVersionExplicit":false,"mqttVersion":4,"cleanSession":true,"clientId":"my-test-client"}
CONSOLE LOG file:///app/status-view-model.js:56:16: Client._on_socket_message
CONSOLE LOG file:///app/status-view-model.js:56:16:   {}
CONSOLE LOG file:///app/status-view-model.js:56:16: Client._handleMessage
CONSOLE LOG file:///app/status-view-model.js:56:16:   {"type":2,"returnCode":0}
CONSOLE LOG file:///app/status-view-model.js:56:16: Client.subscribe
CONSOLE LOG file:///app/status-view-model.js:56:16:   "/device/test-device-id-1/updated"
CONSOLE LOG file:///app/status-view-model.js:56:16:   {}
CONSOLE LOG file:///app/status-view-model.js:56:16: Client._socket_send
CONSOLE LOG file:///app/status-view-model.js:56:16:   {"type":8,"topics":["/device/test-device-id-1/updated"],"requestedQos":[0],"messageIdentifier":1}
CONSOLE LOG file:///app/status-view-model.js:56:16: Client._on_socket_message
CONSOLE LOG file:///app/status-view-model.js:56:16:   {}
CONSOLE LOG file:///app/status-view-model.js:56:16: Client._handleMessage
CONSOLE LOG file:///app/status-view-model.js:56:16:   {"type":9,"messageIdentifier":1,"returnCode":{"0":0}}
CONSOLE LOG file:///app/status-view-model.js:56:16: Pinger.doPing
CONSOLE LOG file:///app/status-view-model.js:56:16:   "send PINGREQ"
CONSOLE LOG file:///app/status-view-model.js:56:16: Client._on_socket_message
CONSOLE LOG file:///app/status-view-model.js:56:16:   {}
CONSOLE LOG file:///app/status-view-model.js:56:16: Client._handleMessage
CONSOLE LOG file:///app/status-view-model.js:56:16:   {"type":13}
CONSOLE LOG file:///app/status-view-model.js:56:16: Pinger.doPing
CONSOLE LOG file:///app/status-view-model.js:56:16:   "send PINGREQ"
CONSOLE LOG file:///app/status-view-model.js:56:16: Client._disconnected
CONSOLE LOG file:///app/status-view-model.js:56:16:   8
CONSOLE LOG file:///app/status-view-model.js:56:16:   "AMQJS0008I Socket closed."
CONSOLE LOG file:///app/status-view-model.js:56:16: Client.getTraceLog
CONSOLE LOG file:///app/status-view-model.js:56:16:   "2019-03-06T02:13:24.299Z"
CONSOLE LOG file:///app/status-view-model.js:56:16: Client.getTraceLog in flight messages
CONSOLE LOG file:///app/status-view-model.js:56:16: undefined

Could you also try it using https://www.eclipse.org/paho/clients/js/utility/ ?

So we can check if the problem is with paho mqtt or with NS websockets. If it also disconnects on the web, it might be an issue with the web server

Edit: Untick "automatic reconnect"

I get an immediate connection timeout when I visit that page:

Wed, 06 Mar 2019 23:19:27 GMT - INFO - Starting Eclipse Paho JavaScript Utility.
Wed, 06 Mar 2019 23:19:37 GMT - INFO - Connecting to Server: [Host: iot.eclipse.org, Port: 443, Path: /ws, ID: js-utility-Eyicv]
Wed, 06 Mar 2019 23:19:43 GMT - ERROR - Failed to connect. [Error Message: AMQJSC0001E Connect timed out.]

@DarrellBrogdon use your own broker, I think iot.eclipse.org isn't working atm

I've exposed most of the stuff in a separate branch, see #10.

The new implementation properly exposes trace options and allows you to use most of the options given by the Paho MQTT Client. This is not final, but probably somewhat close to it.

They fail after what appears to be about 2.5 minutes.

Here is the complete broker log from the time the client connects to the time it disconnects. "my-test-client" is the client ID of my NativeScript app.

1551836600: New client connected from ::ffff:172.17.0.1 as my-test-client (c1, k60, u'').
1551836600: No will message specified.
1551836600: Sending CONNACK to my-test-client (0, 0)
1551836600: Received SUBSCRIBE from my-test-client
1551836600: 	/device/test-device-id-1/updated (QoS 0)
1551836600: my-test-client 0 /device/test-device-id-1/updated
1551836600: Sending SUBACK to my-test-client
1551836605: Received PINGREQ from mqttjs_a77046d5
1551836605: Sending PINGRESP to mqttjs_a77046d5
1551836607: Received PINGREQ from mqttjs_8227a3cb
1551836607: Sending PINGRESP to mqttjs_8227a3cb
1551836615: Received PINGREQ from mosqsub|6138-Darrells-M
1551836615: Sending PINGRESP to mosqsub|6138-Darrells-M
1551836630: Received PINGREQ from mqttjs_f4fd3342
1551836630: Sending PINGRESP to mqttjs_f4fd3342
1551836658: Received PINGREQ from mqttjs_78ec9a9d
1551836658: Sending PINGRESP to mqttjs_78ec9a9d
1551836660: Received PINGREQ from my-test-client
1551836660: Sending PINGRESP to my-test-client
1551836665: Received PINGREQ from mqttjs_a77046d5
1551836665: Sending PINGRESP to mqttjs_a77046d5
1551836667: Received PINGREQ from mqttjs_8227a3cb
1551836667: Sending PINGRESP to mqttjs_8227a3cb
1551836675: Received PINGREQ from mosqsub|6138-Darrells-M
1551836675: Sending PINGRESP to mosqsub|6138-Darrells-M
1551836690: Received PINGREQ from mqttjs_f4fd3342
1551836690: Sending PINGRESP to mqttjs_f4fd3342
1551836718: Received PINGREQ from mqttjs_78ec9a9d
1551836718: Sending PINGRESP to mqttjs_78ec9a9d
1551836725: Received PINGREQ from mqttjs_a77046d5
1551836725: Sending PINGRESP to mqttjs_a77046d5
1551836727: Received PINGREQ from mqttjs_8227a3cb
1551836727: Sending PINGRESP to mqttjs_8227a3cb
1551836735: Received PINGREQ from mosqsub|6138-Darrells-M
1551836735: Sending PINGRESP to mosqsub|6138-Darrells-M
1551836750: Received PINGREQ from mqttjs_f4fd3342
1551836750: Sending PINGRESP to mqttjs_f4fd3342
1551836751: Client my-test-client has exceeded timeout, disconnecting.
1551836751: Socket error on client my-test-client, disconnecting.

For me too, when it fails after a minute, subsequent reconnections also fails when i try to reconnect on failure and loops infinitely...

Connection lost: AMQJS0008I Socket closed.' JS: 'initialized connection' JS: 'mqtt init called' JS: 'connecting...' JS: 'Connection success!' JS: 'Connection lost: AMQJS0008I Socket closed.' JS: 'initialized connection' JS: 'mqtt init called' JS: 'connecting...' JS: 'Connection success!' JS: 'Connection lost: AMQJS0008I Socket closed.' JS: 'initialized connection' JS: 'mqtt init called' JS: 'connecting...' JS: 'Connection success!' JS: 'Connection lost: AMQJS0008I Socket closed.' JS: 'initialized connection' JS: 'mqtt init called' JS: 'connecting...' JS: 'Connection success!' JS: 'Connection lost: AMQJS0008I Socket closed.' JS: 'initialized connection' JS: 'mqtt init called' JS: 'connecting...' JS: 'Connection success!' JS: 'Connection lost: AMQJS0008I Socket closed.' JS: 'initialized connection' JS: 'mqtt init called' JS: 'connecting...' JS: 'Connection success!' JS: 'Connection lost: AMQJS0008I Socket closed.' JS: 'initialized connection' JS: 'mqtt init called' JS: 'connecting...'

Have you had any success testing on https://www.eclipse.org/paho/clients/js/utility/ ? Does it also fail there (uncheck auto reconnect, use the same broker you're trying to use)

I haven't had a chance to test it yet. I'll try to do so today.

I can't reproduce it using broker.mqttdashboard.com. I'm testing the version 2.0 today and spent a good deal of time today connected to it while coding and writing tests. Also, I added a reconnect button to the demo, and it never failed to reconnect.

I've pushed some code to the paho-refactor branch if you want to run the demo with the reconnect button+time to connect message

Edit:

last test result:

image

The second mqtt connect was me hitting the reconnect button

This is what I see:

CONSOLE LOG file:///app/main-view-model.js:126:20: connecting
CONSOLE LOG file:///app/main-view-model.js:126:20: Mqtt connected
CONSOLE LOG file:///app/main-view-model.js:126:20: Mqtt connection stablished {"reconnect":false,"uri":"ws://broker.mqttdashboard.com:8000/mqtt"}
CONSOLE LOG file:///app/main-view-model.js:126:20: Message received. Topic: testtopic/1. Payload: iozlukjhgf
CONSOLE LOG file:///app/main-view-model.js:126:20: Mqtt connection lost: {"errorCode":4,"errorMessage":"AMQJS0004E Ping timed out.","reconnect":false,"uri":"ws://broker.mqttdashboard.com:8000/mqtt"}
CONSOLE LOG file:///app/main-view-model.js:73:24: Time connected: 3m 0.3739999999999952s

As I said before, please try using https://www.eclipse.org/paho/clients/js/utility/ to check if the error is exclusive to mobile or may be an issue with your broker...

Ok, I see that you used broker.mqttdashboard.com, so let's establish some things:

  1. If your connection fails, it's expected that MQTT also fails and disconnects. This is expected behavior.
  2. If your MQTT disconnects, you have to deal with it. This called fault tolerance and recovery and every software in existence has to implement it in some kind of way. In this case, you should probably try to reconnect.

Now let's take a look at this issue. If you got a disconnect, it may be because your connection failed (1). So you try recovering it (2). If you're unable to reconnect, but can reconnect when restarting the app, then we have an issue.

If you get CONSTANTS disconnects after a certain amount of time, this might be an issue with this plugin. But if it works on other brokers (like mqttdashboard) and not yours, might be an issue with YOUR broker.

So far, this is the results of my testing:

  1. I've experienced disconnects only on large amounts of time using broker.mqttdashboard.com, this was one disconnect after 20 minutes and no disconnects for over an hour.
  2. every disconnect I experienced was recoverable by reconnecting

This issue is about two things:

  1. disconnect after a minute
  2. problems reconnecting

Unless you can provide me with an example in which 1 or 2 happens, I'm going to have to close this issue.

In my project (which uses the master branch) I was able to reconnect, but it does disconnect after about a minute regardless.

I'll test the branch with connecting to my broker to see what happens. I feel like it disconnecting after 20 minutes is ok but 1-3 minutes is problematic. That seems really inefficient to have to reconnect that much.

Also, when you say try using https://www.eclipse.org/paho/clients/js/utility/, what values should I be using in the form?

Host: your broker (192.168.etc or my.broker.com or broker.mqttdashboard.com)
Port: port you're using to connect
Path: /mqtt /ws etc (or nothing, based on your broker)

Check/Uncheck TLS accordingly (same as useSSL). Untick "Automatic Reconnect".

If you uncheck TLS and hit connect, chrome may complain about insecure stuff, so you have to click the little shield by the address bar and click "load unsafe scripts".

My best guess is that your network is failing sometimes and dropping some MQTT packets that trigger a disconnect.

My broker is running locally on my machine for now so I'm not able to use that utility to test it.

If I try to connect to broker.mqttdashboard.com I get "Failed to connect: AMQJS0007E Socket error:undefined." Port=8000, Client ID=js-utility-VEdxd, Path=/mqtt, TLS and Automatic Reconnect are unchecked.

You have to check "load unsafe scripts" by the address bar if not using SSL.

It's using SSL. I don't have any VPN or filtering running that would affect this so I'm not sure why it's unable to connect.

So I put my broker on a remote server and tested it both by using mosquitto_sub on the command line and using http://www.hivemq.com/demos/websocket-client/ (I still can't get https://www.eclipse.org/paho/clients/js/utility/ working). Neither of those time out. However, when I run the latest demo code I still get the "AMQJS0008I Socket closed." error.

CONSOLE LOG file:///app/main-view-model.js:187:20: Connecting to ws://my-broker-host:9001
CONSOLE LOG file:///app/main-view-model.js:187:20: onConnectionSuccess
CONSOLE LOG file:///app/main-view-model.js:187:20: onConnected: {"reconnect":false,"uri":"ws://my-broker-host:9001"}
CONSOLE LOG file:///app/main-view-model.js:187:20: onSubscribeSuccess: {"grantedQos":0}
CONSOLE LOG file:///app/main-view-model.js:187:20: (Promise) Subscribed to /device/test-device-id-1/updated {"grantedQos":0}
CONSOLE LOG file:///app/main-view-model.js:187:20: onMessageArrived: {"destinationName":"/device/test-device-id-1/updated","payloadString":"Test Message 5","duplicate":false,"retained":false,"qos":0}
CONSOLE LOG file:///app/main-view-model.js:187:20: onConnectionLost: {"errorCode":8,"errorMessage":"AMQJS0008I Socket closed.","reconnect":false,"uri":"ws://my-broker-host:9001"}
CONSOLE LOG file:///app/main-view-model.js:104:24: Time connected: 2m 37.07599999999999s

what android version are you using? are you using the android emulator, physical device or other emulators (like genymotion)?

I'm using iOS actually. I'm using the iPhone XR simulator running iOS 12.1.

Could you try running on Android so we can determine if it's something specific to iOS?

Looks like you may be right. It has been running for about 10 minutes now on the Android emulator (Pixel_2_XL_Pie avd) without any disconnect.

@DarrellBrogdon can you test something out?

Try setting application.ios.nativeApp.idleTimerDisabled = true; (application comes from tns-core-modules/application).

Maybe the issue comes from app inactivity, as it seems to close sockets

I'm getting this error when I do: file:///app/app.js:8:26: JS ERROR TypeError: null is not an object (evaluating 'application.ios.nativeApp.idleTimerDisabled = true')

Try this:

declare var UIApplication: any;

UIApplication.sharedApplication.idleTimerDisabled = true;

if that doesn't work, just create a dummy button and tap it from time to time, just to test if the socket closing is a result from inactivity

I'm using Vanilla JS but testing with a dummy button, clicking every ~5-10 seconds didn't seem to make a difference. It still eventually loses the connection.

Any more solution ideas?