How to make an IoT app using Flutter, Firebase and NodeMCU ESP8266?

Rushank Shah
8 min readDec 26, 2020

What will we build?

We will build a simple system using Flutter for app, Firebase as backend and NodeMCU ESP8266 as the WiFi board to control an LED. You will be able to turn this LED on and off from anywhere around the world with just internet access, but after reading this article you will be able to understand, how you can control any electrical component with just a few minor tweaks in the code.

Final Application

How will the system work?

The system is pretty simple. We will send the command to control the LED from the app to Firebase Realtime Database. The microcontroller would request continuously to the database for the LED_Status to check the status of the LED, for should it turn it on or off.

System

Let’s Start!!

We will first create a Firebase application, then work on the Flutter app, and then work with the code for microcontroller. Let’s go!

Note: If you are in a hurry, and you can understand codes by yourself, you can head to this link for the Flutter app and this link for the microcontroller’s code.

Step 1: Set up Firebase

1.Head over to Firebase and go to the Firebase Console.

2. Create a new Project and give it any name you want. I would name it as IOT Example. You should see a screen similar to this. (I have already added an Android project but you won’t have one in your own project. But later I will link a demo on how you can integrate Firebase with Flutter).

Firebase application

3. Now you have your Firebase project setup. We will use Firebase Realtime Database to store the LED_Status.

Step 2: Setup the Flutter App

1.Start a new Flutter project in Android Studio (or using CLI) and name it whatever you want. Here, I will name it iot_app.

2. Remove all the boilerplate code provided by Flutter and just create a Stateless Widget which returns a MaterialApp.

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.purple,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomePage());
}
}

3. Next we will create the Layout of the app. The HomePage would be a Stateful Widget as we are going to change the On/Off button state in runtime.

4.The design of the app is pretty minimalistic. I’ve just added a Simple AppBar and a RaisedButton at the Centre of the screen.

class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'IOT App',
),
),
body: Center(
child: RaisedButton(
child: Text(
'On'
)
),
),
);
}
}

5. Next Step is to integrate Firebase in our Flutter app. You can refer this article to follow the steps. (Only follow the steps till integrating Firebase with Flutter. Don’t integrate Cloud Firestore with the app.)

6. After integrating Firebase in our project, we will add the Firebase Realtime Database package to manipulate data in the database. You can find it over here.

7. I will add the GoogleFonts package to style my text but you may skip that part.

dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.3
google_fonts: ^1.1.0
firebase_database: ^3.1.6

8. Above are the final dependencies for my project in pubspec.yaml. (GoogleFonts is not mandatory and CupertinoIcons is the default package provided by Flutter.)

Now let’s start building up the app 😄

1.To connect to the database, we will need a reference to our database. For that first import the Firebase from firebase_database package.

import 'package:firebase_database/firebase_database.dart';

2. Next step is to get a reference to the firebase database. We will keep the reference a global variable in _HomePageState class.

final DBref = FirebaseDatabase.instance.reference();

3. We will need two more variables. Namely ledStatus (int) and isLoading (boolean). The ledStatus is the variable which we will use to manage the status of the LED in our app so that our app knows whether the LED is on or off and isLoading is used so that when the app starts we can read the ledStatus from the database and show an indicator while we get the status of the LED.

int ledStatus = 0;
bool isLoading = false;

4. When the app starts, we need to know the status of the LED so that we can show appropriate text on the button. We will override the initState function of the HomePage and add a functionality to fetch the status of the LED from the database. This is how you can implement the getLEDStatus function :

getLEDStatus() async {
await DBref.child('LED_STATUS').once().then((DataSnapshot snapshot) {
ledStatus = snapshot.value;
print(ledStatus);
});

setState(() {
isLoading = false;
});
}

@override
void initState() {
isLoading = true;
getLEDStatus();
super.initState();
}

5. Next we will change the body of our Scaffold to update with our variables and we will call a function in the onPressed of the RaisedButton. The final build function would look something like this:

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'IOT App',
style:
GoogleFonts.montserrat(fontSize: 25, fontStyle: FontStyle.italic),
),
),
body: Center(
child: isLoading
? CircularProgressIndicator()
: RaisedButton(
child: Text(
ledStatus == 0 ? 'On' : 'Off',
style: GoogleFonts.nunito(
fontSize: 20, fontWeight: FontWeight.w300),
),
onPressed: () {
buttonPressed();
},
),
),
);
}

