关于ESP8266-NodeMCU和onenet通信传输学习总结(三)

关于ESP8266-NodeMCU和onenet通信传输学习总结(三)

一、前篇概述

​ 很久没更新了,原因在于物流快递太慢和重温Android开发知识去了,想着脱离onenet平台 写自己的app使用,这里要先感谢下各位大佬的开发经验和教学分享。前面两节,我用esp8266nodemcu实现了onenet平台的连接和数据点上传下发指令,然后还接入了byj-48电机的操作,实现了一些基础通信控制。

整体构建:

在这里插入图片描述

​ 时隔多日,到今天终于实现了Android app的开发使用和天猫精灵的语音接入控制,其中有很多槽点和想法,文末再提,下面开始正文:

二、基于之前的设计开发Android app

app我采用android studio 进行开发,这里要感谢一下b站博主阿正的教学分享!这里用多线程分别处理界面显示和数据处理,大致过程如下:

Android数据处理:

在这里插入图片描述
在这里插入图片描述

1、xml布局文件
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:orientation="vertical"
        android:layout_height="match_parent">
        <LinearLayout
            android:layout_marginTop="5dp"
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:layout_height="250dp">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_weight="1"
                android:layout_height="match_parent">
                <ImageView
                    android:layout_width="80dp"
                    android:id="@+id/image_temperture"
                    android:layout_gravity="left"
                    android:src="@drawable/temperture"
                    android:layout_height="wrap_content">
                </ImageView>
                <TextView
                    android:id="@+id/text_temperture"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:textSize="60sp"
                    android:text="暂无数据">
                </TextView>
            </LinearLayout>
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_weight="1"
                android:layout_height="match_parent">
                <ImageView
                    android:layout_width="80dp"
                    android:id="@+id/image_5"
                    android:layout_gravity="left"
                    android:src="@drawable/bright"
                    android:layout_height="wrap_content">
                </ImageView>
                <TextView
                    android:id="@+id/text_bright"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:textSize="60sp"
                    android:text="暂无数据">
                </TextView>
            </LinearLayout>
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_weight="1"
                android:layout_height="match_parent">
                <ImageView
                    android:layout_width="80dp"
                    android:id="@+id/image_7"
                    android:layout_gravity="left"
                    android:src="@drawable/door_lock"
                    android:layout_height="wrap_content">
                </ImageView>
                <TextView
                    android:id="@+id/text_doorLock"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:textSize="60sp"
                    android:text="暂无数据">
                </TextView>
            </LinearLayout>
        </LinearLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:layout_marginTop="5dp"
            android:layout_height="wrap_content">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_weight="1"
                    android:orientation="vertical"
                    android:layout_height="wrap_content">
                    <ImageView
                        android:layout_width="80dp"
                        android:id="@+id/light_control"
                    android:layout_gravity="center_horizontal"
                        android:src="@drawable/open"
                        android:layout_height="80dp">
                    </ImageView>
                    <TextView
                        android:layout_width="wrap_content"
                        android:text="灯"
                        android:textSize="20sp"
                    android:layout_gravity="center_horizontal"
                        android:layout_height="wrap_content">
                    </TextView>
                </LinearLayout>
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_weight="1"
                    android:orientation="vertical"
                    android:layout_height="wrap_content">
                    <ImageView
                        android:layout_width="80dp"
                        android:src="@drawable/lock"
                    android:layout_gravity="center_horizontal"
                        android:id="@+id/door_control"
                        android:layout_height="80dp">
                    </ImageView>
                    <TextView
                        android:layout_width="wrap_content"
                        android:text="门禁"
                        android:textSize="20sp"
                    android:layout_gravity="center_horizontal"
                        android:layout_height="wrap_content">
                    </TextView>
                </LinearLayout>
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_weight="1"
                    android:orientation="vertical"
                    android:layout_height="wrap_content">
                    <ImageView
                        android:layout_width="80dp"
                    android:layout_gravity="center_horizontal"
                        android:src="@drawable/air_control"
                        android:id="@+id/air_control"
                        android:layout_height="80dp">
                    </ImageView>
                    <TextView
                        android:layout_width="wrap_content"
                        android:text="空调"
                        android:textSize="20sp"
                    android:layout_gravity="center_horizontal"
                        android:layout_height="wrap_content">
                    </TextView>
                </LinearLayout>
            </LinearLayout>
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_marginTop="20dp"
                android:layout_height="wrap_content">
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_weight="1"
                    android:orientation="vertical"
                    android:layout_height="wrap_content">
                    <ImageView
                        android:layout_width="80dp"
                    android:layout_gravity="center_horizontal"
                        android:src="@drawable/curtain"
                        android:id="@+id/curtain_control"
                        android:layout_height="80dp">
                    </ImageView>
                    <TextView
                        android:layout_width="wrap_content"
                        android:text="窗帘"
                        android:textSize="20sp"
                    android:layout_gravity="center_horizontal"
                        android:layout_height="wrap_content">
                    </TextView>
                </LinearLayout>
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_weight="1"
                    android:orientation="vertical"
                    android:layout_height="wrap_content">
                    <ImageView
                        android:layout_width="80dp"
                    android:layout_gravity="center_horizontal"
                        android:src="@drawable/tv"
                        android:id="@+id/tv_control"
                        android:layout_height="80dp">
                    </ImageView>
                    <TextView
                        android:layout_width="wrap_content"
                        android:text="电视"
                        android:textSize="20sp"
                    android:layout_gravity="center_horizontal"
                        android:layout_height="wrap_content">
                    </TextView>
                </LinearLayout>
                <LinearLayout
                    android:layout_width="wrap_content"
                    android:layout_weight="1"
                    android:orientation="vertical"
                    android:layout_height="wrap_content">
                    <ImageView
                        android:layout_width="80dp"
                    android:layout_gravity="center_horizontal"
                        android:src="@drawable/water_heater"
                        android:id="@+id/water_control"
                        android:layout_height="80dp">
                    </ImageView>
                    <TextView
                        android:layout_width="wrap_content"
                        android:text="热水器"
                        android:textSize="20sp"                     android:layout_gravity="center_horizontal"
                        android:layout_height="wrap_content">
                    </TextView>
                </LinearLayout>
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>
</android.support.constraint.ConstraintLayout>

