# Background notifications from OpenWRT to Android This research started as part of a need from the [LibreRouter team](https://librerouter.org) to be able to get to reliably call the user's attention. When the user has the [LiMe-App](https://github.com/libremesh/lime-app) (The web app used to manage the router) in foreground and with the screen unlocked in their phone, sending notifications is easy, as the LiMe-App can poll for these events. The issue comes when an event happens and the user doesn't have the Lime-App open, which happen to be most of the time. The situations when this could happen are, for example: 1. a cable got disconnected and, if unnoticed by the user, services might not work as expected 2. internet went down on the network, and it would be good for the community to get on working on it as soon as possible 3. the link quality of the wireless links have changed drastically and it would be good for the user to get on improving that link that historically was better than today 4. the router has been rebooting too frequently and it would be good if the user could check the power source 5. the router wants the user's device to remember certain information that the router itself won't be able to remember after a reboot, for example regular checks, metrics, peers, etc. 6. request the user's phone to do things for the router, like accesing the gps, the compass, store things, do maths, 7. ask the user to authorize an action, like an update, signing a mesh-wide config change In any case, there is no way as of now to deal with this usecase. There are different strategies to tackle this issue: 1. MQTT: it has an extensive ecosystem and broad adoption, as well as being a ISO Standard. For Android there is [a library and a service that deals with the background task](https://github.com/eclipse/paho.mqtt.android), and there is [an MQTT Broker on OpenWRT, that doesn't require SSL](https://openwrt.org/packages/pkgdata_lede17_1/mosquitto-nossl). There is a [javascript version also](https://github.com/mqttjs/MQTT.js/). 2. Using [Server-Sent Events](https://en.wikipedia.org/wiki/Server-sent_events): is a server push technology enabling a client to receive automatic updates from a server via HTTP connection. This implementation is important because it is a push technology that can be implemented in a very simple hardware, and it is featureful while being simple. In a previous article we have already shown that they can be used to receive system messages from the system bus in realtime using this method: https://bugs.openwrt.org/index.php?do=details&task_id=2248 We are trying not to use SSL to reduce storage footprint and CPU use. So... as it appears, the best approach is to use MQTT, with certain caveats that are related to power consumption on Android, like this: * https://stackoverflow.com/questions/38005444/android-mqtt-mosquitto-how-to-operate-in-background/41916794 * https://developer.android.com/topic/performance/background-optimization ## MQTT As mentioned previously... ### Client Relevant links: * https://www.hivemq.com/blog/mqtt-client-library-enyclopedia-paho-android-service/ * https://github.com/eclipse/paho.mqtt.android In order for this to compile I had to: 1. download android-studio: https://developer.android.com/studio 2. clone and import this repo: https://github.com/nicopace/paho.mqtt.android 3. build You can use this [web client](http://www.hivemq.com/demos/websocket-client/) to connect to the mqtt configured on this sample project, mqtt.eclipse.org:80, and send messages on topic `exampleAndroidTopic` that will get received on the android app. Messages will arrive no matter if the app is on foreground or background. Messages won't arrive if the app is closed though, work needs to be done for that to still happen. ### Broker On OpenWRT we have a few options. 1. the tried and true Mosquitto: https://openwrt.org/packages/pkgdata_lede17_1/mosquitto-nossl 2. some lean implementation, but it depends on ssl for now: https://github.com/homewsn/homewsn.openwrt.packages and https://github.com/homewsn/whsnbg As it has a broader community we will try Mosquitto. In order to try it out on an openwrt image, you can do `opkg install mosquitto-nossl` or add the following line to your .config: ``` CONFIG_mosquitto-nossl=y # have also added the client so i can call it directly from the router CONFIG_mosquitto-client-nossl=y ``` In order to test it out, I modified the [broker's serverUri](https://github.com/nicopace/paho.mqtt.android/blob/master/paho.mqtt.android.example/src/main/java/paho/mqtt/java/example/PahoExampleActivity.java#L44) to `tcp://` so it could connect to the broker I just installed, connected the phone and the computer to the same wireless network and while watching the logs on the dev tools sent a message with the following command `mosquitto_pub -h -t exampleAndroidTopic -m "ON" -d`. the message is received by the text shown on the logs triggered by [this line in the code](https://github.com/nicopace/paho.mqtt.android/blob/master/paho.mqtt.android.example/src/main/java/paho/mqtt/java/example/PahoExampleActivity.java#L190). Screen of the debug console when you send a message over the router: ![](https://i.imgur.com/VlA3hGl.gif) Screen of the test app: ![](https://i.imgur.com/o3UxDre.jpg) I then added a notification that will take will open the LiMe-App and will pass the message over the URL: ![](https://i.imgur.com/spGfOMM.gif) You can even send a message that will send you to a LiMe-App specific page, like if you send `/notes` you will be redirected directly to that page: ![](https://i.imgur.com/p5ishj4.gif) If you want to debug the messages, you can use the `mosquitto_sub` command like so: `mosquitto_sub -h -i desktop -t exampleAndroidTopic`. ## Examples of use ### Detect when a cable is connected to the switch ```bash #!/bin/sh while true; do old_status=$port_status port_status=`swconfig dev switch0 show | grep link | cut -d\ -f2-3` old_status=`echo -e "${port_status}"` ports_changed=`echo -e "${old_status}\n${port_status}" | sort | uniq -u | cut -d\ -f 1 | sort -u` if ! test -z "$ports_changed" then mosquitto_pub -h -t exampleAndroidTopic -m "ports_changed/$ports_changed" -d fi sleep 1 done ``` ### Let the user know that a new device got connected to their router ```bash #!/bin/sh # configure dnsmasq with --dhcp-script= this script # based on this article: https://jpmens.net/2013/10/21/tracking-dhcp-leases-with-dnsmasq/ op="${1:-op}" mac="${2:-mac}" ip="${3:-ip}" hostname="${4}" tstamp="`date '+%Y-%m-%d %H:%M:%S'`" topic="network/dhcp/${mac}" payload="${op} ${ip} ${tstamp} (${hostname})" mosquitto_pub -h -t "${topic}" -m "${payload}" -r ``` ### notify the user when there is no internet ```bash #!/bin/sh # Add this script tp /etc/watchping/wan-fail.d/ mosquitto_pub -h -t "wan-fail" -m "wan-fail" -r ``` ## Pending issues ### Client 1. Allow the LiMe-App to talk to the daemon to ask for previous messages 2. Receive messages even if the app is closed manually by the user, and start the app on boot. ### Broker 1. Connect ubus messaging with MQTT 2. Compile Mosquitto with websocket support (so the browser can access it directly) but without SSL (so it doesn't weight too much): can be done as shown in https://github.com/nicopace/owsd-tiny ## Ideas If using MQTT in the Mesh, you could have one broker running on each node of the mesh, and replicate the information through the mesh by connecting to your neighbouring nodes to spread the information like it is explained here: https://selfhostedhome.com/using-two-mqtt-brokers-with-mqtt-broker-bridging/ . It seems it is included in Mosquitto already: https://owntracks.org/booklet/guide/bridge/