NodeMCU: Show Live Data from DHT11 Sensor Using WebSocket on Flutter Mobile App

In this example, we are going to show you how to show live data like temperature, humidity, and Heat Index from DHT11 Sensor on a mobile App using NodeMCU (ESP8266). We have used WebSocket to transfer data from NodeMCU to Mobile App. WebSocket is very fast for communication, therefore we use it to stream live data to a mobile app.

We are using PlatromIO on Visual Studio Code as an IDE. Download WebSocket.zip and DHT.zip CPP library for NodeMCU. Extract the zip folders to lib/ folder.

CPP code for NodeMCU(ESP8266): main.cpp

#include <Arduino.h>
#include <ESP8266WiFi.h> //import for wifi functionality
#include <WebSocketsServer.h> //import for websocket
#include <DHT.h> //library for DHT Sensor

#define dhttype DHT11 //defining DHT Type

const char *ssid =  "HelloHPC - Wifi";   //Wifi SSID (Name)   
const char *pass =  "12345678"; //wifi password

String json; //variable for json 

char tstr[10]; //Character array for temperature 
char hstr[10]; //Character array for Humidity
char histr[10]; //Character array for Heat Index

DHT dht(D5, dhttype); //initialize DHT sensor, D5 is the pin where we connect data pin from sensor

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 == "readdata"){ //when command from app is "poweron"
               //recieved command from mobile app
               //we can do task according to command from mobile using if-else-else if
            } 

             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;
    }
}

String chr2str(char* chr){ //function to convert characters to String
    String rval;
    for(int x = 0; x < strlen(chr); x++){
        rval = rval + chr[x];
    }
    return rval;
}

void setup() {
   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

    delay(2000); //delay by 2 second, DHT sesor senses data slowly with delay around 2 seconds
    float h = dht.readHumidity(); //Humidity float value from DHT sensor
    float t = dht.readTemperature(); //Temperature float value from DHT sensor
    float f = dht.readTemperature(true); //Temperature float value from DHT sensor

    if (isnan(h) || isnan(t) || isnan(f)) {
        //if data from DHT sensor is null
        Serial.println(F("Failed to read from DHT sensor!"));
        return;
    }else{
        float hic = dht.computeHeatIndex(t, h, false); //convert humidity and temperature to heat index
        sprintf(tstr, "%.2f", t); //convert float to characters
        sprintf(hstr, "%.2f", h); //convert float to characters
        sprintf(histr, "%.2f", hic); //convert float to characters

        json = "{'temp':'" + chr2str(tstr) + "','humidity':'" + chr2str(hstr) + "%','heat':'" + chr2str(histr) + "'}";
        //formulate JSON string format from characters (Converted to string using chr2str())
        Serial.println("DHT Data read Successful");
        webSocket.broadcastTXT(json); //send JSON to mobile
    }
}

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"

Dart Code for Flutter App:

import 'dart:convert';
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: WebSocketDHT(),
    );
  }
}

//apply this class on home: attribute at MaterialApp()
class WebSocketDHT extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    return _WebSocketDHT(); 
  }
}

class _WebSocketDHT extends State<WebSocketDHT>{
  String temp; //variable for temperature
  String humidity; //variable for humidity
  String heatindex; //variable for heatindex

  IOWebSocketChannel channel;
  bool connected; //boolean value to track if WebSocket is connected

  @override
  void initState() {
    connected = false; //initially connection status is "NO" so its FALSE

    temp = "0"; //initial value of temperature
    humidity = "0"; //initial value of humidity
    heatindex = "0"; //initial value of heatindex

    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.substring(0, 6) == "{'temp"){ 
                     //check if the resonse has {'temp on it
                      message = message.replaceAll(RegExp("'"), '"'); 
                      Map<String, dynamic> jsondata = json.decode(message); //decode json to array
                      setState(() {
                          temp = jsondata["temp"]; //temperature value
                          humidity = jsondata["humidity"]; //humidity value
                          heatindex = jsondata["heat"]; //heatindex value
                      });
                 }
                 //you can apply "if elese - else if for more message type from NodeMCU"
            });
          }, 
        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){
            channel.sink.add(cmd); //sending Command to NodeMCU
            //send command to NodeMCU
         }else{
            channelconnect();
            print("Websocket is not connected.");
         }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title:Text("DHT 11 - TEMP/HUMIDITY/HEAT INDEX"),
        backgroundColor: Colors.redAccent
      ),
      body:Container(
         alignment: Alignment.topCenter, //inner widget alignment to center
         padding: EdgeInsets.all(20),
         child:Column(
           children:[

               Container( //showing if websocket is connected or disconnected
                  child: connected?Text("WEBSOCKET: CONNECTED"):Text("DISCONNECTED")    
               ),

               Container( 
                 child: Text("Current Weather in Kathmandu",
                      style:TextStyle(fontSize: 20, color: Colors.redAccent))
               ),

               Container( //showing temperature and humidity
                  child: Text("Temperature $temp°C | Humidity: $humidity", 
                        style: TextStyle(fontSize: 18),),    
                ),

                Container( //showing heat index
                  child: Text("Heat Index: $heatindex°C"),      
                ),
           ],
         )
      ),
    );
  }
}

This is the way you can read Temperature, Humidity, and Heat Index from DHT11 sensor and live display on Android/iOS Mobile app using Flutter.

No any Comments on this Article


Please Wait...