显示效果:
在这里插入图片描述

2、AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.admin.mqtt">
    <!--允许程序打开网络套接字-->
    <uses-permission android:name="android.permission.INTERNET" />
    <!--允许程序获取网络状态-->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/home"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
3、MainActivity.java
package com.example.admin.mqtt;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.json.JSONArray;
import org.json.JSONObject;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {
    
    
    protected String host = "tcp://183.230.40.39:6002";
    protected String userName = "396066";
    protected String passWord = "tx6WM==zmW21Z2pt4susBRlHMuY=";
    protected String mqtt_id = "671460025"; //
    protected String mqtt_sub_topic = "getMessage"; //
    protected String mqtt_pub_topic = "sendMessage"; //
    protected int led_flag =1;
    protected int door_flag =1;
    protected ScheduledExecutorService scheduler;

    private ImageView light_control;
    private ImageView door_control;
    private ImageView air_control;
    private ImageView curtain_control;
    private ImageView tv_control;
    private ImageView water_control;
    private TextView text_temperature;
    private TextView text_light;
    private TextView text_door_lock;
    protected MqttClient client;
    protected MqttConnectOptions options;
    protected Handler handler;

    @SuppressLint("HandlerLeak")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        curtain_control =findViewById(R.id.curtain_control);
        curtain_control.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                if(door_flag == 0)
                {
    
    
                    publishmessageplus(mqtt_pub_topic,"{\"doorLock\":\"open\",\"led\":\"\"}");
                    Toast.makeText(MainActivity.this,"开门" ,Toast.LENGTH_SHORT).show();
                    door_flag =1;
                }else{
    
    
                    publishmessageplus(mqtt_pub_topic,"{\"doorLock\":\"close\",\"led\":\"\"}");
                    Toast.makeText(MainActivity.this,"关门" ,Toast.LENGTH_SHORT).show();
                    door_flag =0;
                }
            }
        });
        light_control=findViewById(R.id.light_control);
        light_control.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View v) {
    
    
                if(led_flag == 0)
                {
    
    
                    publishmessageplus(mqtt_pub_topic,"{\"led\":\"open\",\"doorLock\":\"\"}");
                    Toast.makeText(MainActivity.this,"开灯" ,Toast.LENGTH_SHORT).show();
                    led_flag =1;
                }else{
    
    
                    publishmessageplus(mqtt_pub_topic,"{\"led\":\"close\",\"doorLock\":\"\"}");
                    Toast.makeText(MainActivity.this,"关灯" ,Toast.LENGTH_SHORT).show();
                    led_flag =0;
                }
            }
        });
        //  两个控件联动    按钮单机 更改 textview 的内容
        text_temperature =findViewById(R.id.text_temperture);
        text_door_lock=findViewById(R.id.text_doorLock);
        text_light=findViewById(R.id.text_bright);

