0

I have a Broadcast receiver that checks WIFI_STATE_CHANGE to see if I have connected to a certain WiFi network. For example if I am coming home, I want a certain MQTT message to be sent. The problem I have is that it connects and sends the MQTT message, only when run the app the first time.

Process:

  1. If I build the application and run it on the device and it recognised my home WiFi it sends the message.
  2. I turn off Wifi from the device, and turn it back on again.
  3. I get "Failure" which is a message when the MQTT connection to the server could not be established.

What I would need is that after I reconnect to the network, instead of "Failure" to get "Connected" but somehow it never happens...what could be wrong?

PS. I think it has to do with the fact that when WiFi is detected, the Broadcast Receiver runs the connection code, although Internet is not available at that point of time (obtaining IP etc.)

Here is the code of the Broadcast receiver:

package me.app.comehomedemo;

import ...
 

public class SynchronizeBroadcastReceiver extends BroadcastReceiver {


   
    MqttAndroidClient client;
    static String MQTTHOST = "myhost";
    static String USERNAME = "myusername";
    static String PASSWORD = "mypassword";
    static String topicStr = "/topic/mac/control";
    static String payload = "1";


    @Override
    public void onReceive(final Context context, Intent intent) {


        NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);


        if (info.isConnected()) {


            WifiManager wifiManager = ( WifiManager ) context.getSystemService(Context.WIFI_SERVICE);
            WifiInfo wifiInfo = wifiManager.getConnectionInfo();

            int ip = wifiInfo.getIpAddress();

            Toast.makeText(context, String.valueOf(ip), Toast.LENGTH_SHORT).show();


            String ssid = wifiInfo.getSSID();

            if (ssid.equals("\"mySSID\"")) {


                String clientId = MqttClient.generateClientId();
            client = new MqttAndroidClient(context.getApplicationContext(), MQTTHOST, clientId);
            MqttConnectOptions options = new MqttConnectOptions();
            options.setUserName(USERNAME);
            options.setPassword(PASSWORD.toCharArray());
         //   options.setAutomaticReconnect(true);




                   try {
                       IMqttToken token = client.connect(options);
                       token.setActionCallback(new IMqttActionListener() {
                           @Override
                           public void onSuccess(IMqttToken asyncActionToken) {
                               // We are connected
                               Toast.makeText(context, "Connected", Toast.LENGTH_SHORT).show();
                               try {

                                   client.publish(topicStr, payload.getBytes(), 0, false);
                               } catch (MqttException e) {
                                   e.printStackTrace();
                               }
                           }

                           @Override
                           public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                               // Something went wrong e.g. connection timeout or firewall problems
                               Toast.makeText(context, "Failure", Toast.LENGTH_SHORT).show();

                           }
                       });
                   } catch (MqttException e) {
                       e.printStackTrace();
                   }


                Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
                MediaPlayer mp = MediaPlayer.create(context.getApplicationContext(), notification);
                mp.start();


            }

        }
    }

    }

2 Answers2

0

I have managed to solve it by waiting 2 seconds and then running the task. Used this solution and it worked. I had to wait for the Internet connection to get ready!

0

Since waiting 2 seconds has solved your problem, then it might be that the Wifi broadcast comes too early, before there is a connection established (like DHCP gives your phone IP and establishes the routes) for the MQTT connect and publish packets to be properly delivered.

But what happens if some other user needs to wait 10 and not 2 seconds?

My suggestion is to set the automatic reconnect option in MqttConnectOptions and then use the connection callback to publish the needed info to the broker and finally disconnect in publish callback:

private IMqttActionListener mConnectCallback = new IMqttActionListener() {
    @Override
    public void onSuccess(IMqttToken token) {
        try {
            client.publish(topicStr, new MqttMessage(payload.getBytes()), null, mPublishCallback);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void onFailure(IMqttToken token, Throwable ex) {
    }
};

private IMqttActionListener mPublishCallback = new IMqttActionListener() {
    @Override
    public void onSuccess(IMqttToken token) {
         // TODO disconnect
    }

    @Override
    public void onFailure(IMqttToken token, Throwable ex) {
    }
};

MqttAndroidClient client = new MqttAndroidClient(context, MQTTHOST, "my_id");
MqttConnectOptions options = new MqttConnectOptions();
options.setUserName(USERNAME);
options.setPassword(PASSWORD.toCharArray());
options.setAutomaticReconnect(true);
client.connect(options, null, mConnectCallback);
Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
  • For some reason I didnt manage to make ît work with your code. Callbacks are never called. There is also a "mClient" inc the code which probably has to become client. – Vasileios Antoniadis Sep 17 '17 at 09:48