Are you making an IoT Android/iOS app to control NodeMCU (ESP8266)? I recommend you to use WebSocket to communicate between App and NodeMCU. If you are using HTTP web-server then it will be slow communication between Chip and Mobile App therefore use WebSocket instead. Follow the guideline and codes below. This is the basic project for beginners to learn Turn ON/OFF LED using WebSocket using Flutter and NOdeMCU (ESP8266). Communication using WebSocket is very useful for instant controlling bots.
We are using PlatromIO on Visual Studio Code as an IDE. Download the WebSocket.zip CPP library for NodeMCU. Extract the zip folder to lib/ folder.
#include <Arduino.h>
#include <ESP8266WiFi.h> //import for wifi functionality
#include <WebSocketsServer.h> //import for websocket
#define ledpin D2 //defining the OUTPUT pin for LED
const char *ssid = "HelloHPC - Wifi"; //Wifi SSID (Name)
const char *pass = "12345678"; //wifi password
WebSocketsServer webSocket = WebSocketsServer(81); //websocket init with port 81
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
//webscket event method
String cmd = "";
switch(type) {
case WStype_DISCONNECTED:
Serial.println("Websocket is disconnected");
//case when Websocket is disconnected
break;
case WStype_CONNECTED:{
//wcase when websocket is connected
Serial.println("Websocket is connected");
Serial.println(webSocket.remoteIP(num).toString());
webSocket.sendTXT(num, "connected");}
break;
case WStype_TEXT:
cmd = "";
for(int i = 0; i < length; i++) {
cmd = cmd + (char) payload[i];
} //merging payload to single string
Serial.println(cmd);
if(cmd == "poweron"){ //when command from app is "poweron"
digitalWrite(ledpin, HIGH); //make ledpin output to HIGH
}else if(cmd == "poweroff"){
digitalWrite(ledpin, LOW); //make ledpin output to LOW on 'pweroff' command.
}
webSocket.sendTXT(num, cmd+":success");
//send response to mobile, if command is "poweron" then response will be "poweron:success"
//this response can be used to track down the success of command in mobile app.
break;
case WStype_FRAGMENT_TEXT_START:
break;
case WStype_FRAGMENT_BIN_START:
break;
case WStype_BIN:
hexdump(payload, length);
break;
default:
break;
}
}
void setup() {
pinMode(ledpin, OUTPUT); //set ledpin (D2) as OUTPUT pin
Serial.begin(9600); //serial start
Serial.println("Connecting to wifi");
IPAddress apIP(192, 168, 0, 1); //Static IP for wifi gateway
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); //set Static IP gateway on NodeMCU
WiFi.softAP(ssid, pass); //turn on WIFI
webSocket.begin(); //websocket Begin
webSocket.onEvent(webSocketEvent); //set Event for websocket
Serial.println("Websocket is started");
}
void loop() {
webSocket.loop(); //keep this line on loop method
}
Now on the Flutter part, add web_socket_channel plugin as a dependency on pubspec.yaml file.
dependencies:
flutter:
sdk: flutter
web_socket_channel: ^1.1.0
Add Internet Permission by adding this line in android/app/src/main/AndroidManifest.xml before <application>
<uses-permission android:name="android.permission.INTERNET"/>
Here we are using ws
, non-secure WebSocket protocol. Therefore, add the following lines to AndroidManifest.xml file as well.
<application
android:usesCleartextTraffic="true"
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:web_socket_channel/io.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: WebSocketLed(),
);
}
}
//apply this class on home: attribute at MaterialApp()
class WebSocketLed extends StatefulWidget{
@override
State<StatefulWidget> createState() {
return _WebSocketLed();
}
}
class _WebSocketLed extends State<WebSocketLed>{
bool ledstatus; //boolean value to track LED status, if its ON or OFF
IOWebSocketChannel channel;
bool connected; //boolean value to track if WebSocket is connected
@override
void initState() {
ledstatus = false; //initially leadstatus is off so its FALSE
connected = false; //initially connection status is "NO" so its FALSE
Future.delayed(Duration.zero,() async {
channelconnect(); //connect to WebSocket wth NodeMCU
});
super.initState();
}
channelconnect(){ //function to connect
try{
channel = IOWebSocketChannel.connect("ws://192.168.0.1:81"); //channel IP : Port
channel.stream.listen((message) {
print(message);
setState(() {
if(message == "connected"){
connected = true; //message is "connected" from NodeMCU
}else if(message == "poweron:success"){
ledstatus = true;
}else if(message == "poweroff:success"){
ledstatus = false;
}
});
},
onDone: () {
//if WebSocket is disconnected
print("Web socket is closed");
setState(() {
connected = false;
});
},
onError: (error) {
print(error.toString());
},);
}catch (_){
print("error on connecting to websocket.");
}
}
Future<void> sendcmd(String cmd) async {
if(connected == true){
if(ledstatus == false && cmd != "poweron" && cmd!= "poweroff"){
print("Send the valid command");
}else{
channel.sink.add(cmd); //sending Command to NodeMCU
}
}else{
channelconnect();
print("Websocket is not connected.");
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:Text("LED - ON/OFF NodeMCU"),
backgroundColor: Colors.redAccent
),
body:Container(
alignment: Alignment.topCenter, //inner widget alignment to center
padding: EdgeInsets.all(20),
child:Column(
children:[
Container(
child: connected?Text("WEBSOCKET: CONNECTED"):Text("DISCONNECTED")
),
Container(
child: ledstatus?Text("LED IS: ON"):Text("LED IS: OFF")
),
Container(
margin: EdgeInsets.only(top:30),
child: FlatButton( //button to start scanning
color: Colors.redAccent,
colorBrightness: Brightness.dark,
onPressed: (){ //on button press
if(ledstatus){ //if ledstatus is true, then turn off the led
//if led is on, turn off
sendcmd("poweroff");
ledstatus = false;
}else{ //if ledstatus is false, then turn on the led
//if led is off, turn on
sendcmd("poweron");
ledstatus = true;
}
setState(() {
});
},
child: ledstatus?Text("TURN LED OFF"):Text("TURN LED ON")
)
)
],
)
),
);
}
}
This is the way you can control NodeMCU using the Android/iOS mobile APP. Follow the guidelines above and integrate it into your project.
Please Wait...
6 Comments on this Article
pjdf
ESP:39:40: error: cannot bind non-const lvalue reference of type ’String&’ to an rvalue of type ’String’
dfsd
ESP:39:40: error: cannot bind non-const lvalue reference of type ’String&’ to an rvalue of type ’String’
tsdf
’D2’ was not declared in this scope
mahdi
hi.
when I connect to esp’s wifi the application says websocket: connected and after some seconds it says disconnected and when I tap on turn on or off led button this cycle happens . how can I solve this problem?
Hari Prasad Chaudhary
Inside a loop() of cpp code, check the WebSocket connection on each loop, better to use async code, and if it is disconnected, reconnect the WebSocket.
2 years agomahdi
thanks ,
but I didn’t undrestand how can I do the things you said.
2 years ago