//**********************************************************//
        Mqtt_init();
        startReconnect();
        handler = new Handler() {
    
    
            @SuppressLint("SetTextI18n")
            public void handleMessage(Message msg) {
    
    
                super.handleMessage(msg);
                switch (msg.what){
    
    
                    case 1: //开机校验更新回传
                        break;
                    case 2:  // 反馈回传

                        break;
                    case 3:  //MQTT 主页消息处理   收到消息回传   UTF8Buffer msg=new UTF8Buffer(object.toString());
                        //处理message 传过来的 obj字段(里面包了数据)
/*
                        String T_val = msg.obj.toString().substring(msg.obj.toString().indexOf("temperature\":")+13,msg.obj.toString().indexOf("}"));
                        String text_val = T_val+"℃";
                        //在主进程 handler 里面更新UI  既保证了稳定性  又不影响网络传输
                        text_temperature.setText(text_val);
                        //Toast.makeText(MainActivity.this,T_val ,Toast.LENGTH_SHORT).show();
*/
                        try{
    
    
                            Log.v("1",msg.obj.toString());
                            JSONObject jsonObject=new JSONObject(msg.obj.toString());
                            GetMessage getMessage=new GetMessage();
                            getMessage.setTemperture(jsonObject.getString("temperature"));
                            getMessage.setLight(jsonObject.getString("bright"));
                            getMessage.setDoor_lock(jsonObject.getString("doorLock"));
                            Log.v("3",getMessage.getDoor_lock());
                            if(getMessage.getTemperture()!=null){
    
    
                                String text_val = getMessage.getTemperture()+"℃";
                                text_temperature.setText(text_val);
                            }
                            if(getMessage.getDoor_lock()!=null){
    
    
                                String text_val = getMessage.getDoor_lock();
                                text_door_lock.setText(text_val);
                            }
                            if(getMessage.getLight()!=null){
    
    
                                String text_val = getMessage.getLight();
                                text_light.setText(text_val);
                            }
                            getMessage.setTemperture(null);
                            getMessage.setLight(null);
                            getMessage.setDoor_lock(null);
                        }catch (Exception e){
    
    e.printStackTrace();}
                        break;
                    case 30:  //连接失败
                        Toast.makeText(MainActivity.this,"连接失败" ,Toast.LENGTH_SHORT).show();
                        break;
                    case 31:   //连接成功
                        Toast.makeText(MainActivity.this,"连接成功" ,Toast.LENGTH_SHORT).show();
                        try {
    
    
                            client.subscribe(mqtt_sub_topic,1);
                        } catch (MqttException e) {
    
    
                            e.printStackTrace();
                        }
                        break;
                    default:
                        break;
                }
            }
        };
    }
    private void parseEasyJson(String json){
    
    

        try{
    
    
            JSONArray jsonArray = new JSONArray(json);
            for(int i = 0;i < jsonArray.length();i++){
    
    
                JSONObject jsonObject = (JSONObject) jsonArray.get(i);
                GetMessage getMessage=new GetMessage();
                getMessage.setTemperture(jsonObject.getString("temperature"));
                getMessage.setLight(jsonObject.getString("bright"));
                getMessage.setDoor_lock(jsonObject.getString("doorLock"));

            }
        }catch (Exception e){
    
    e.printStackTrace();}
    }
    protected void Mqtt_init()
    {
    
    
        try {
    
    
            //host为主机名,test为clientid即连接MQTT的客户端ID,一般以客户端唯一标识符表示,MemoryPersistence设置clientid的保存形式,默认为以内存保存
            client = new MqttClient(host, mqtt_id,
                    new MemoryPersistence());
            //MQTT的连接设置
            options = new MqttConnectOptions();
            //设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
            options.setCleanSession(false);
            //设置连接的用户名
            options.setUserName(userName);
            //设置连接的密码
            options.setPassword(passWord.toCharArray());
            // 设置超时时间 单位为秒
            options.setConnectionTimeout(10);
            // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送个消息判断客户端是否在线,但这个方法并没有重连的机制
            options.setKeepAliveInterval(20);
            //设置回调
            client.setCallback(new MqttCallback() {
    
    
                @Override
                public void connectionLost(Throwable cause) {
    
    
                    //连接丢失后,一般在这里面进行重连
                    System.out.println("connectionLost----------");
                    startReconnect();
                }


                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
    
    
                    //publish后会执行到这里
                    System.out.println("deliveryComplete---------"
                            + token.isComplete());
                }
                @Override
                public void messageArrived(String topicName, MqttMessage message)
                        throws Exception {
    
    
                    //subscribe后得到的消息会执行到这里面
                    System.out.println("messageArrived----------");
                    Message msg = new Message();
                    //封装message包
                    msg.what = 3;   //收到消息标志位
                    msg.obj =message.toString();
                    //发送messge到handler
                    handler.sendMessage(msg);    // hander 回传
                }
            });
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }
    protected void Mqtt_connect() {
    
    
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                try {
    
    
                    if(!(client.isConnected()) )  //如果还未连接
                    {
    
    
                        client.connect(options);
                        Message msg = new Message();
                        msg.what = 31;
                        // 没有用到obj字段
                        handler.sendMessage(msg);
                    }
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                    Message msg = new Message();
                    msg.what = 30;
                    // 没有用到obj字段
                    handler.sendMessage(msg);
                }
            }
        }).start();
    }
    protected void startReconnect() {
    
    
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                if (!client.isConnected()) {
    
    
                    Mqtt_connect();
                }
            }
        }, 0 * 1000, 10 * 1000, TimeUnit.MILLISECONDS);
    }
    protected void publishmessageplus(String topic,String message2)
    {
    
    
        if (client == null || !client.isConnected()) {
    
    
            return;
        }
        MqttMessage message = new MqttMessage();
        message.setPayload(message2.getBytes());
        try {
    
    
            client.publish(topic,message);
        } catch (MqttException e) {
    
    
            e.printStackTrace();
        }
    }
}

