Design and implementation of smart home system for Internet of things

1. Project overview

Implement a mobile App that can control home devices and obtain relevant temperature and humidity information.

App calls HTTP service on ECs; HTTP service encapsulates MQTT subscription and push requests to update the MQTT server;

The esp8266 module is connected to the MQTT server through networking, sends the data transmitted from the server to the 51 single chip microcomputer for control, and sends the temperature and humidity information collected by DHT11 to the MQTT server.

2. Reference blog

arduino downloads and tutorials

esp8266 and 51 communication

MQTT protocol details

The server runs the MQTT server

3. Development environment

1. IDEA (developing Java Web Applications)
2. Android studio (developing mobile App)
3. arduino (developing esp8266 program)
4. keil5 (development of single chip microcomputer program)
5. Serial port debugging tool

4. Prepare equipment

  • 1. 51 single chip microcomputer (used to manage household equipment)

  • 2. DHT11 (used to obtain temperature and humidity information)

  • 3. esp8266-12e (connect to mqtt server on external network)

  • 4. ECS (deploy mqtt server and http service)

5. System design

Overall design flow chart

5.1 hardware

The esp8266 module connects the mobile phone hotspot to the Internet, then connects to the MQTT server, pushes the relevant temperature and humidity information, and subscribes to the control topic.

After receiving the subscription information, esp8266 sends it directly to the serial port.

51 single chip microcomputer obtains information through serial port interrupt, and then carries out relevant processing.

5.2 software

On the server side, first deploy an MQTT server, and then encapsulate an Http service for its related operations.

Finally, the mobile App only needs to send an http request to operate the relevant hardware.

6. System implementation

6.1 deployment of MQTT server on ECS

This scheme uses Docker to deploy EMQ.

Pull the official website image locally, and then run the image.

docker pull emqx/emqx:4.3.4
docker run -d --name emqx -p 1883:1883 -p 8081:8081 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:4.3.4

After successful startup, docker ps will have relevant container information as follows.

Visit port 18083 of the server and you can see the following page to indicate that the deployment is successful (account: admin, password: public)

6.2. Connect the MQTT server with ESP8266

6.2.1 download the related component library of esp12e in arduino.

Download relevant libraries in toolbar > Tools > development board > development board manager > search esp8266 (there are detailed tutorials in the blog link of this article).

6.2.2 import other libraries

Import relevant third-party libraries (if any in the project).

Then toolbar > Project > Load Library > Add ZIP libraries add the following libraries.

6.2.3 code

Esp8266 must be connected to the Internet before MQTT communication. Therefore, esp8266 must first connect to WiFi, and then push and subscribe to MQTT related information.

Use DHT11 module to directly read the temperature and humidity information of DHT11 module, and then use pubsubclient module for MQTT communication.

The source code of arduino project is as follows

#include <ESP8266WiFi.h>
#include <SoftwareSerial.h>
#include <PubSubClient.h>
#include <dht11. h> / / import DHT11 Library

SoftwareSerial mySerial(13, 12); // RX, TX

/********************###Definition###********************/
dht11 DHT11;//Define sensor type
#define DHT11PIN 2 / / define the sensor connection pin. PIN2 here corresponds to D4 on the NodeMcu8266 development board
 
/********************###Subfunction###********************/
double Fahrenheit(double celsius)
{
  return 1.8 * celsius + 32; //The temperature from Celsius to Fahrenheit
}
 
double Kelvin(double celsius)
{
  return celsius + 273.15; //Conversion of Celsius temperature to Kelvin temperature
}

// Update these with values suitable for your network.

const char* ssid = "1122";//wifi account
const char* password = "11111111";//wifi secret
const char* mqtt_server = "159.75.88.181";//mqtt server

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

/**
 * Message callback
 */
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print((char)payload[0]);

}

/**
 * Disconnect and reconnect
 */
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("dht11Topic", "hello world");
      // ... and resubscribe
      client.subscribe("51Topic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  Serial.begin(9600);
  mySerial.begin(9600);
  setup_wifi();
  //Configure mqtt server address and port
  client.setServer(mqtt_server, 1883);
  //Set subscription message callback
  client.setCallback(callback);
}

void loop() {
  //Reconnection mechanism
  if (!client.connected()) {
    reconnect();
  }
  //Constantly listening for information
  client.loop();

  long now = millis();
  if (now - lastMsg > 5000) {
    DHT11.read(DHT11PIN); //Update all sensor information

    //Publish information every 5s
    lastMsg = now;
    ++value;
    snprintf (msg, 50, "temperature: %f,humidity: %f", (float)DHT11.temperature, (float)DHT11.humidity);
//    Serial.print("Publish message: ");
//    Serial.println(msg);
    client.publish("dht11Topic", msg);
  }
}

6.3 single chip microcomputer implementation

Turn on the serial port interrupt, and then connect the single chip microcomputer RXD, TXD and esp8266 to directly obtain the serial port information of 8266.

Then the corresponding operation implementation of relevant instructions is directly set in the serial port interrupt.

The following codes are for operation only. Different pins of different microcontrollers may be different.

#include<reg52.h>
typedef unsigned char u8;
typedef unsigned int u16;
sbit LED = P2^3;
sbit MOTO = P1^0;	
u8 dat;
void Init(void)		
{
	TMOD = 0x20;	
	TL1 = 0xfd;		
	TH1 = 0xfd;		
	TR1 = 1;	
	REN=1;    
	SM0=0;    
	SM1=1;   
	EA = 1;   
	ES=1;     
}

void main()
{
    Init();
    while(1);
}