6. Next we will write the buttonPressed function. In this function we will use the ledStatus variable to change the state of the button and send data to the database. This is how you can implement the function:

void buttonPressed() {
ledStatus == 0
? DBref.child('LED_STATUS').set(1)
: DBref.child('LED_STATUS').set(0);
if (ledStatus == 0) {
setState(() {
ledStatus = 1;
});
} else {
setState(() {
ledStatus = 0;
});
}
}

The app is now ready 🥳. You can now run the app and see the LED status variable in the firebase console live.

You can find the complete code here.

Step 3: Writing and uploading code to Esp8266

Head over to this link and find the complete code over there. You just need to make a few changes and then you can use the code.

Some Prerequisites required to run the code:

  1. You need to add two libraries to the Arduino IDE, namely ArduinoFirebase and ArduinoJSON (Please download the 5.x version of ArduinoJSON as 6.x version causes unexpected errors).
  2. You can follow this tutorial on how to add libraries in Arduino IDE.
  3. If you haven’t yet, you also need to download the Esp8266 board for the code to compile for that microcontroller. You can follow this tutorial to do so.
  4. Next select the NodeMCU 1.0 (Esp-12E Module) from the boards.

Now, when all the setup is done, we can focus on the code!

When you head over to the code, you will have to change just four different things there:

  • WiFi name
  • WiFi password
  • Firebase URL
  • Firebase Secret

WiFi name and WiFi password are pretty obvious fields.

The Firebase Host is the URL which you can find in the Firebase Console’s Realtime Database.

Firebase URL

Note: You have to remove ‘https://’ from the start and the ‘/’ at the end.

So here, the Firebase URL will become iot-example-3d87a.firebaseio.com

Next up, is the Firebase secret key. You can find it in the Firebase Console at:

Project Overview -> Project Settings -> Service Accounts and then go to Database Secrets. You will find the database secret for your Firebase app over there.

Firebase secret

Enter the Firebase Secret in the FIREBASE_AUTH variable.

Now let’s look at the remaining code

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
// connect to wifi.
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("connecting");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println();
Serial.print("connected: ");
Serial.println(WiFi.localIP());
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
WiFi.setSleepMode(WIFI_NONE_SLEEP);
pinMode(D1,OUTPUT);
}

The setup function is pretty self explanatory. We are first setting up the baud rate, then the WiFi Setup and then the Firebase setup.

Note: WiFi.setSleepMode has been set to never sleep which means WiFi will never disconnect.

pinMode() is the basic function of Arduino which specifies each pin whether it is OUTPUT or INPUT pin.

Now let’s move over to the loop function:

int n = 0;  
void loop() {
// set value
n=Firebase.getInt("LED_STATUS");
Serial.println(n);
// handle error
if (n==1) {
Serial.print("LED is ON");
digitalWrite(D1,HIGH);
Serial.println(Firebase.error());
}
else if (n==0){
Serial.print("LED is OFF");
digitalWrite(D1,LOW);
Serial.println(Firebase.error());
}
else{
Serial.println("error");
}
}

We have kept a variable n to store the value of the LED Status. Firebase.getInt() function takes a String as the parameter which is the parameter of the attribute in Firebase console. This function returns an integer which specifies the current state of LED.

If n is 1, which means we need to turn on the LED and hence, we have set the D1 pin to high and turn the LED off for n = 0 so we set D1 to low.

So this was pretty much about it from coding side. Before uploading the code, you need to download the ESP8266 boards in your Arduino IDE if you haven’t yet. You can find a written tutorial over here about it.

While uploading the code make sure that that you have selected NodeMCU 1.0 (ESP-12E Module) as the board.

Circuit Diagram:

Circuit Diagram

Congratulation 🥳🥳, you have finally completed the whole setup for Flutter and IOT control with NodeMCU Esp8266. Now you can give the microcontroller power supply and start controlling it with the app. The LED will turn on and as per your instructions.

Conclusion

So with this tutorial completed, you can now control devices through IOT. A good roadmap to build this kind of project would be to go step by step, i.e. you should first design the app and the database for whatever scale and attributes you might want to and then code for microcontroller, which will give you a clear idea on what you should control via microcontroller.

What Next?

Now that you have a clear idea of how to control a single LED, you can extend the same idea to control multiple devices with just minor tweaking in the code. You can build up any IOT system using this roadmap and create your own ecosystem of IOT devices and showcase it to the world.

Happy Coding :)

--

--