三、esp8266客户端

这里由于准备不用onenet的功能了,因此只是把他当成一个服务器中转使用,代码建立在前两篇成果之上。

#define BLINKER_WIFI
#define BLINKER_ALIGENIE_OUTLET
#define BLINKER_PRINT Serial
#include <Blinker.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "AccelStepper.h"
#include <Ticker.h>

#define PRODUCT_ID    "396066" //产品名
#define API_KEY    "tx6WM==zmW21Z2pt4susBRlHMuY="//产品密钥
#define DEVICE_ID "666259032"//设备名
#define TOPIC     "sendMessage"//订阅主题
char auth[] = "0c39eb647f6d";
char ssid[] = "CMCC-Q4QF";
char pswd[] = "jcv53rvq";
WiFiClient wifiClient;
Ticker ticker;
Ticker ticker2;
int count = 0; //ticker1控制 数据上传下发的间隔时间(s)
int count2 = 0; //ticker2控制 电机转动的时间(s)
AccelStepper stepper1(4, D0, D2, D1, D3);//电机引脚
String door = "close"; //默认检测门关闭
PubSubClient mqttClient(wifiClient);

const char* mqttServer = "183.230.40.39";//onenet地址
const uint16_t mqttPort = 6002;//mqtt接口端口
String doorLock = "close"; //默认门锁指令关闭
char msgJson[75];//存json下发信息数据
char msg_buf[200];//存json上传数据及标识位
// 新建组件对象
BlinkerButton Button1("btn-door");

