Imagine the following situation: you have an IoT project in your local WIFI network and want to be able to control it / read data from it using a mobile app. Doesn’t sound like something you need to imagine, but rather actually need for your use case? Well, then you’ve come to the right place. In this article I will be showing you how to discover devices using a mobile application built with Flutter.
The Basic Concept
There are two standard approaches when it comes to device discovery on a local network:
- Send out a UDP broadcast from the device that is to be discovered and then listen for UDP broadcasts in the app. This approach is done i.e.when searching for local network printers. Since e
- The second way device discovery can be done, is by setting up a web server on the device and make a REST endpoint available which can identify the device, i.e. return meta information about the device. The app would scan for all IP addresses given a certain sub net and test the IP address for the REST endpoint and see what information comes back. This solution clearly isn’t the most performant.
Optimally, we should use the first option. However, Flutter doesn’t quite yet have a package sending / receiving a UDP broadcast, so we’ll be using the second option, which is still perfectly legitimate and fine to use, unless you absolutely need a performant option.
The IoT Device
Let’s start with the device that we want to be able to discover from the Flutter application. We need to do the following things:
- Connect our device to the local network
- Create an endpoint that will return some meta information about the device
The easiest way to get started is by using a chip that has an integrated ESP32 or ESP8266 chip. Either the NodeMCU or the Arduino MKR1010 would be an option.
If you don’t know how to connect your chip to your local network, you can check out my article on getting started with creating an IoT device.
For creating a REST endpoint on the device, we will be using the library called arest, which you can learn more about here. Creating a REST endpoint with arest is very simple. At the top of your code, you define a global object using the aREST class. The setup function is then the place where you define your endpoints and variables. Lastly, you need to handle incoming requests with your aREST object. The code for your device would look something like this:
The Flutter Application
We will be using Flutter to display a list of devices, that can be reached by the endpoint “/helloWorld”.
Let’s start with the UI of the app. We’ll use a ListView to display the IP addresses of the local devices.
The main layout of our app will contain the following:
As you can see, it’s quite simple. We also need two more classes that are imported at the top of the main file. One of the classes is just a container class that you can expand to list some meta information about the device. The other class is a container class for the list items that will be going inside of our ListView.
The container class for the meta information about the device looks like this:
The other class is looks like this:
The Actual Logic
Now that we have the UI finished, we can go ahead and implement the logic to find local devices connected to the WIFI network. Luckily, there is already a Flutter package that allows us to do this, so scanning for local devices has been made easy.
The package that we will be using is called ping_discover_network and can be found here. To make an http call to the device, we will also need the http dependency and the wifi dependency in our pubspec.yaml file. We need to include these dependencies to the top of our main layout file.
We also need the logic, which we can basically copy from the example from the ping_discover_network package.
Inside of the stream callback, on line 9 of the “_scanDevices” function, we can test the IP address for the “helloWorld” REST endpoint.
And thats it! If you start the app on a real device, not a simulator, you will see the IP address of the IoT device that we created before. If the app is started on a simulator, you won’t see the device, since the simulator is not connected to your WIFI network by default.
You can expand this project by adding meta information about the device, by adding rest variables. They can only be accessed through the root endpoint and are returned in JSON format. To add these variables, just add the following line of code to the setup function of your device:
String DEVICE_TYPE = "Normal";
The variable “DEVICE_TYPE” needs to be a global variable of your sketch and the rest.variable call needs to be contained in the setup function of your sketch. If you now access the device over its IP address in your browser at the root endpoint, you will see that the JSON that is returned, contains the variable “type”.
Now that you have a basic application that can reach an IoT device through REST endpoints, you can start building extra functionalities to it to display temperature data, a camera feed, or whatever your imagination can think of.
You can find the full source code here.