void InterruptUART() interrupt 4   
{ 
      RI = 0;        
      dat = SBUF;    
	  {
         if(dat=='o')
		 {
			 LED =0;    
		 }
		 if(dat=='f')  
		 {						 
		     LED =1; 
		 }			
		 if (dat == 'a')
			 MOTO = 1;
		 if (dat == 'b')
			 MOTO = 0;
	  }
}

6.4. HTTP service implementation

Encapsulate an HTTP service, mask the service call of MQTT, and let the APP directly send HTTP requests to operate the hardware.

The core class MqttChannel encapsulates the MQTT protocol. Maintain a subscription information Map internally. When new information is pushed, you can modify the information of the Map.

package cn.wen233.iocdemo.infrustructure.util;

import cn.wen233.iocdemo.domain.enums.LedState;
import cn.wen233.iocdemo.domain.enums.MotorState;
import org.eclipse.paho.client.mqttv3.*;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * mqtt Protocol processing tool class
 *
 * @author wenei
 * @date 2021-06-23 10:08
 */
public class MqttChannel implements AutoCloseable {

    private static final Logger log = LoggerFactory.getLogger(MqttChannel.class);

    /**
     * Client id
     */
    private static final String clientId = "http-consumer";

    /**
     * Service quality
     */
    private static final int qos = 1;

    private static String ip = IocUtil.getBean(MQTTProperties.class).getIp();

    private static int port = IocUtil.getBean(MQTTProperties.class).getPort();

    private static final String serviceUrl = String.format("tcp://%s:%d", ip, port);

    private static final Map<String, String> topicMap = new HashMap<>();

    /**
     * Topics for default subscriptions
     */
    private static final List<String> defaultSubscribeTopic = Collections.singletonList("dht11Topic");

    private static final Map<String, String> defaultTopicStatus = new HashMap<>();

    static {
        final String topic = "51Topic";
        defaultTopicStatus.put(topic, LedState.OFF.getCommand());
        defaultTopicStatus.put(topic, MotorState.OFF.getCommand());
    }

    private static MqttClient mqttClient = null;

    static {
        // Memory storage
        MemoryPersistence persistence = new MemoryPersistence();
        // Create client
        try {
            mqttClient = new MqttClient(serviceUrl, clientId, persistence);
            // Create link parameters
            MqttConnectOptions connOpts = new MqttConnectOptions();
            // Remember status when restarting and reconnecting
            connOpts.setCleanSession(false);
            // Set the user name for the connection
//            connOpts.setUserName(userName);
//            connOpts.setPassword(password.toCharArray());
            // Establish connection
            mqttClient.connect(connOpts);
            // Set callback function
            mqttClient.setCallback(new MqttCallback() {

                @Override
                public void connectionLost(Throwable cause) {
                    log.info("Lost connection");
                }

                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    log.info("Time: {}, Topic:{}, Message:{}",
                            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), topic, message);
                    topicMap.put(topic, new String(message.getPayload()));
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                    log.info("Update subscription:" + token.isComplete());
                }

            });
            // Topics for default subscriptions
            defaultSubscribeTopic.forEach(x -> {
                try {
                    mqttClient.subscribe(x, qos);
                } catch (MqttException e) {
                    e.printStackTrace();
                }
                topicMap.put(x, "temperature:-99.00000, humidity:-99.00000");
            });
            // Default 51 control topic status setting
            defaultTopicStatus.forEach(MqttChannel::publish);
        } catch (MqttException mqttException) {
            mqttException.printStackTrace();
        }
    }

    /**
     * Asynchronous call push method
     */
    public static void asyncPublish(String topic, String sendData) {
        CompletableFuture.supplyAsync(() -> {
            publish(topic, sendData);
            return null;
        });
    }

    public static void publish(String topic, String sendData) {
        try {
            // Create message
            MqttMessage message = new MqttMessage(sendData.getBytes(StandardCharsets.UTF_8));
            // Set the quality of service of the message
            message.setQos(qos);
            // Release news
            mqttClient.publish(topic, message);
            log.info("towards {} of {} Subject sending:{}", serviceUrl, topic, sendData);
        } catch (MqttPersistenceException e) {
            e.printStackTrace();
        } catch (MqttSecurityException e) {
            e.printStackTrace();
        } catch (MqttException e) {
            e.printStackTrace();
        }

    }

    public static String subscribe(String topic) {
        return topicMap.get(topic);
    }

    @Override
    public void close() throws Exception {
        mqttClient.disconnect();
        mqttClient.close();
    }
}

After successful operation, MQTT information has been pushed out as follows.

Then package the SpringBoot application and deploy it to the ECS (so that subsequent apps can send Http requests).

Connect the esp8266 and 51 MCU in 6.1, 6.2 and 6.3 above, then supply power and wait for WiFi connection. After connecting to WiFi, the http service can directly control the MCU.

6.5 App implementation

The App page is as follows (the project path should not have Chinese)

Receive relevant temperature and humidity information and display it in real time, and then control relevant LED and fan status.

7. System test

After burning the MCU and esp8266 programs, deploy the MQTT server on the ECS and set the relevant WiFi and server information of esp8266.

Then enable the http service and you will have the following information


Call the relevant HTTP interface to operate the MCU

8. Systematic review

The system is essentially a system that esp8266 serves as an MQTT client to connect to an external MQTT server.

After the connection is completed, the serial port of 51 single chip microcomputer can transmit transparently with the theme of MQTT. The received information of the subject can be completely sent to the single chip microcomputer.

Therefore, if you need to develop again, you only need to modify the relevant operation instructions sent by the MCU and HTTP service.

9. Project address

Keywords: Android Single-Chip Microcomputer IoT Sensor MQTT

Added by bokehman on Sun, 23 Jan 2022 22:09:17 +0200