bool oState = false;

void aligeniePowerState(const String & state)
{
  BLINKER_LOG("need set power state: ", state);

  if (state == BLINKER_CMD_ON) {
    digitalWrite(LED_BUILTIN, LOW);

    BlinkerAliGenie.powerState("on");
    BlinkerAliGenie.print();

    oState = true;
  }
  else if (state == BLINKER_CMD_OFF) {
    digitalWrite(LED_BUILTIN, HIGH);

    BlinkerAliGenie.powerState("off");
    BlinkerAliGenie.print();

    oState = false;
  }
}

void aligenieQuery(int32_t queryCode)
{
  BLINKER_LOG("AliGenie Query codes: ", queryCode);

  switch (queryCode)
  {
    case BLINKER_CMD_QUERY_ALL_NUMBER :
      BLINKER_LOG("AliGenie Query All");
      BlinkerAliGenie.powerState(oState ? "on" : "off");
      BlinkerAliGenie.print();
      break;
    case BLINKER_CMD_QUERY_POWERSTATE_NUMBER :
      BLINKER_LOG("AliGenie Query Power State");
      BlinkerAliGenie.powerState(oState ? "on" : "off");
      BlinkerAliGenie.print();
      break;
    default :
      BlinkerAliGenie.powerState(oState ? "on" : "off");
      BlinkerAliGenie.print();
      break;
  }
}

// 按下按键即会执行该函数
void button1_callback(const String & state) {
  BLINKER_LOG("get button state: ", state);
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}

// 如果未绑定的组件被触发,则会执行其中内容
void dataRead(const String & data)
{
  BLINKER_LOG("Blinker readString: ", data);
}

void setup() {
  // 初始化串口
  Serial.begin(9600);
  stepper1.setMaxSpeed(500);   // 设置电机最大速度为500
  stepper1.setSpeed(0);      // 初始化电机速度为300
#if defined(BLINKER_PRINT)
  BLINKER_DEBUG.stream(BLINKER_PRINT);
#endif
  pinMode(A0, INPUT);
  pinMode(D6, INPUT);
  pinMode(D8, INPUT);
  // 初始化有LED的IO
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  WiFi.mode(WIFI_STA);
  mqttClient.setServer(mqttServer, mqttPort);
  // 设置MQTT订阅回调函数
  mqttClient.setCallback(receiveCallback);
  connectMQTTServer();
  ticker.attach(1, addCount);
  // 初始化blinker
  Blinker.begin(auth, ssid, pswd);
  Blinker.attachData(dataRead);
  Button1.attach(button1_callback);
  BlinkerAliGenie.attachPowerState(aligeniePowerState);
  BlinkerAliGenie.attachQuery(aligenieQuery);
}

