Using Flutter and Arduino to control Appliances
Flutter is a UI framework that makes it easy to get started creating mobile apps for iOS and Android and Arduino is a firmware development platform that makes it easy to get started creating embedded applications for a variety of micro-controllers and combined they make it easy to create app enabled hardware.
As an exercise we’ll a use a hand full of cheap “jelly bean” components, Arduino and Flutter to create the hardware and mobile app needed to control infrared remote controlled appliances such as television sets, air conditioners, space heaters and stereos.
The hardware needed to complete this includes a NodeMCU esp8266 development module, an infrared LED, a 38 kHz infrared receiver and a 2n3904 PNP transistor. You should be able to source the parts online for $5 to $10 maybe even cheaper if you are willing to wait on shipping from China.
Configuring the Arduino IDE
The Arduino IDE needs to be configured to program the NodeMCU board you can find a tutorial here: Getting Started with NodeMCU (ESP8266) on Arduino IDE.
Serving TCP on esp8266
As a first step lets get a TCP server running and test that it works
Create a WiFi Server object named wifiServer.
Define constant character pointer to contain the SSID and password for your WiFi password.
Now lets fill out the setup() function.
Configure the serial connection for speed of 115,200 bps.
Wait a second to ensure the serial connection is initialized.
Initialize the WiFi connection. *ESP8266 wifi library docs
And then move on to the loop() function.
Gets a client that is connected to the server and has data available for reading.
Start a loop for as long as the client is connected.
As long as there are bytes available read a byte and write it to the serial port.
Now compile and upload the code to the NodeMCU.
After uploading the Sketch open the serial monitor (Ctrl+Shift+M on Windows). If you don’t see this in your serial monitor try unplugging the USB cable and plugging it back in then quickly open the serial monitor.
Now that we have a basic TCP server lets test it out using Putty. Configure a connection using the IP address in the serial monitor, port 80 and a Raw connection type.
Anything you type in the terminal should be echoed in the serial monitor.
We now have enough functionality established on the hardware side of this project to move on to the Flutter portion of the project.
Creating a simple interface in Flutter
If you haven’t installed a development environment for Flutter yet you can find the instructions here. This tutorial will use Android studio it is the easiest way to get started, will install the necessary prerequisites for you and is supported by Google.
To start lets close PuTTY since the server running on the NodeMCU can only handle a single connection at a time. Then open Android Studio and create a new Flutter project using the default choices.
In the _MyHomePageState class delete the Text widgets from Body:
And delete the floating action button but before you do take notice of the the onPressed event and the _incrementCounter method assigned to it.
Now in the body of the _MyHomePageState class add a raised button. Notice that the button has a child Text widget nested in it. Many of the UI widgets in Flutter are made of multiple primitive widgets.
At this point we can run the app.
The raised button is grayed out showing that it is inactive because we haven’t assigned a method to it’s onPressed event but don’t worry we will get to that soon.
Now we are ready to move on to sending a command via TCP to the NodeMCU when a button is pushed.
Add imports for foundation.dart from flutter and dart.io.
And rewrite the main function as shown below.
In the code above the IP address passed to the Sockets connect method should be the address that was copied from the serial monitor earlier when we were testing the TCP server.
Add a Socket object and constructor to the MyApp class as shown below.
A little further down in the return statement of the Build widget add a channel parameter with a value of socket to MyHomePage.
In the MyHomePage class add a channel field of the type Socket.
In the _MyHomePageState class add a _togglePower() method. Also you can delete the _counter variable property and the _incrementCounter() method while you are here.
Override the _MyHomePageState class’s dispose method and close the channel when the state object is closed.
Now lets go back and assign the _togglePower method to the onPressed event so that the string “POWER\n” is sent to the NodeMCU when the power button is pressed.
Go ahead and run the app and if there are no errors we are ready to test the app with the NodeMCU.
Testing Android to NodeMCU TCP Connection
First reconnect a NodeMCU with the Arduino program that we created earlier uploaded to it. Open the serial monitor and then open the flutter app we’ve been working on and touch the Power button you should see the string “POWER\n” echoed in the serial monitor.
Training our remote
We have proven that we can communicate between a mobile app and a NodeMCU board now we can move on to communication between the NodeMCU and appliances using infrared remote protocols.
Fortunately the hard work has been done for us by the IRremoteESP8266 library available here. Once the library has been installed go to File > Examples>IRremoteESP8266>IRrecvDumpV2 and open this sketch.
Before we do anything else we need to connect an infrared receiver to the NodeMCU. You will need to determine the pin out for your IR receiver I personally had to release some magic smoke from one before I got the pin out rite fortunately I purchased 6 of them. The pin out for mine is pictured below and is typical for these components.
Connect Serial to NodeMCU D5 (esp8266 pin 14), Positive to 3.3v and Ground to GND.
The IRrecvDumpV2 sketch will allow us to capture the IR commands sent by the remote or remotes that control our targeted appliances. Go ahead and load the IRrecvDumpV2 sketch on to the NodeMCU and open the serial monitor. Now point your remote at the IR receiver and press the power button a couple of times. The output below was produced by a Haier AC remote.
Select several lines of text being sure to capture the rawData and then copy it to the clipboard Ctrl + C on windows. Then open the text editor of your choice and paste it in. In the example below I have reformatted the data so that it doesn’t run off the edge of the screen.
Now reopen the Arduino sketch that we created earlier to test TCP communications. Add a constant to define the pin we will use to transmit IR remote commands.
const uint16_t kIrLed = 4;
And then use that constant when creating an instance of a IRsend object.
IRsend irsend(kIrLed);
Then paste the raw data we captured earlier pay special attention to the length of the command which is 71 in the example below. Give the array holding the command a meaningful name and make sure the array type is uint16_t (16 bit unsigned integer).
uint16_t HaierAC_power[71] = {8928, 4556, …
In the setup() function we only have one change we add
irsend.begin();
to the first line of the first line of the setup() function before the Serial.begin(115200); statement.
Previously in our loop function we captured each character and then wrote it to the serial port.
We need to change the loop function so that it collects the received character till it reaches a break character (in our case newline \n) and then checks to see if the resulting word is a command we need to act on.
Upload the latest code to the NodeMCU then open the flutter app and you should have a functioning IR remote app.
The full source code for this project is available on github https://github.com/toomuchcoffeecoder/flutter_esp8266_ir_remote
If you have any questions or need assistance please log an issue in the github repository.