void loop() {
  Blinker.run();
  if (mqttClient.connected()) { // 如果开发板成功连接服务器
    // 每隔2秒钟发布一次信息
    // 保持心跳 若电机正在运转,暂时不发信息(由于mcu没有多线程,不能同时运转电机和上传下发数据)
    if (count >= 2)
    {
      if (count2 == 0)
      {
        pubMsgAndroid();
        //pubMQTTmsg();
        mqttClient.loop();
        count = 0;
      }
    }

  } else {                  // 如果开发板未能成功连接服务器
    connectMQTTServer();    // 则尝试连接服务器
  }

  //电机控制
  if (doorLock == "close" && door == "open")
  {
    stepper1.setSpeed(-500);

    ticker2.attach(1, controlDoor);
    Serial.println("door closed");
    door = "close";
  }
  else if (doorLock == "open" && door == "close")
  { stepper1.setSpeed(500);
    ticker2.attach(1, controlDoor);
    door = "open";
    Serial.println("door opened");
  }
  stepper1.runSpeed();

}
//ticker2控制 电机运转时间
void controlDoor() {
  count2++;
  Serial.print("ticker调用");
  if (count2 >= 6) {
    stepper1.setSpeed(0);
    count2 = 0;
    ticker2.detach();  // 使用detach来停止ticker对象定时调用函数
    Serial.print("ticker.detach()");
  }
}
//连接mqtt服务器
void connectMQTTServer() {
  String clientId = DEVICE_ID;
  String productId = PRODUCT_ID;
  String apiKey = API_KEY;
  // 连接MQTT服务器
  if (mqttClient.connect(clientId.c_str(), productId.c_str(), apiKey.c_str())) {
    Serial.println("MQTT Server Connected.");
    Serial.println("Server Address: ");
    Serial.println(mqttServer);
    Serial.println("ClientId:");
    Serial.println(clientId);
    subscribeTopic(); // 订阅指定主题
  } else {
    Serial.print("MQTT Server Connect Failed. Client State:");
    Serial.println(mqttClient.state());
    delay(3000);
  }
}
// 订阅指定主题
void subscribeTopic() {

  // 这么做是为确保不同设备使用同一个MQTT服务器测试消息订阅时,所订阅的主题名称不同
  String topicString = TOPIC;
  char subTopic[topicString.length() + 1];
  strcpy(subTopic, topicString.c_str());

  // 通过串口监视器输出是否成功订阅主题以及订阅的主题名称
  if (mqttClient.subscribe(subTopic)) {
    Serial.println("Subscrib Topic:");
    Serial.println(subTopic);
  } else {
    Serial.print("Subscribe Fail...");
  }
}
//获取下发指令topic 指定主题 payload 下发信息,以字节存储 length 下发信息长度
void receiveCallback(char* topic, byte* payload, unsigned int length) {

  Serial.print("Message Received [");
  Serial.print(topic);
  Serial.print("] ");
  String receivePassage;
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
    receivePassage += (char)payload[i];
  }
  Serial.println("----" + receivePassage + "----");
  Serial.print("Message Length(Bytes) ");
  Serial.println(length);
  ///

  StaticJsonDocument<96> doc;
  deserializeJson(doc, receivePassage);

  const char* doorLock = doc["doorLock"]; // "close"
  const char* led = doc["led"]; // "close"
  receivePassage = "";
  if (doc["doorLock"].as<String>() == "open")
  {
    doorLock = "open";

  } else if (doc["doorLock"].as<String>() == "close") {
    doorLock = "close";
    Serial.println("door closed");
  }
  if (doc["led"].as<String>() == "open")
  {
    digitalWrite(BUILTIN_LED, LOW);  // 则点亮LED。
    Serial.println("LED ON");
  } else if (doc["led"].as<String>() == "close") {
    digitalWrite(BUILTIN_LED, HIGH); // 否则熄灭LED。
    Serial.println("LED OFF");
  }
  /*

    const char* json = (char *)payload;

    DynamicJsonDocument doc(64);
    deserializeJson(doc, json);

    const char* led = doc["led"]; // 灯控
    const char* door = doc["door"]; // 门控

    ///


    if(doc["door"].as<String>()=="open")
    {
    doorLock='1';
    Serial.println("door open");
    }
    else if(doc["door"].as<String>()=="close")
    {
    doorLock='2';
    Serial.println("door off");
    }
    if(doc["led"].as<String>()=="open")
    {
    digitalWrite(BUILTIN_LED, LOW);  // 则点亮LED。
    Serial.println("LED ON");
    }
    else if(doc["led"].as<String>()=="close")
    {
    digitalWrite(BUILTIN_LED, HIGH); // 否则熄灭LED。
    Serial.println("LED OFF");
    }*/
  /* //onenet测试下发数据
    if ((char)payload[0] == 'L') {     // 如果收到的信息以“1”为开始
     if((char)payload[1] == '0')
     {
     digitalWrite(BUILTIN_LED, LOW);  // 则点亮LED。
     Serial.println("LED ON");
     }
     else if((char)payload[1] == '1')
     {
     digitalWrite(BUILTIN_LED, HIGH); // 否则熄灭LED。
     Serial.println("LED OFF");
     }
    }else if((char)payload[0] == 'D') {     // 如果收到的信息以“1”为开始
     if((char)payload[1] == '1')
     doorLock="open";
     else if((char)payload[1] == '2')
     doorLock="close";
     }

    //
  */

}
/*
  void doorControl(char doorLock)
  {
  //开门
  if(doorLock=='1')
  {
    digitalWrite(D5, HIGH);

  }
  //关门
  else if(doorLock=='2')
  {
    digitalWrite(D5, LOW);


  }

  doorLock='0';
  }
*/
//对指定主题上传信息
void pubMsgAndroid() {
  String topicString = "getMessage";
  char publishTopic[topicString.length() + 1];
  strcpy(publishTopic, topicString.c_str());
  //json数据转换为数组
  DynamicJsonDocument doc(64);
  doc["temperature"] = analogRead(A0);
  doc["doorLock"] = digitalRead(D8);
  doc["bright"] = digitalRead(D5);
  serializeJson(doc, Serial);
  String jsonCode;
  serializeJson(doc, jsonCode);
  Serial.print("json Code: "); Serial.println(jsonCode);
  String messageString = jsonCode;
  char publishMsg[messageString.length() + 1];
  strcpy(publishMsg, messageString.c_str());
  int json_len = strlen(publishMsg);

  mqttClient.publish(publishTopic, publishMsg, json_len);
}
/*void pubMQTTmsg(){
  //onenet数据点上传系统主题
  String topicString = "$dp";
  char publishTopic[topicString.length() + 1];
  strcpy(publishTopic, topicString.c_str());
  //json数据转换为数组
  DynamicJsonDocument doc(64);
  bool pinState = !digitalRead(BUILTIN_LED);
  bool doorState = !digitalRead(D6);
  doc["led"] = pinState;
  doc["door"] = doorState;

  serializeJson(doc, Serial);
  // 建立发布信息。温度
  String jsonCode;
  serializeJson(doc, jsonCode);
  Serial.print("json Code: ");Serial.println(jsonCode);
  String messageString = jsonCode;
  char publishMsg[messageString.length() + 1];
  strcpy(publishMsg, messageString.c_str());
  int json_len=strlen(publishMsg);
  memset(msg_buf,0,200);
  msg_buf[0]=char(0x03);
  msg_buf[1]=char(json_len>>8);
  msg_buf[2]=char(json_len &0xff);
  memcpy(msg_buf+3,publishMsg,json_len);
  // 实现ESP8266向主题发布信息
  if(mqttClient.publish(publishTopic, (uint8_t*)msg_buf,3+json_len)){
    Serial.println("Publish Topic:");Serial.println(publishTopic);
    String msg_bufTotal;
    for(int i=0;i<sizeof(msg_buf)/sizeof(msg_buf[0]);i++)
    {
      msg_bufTotal+=msg_buf[i];
    }
    Serial.println("Publish message:");Serial.println(msg_bufTotal);
  } else {
    Serial.println("Message Publish Failed.");
  }
  }*/
void addCount() {
  count++;
}

这里android手机端 发布主题 sendMessage专门用来发送手机端指令,订阅主题getMessage用来接收esp8266客户端数据并通过handler异步处理,将数据显示在界面上。esp8266客户端订阅与发布相反。

在此基础上,使用了blinker接入天猫精灵的示例,并加以改进,融入到了该程序中,实现了天猫精灵的语音控制。

扫描二维码关注公众号,回复: 12450287 查看本文章

四、成果展示

接收到的温度信息,点击按键可控制客户端,还有更多功能等待开发

天猫精灵与esp8266开发板通信

猜你喜欢

转载自blog.csdn.net/TOPthemaster/article/details/112909270