基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(十一)使用domoticz+mosquitto+Android客户端实现控制STM32板上的LED(二)

原创 2017年04月28日 03:50:01

本文在前一篇实现了STM32平台利用MQTT协议对接domoticz平台控制LED灯的基础上,完善了网络连接和MQTT的broker连接过程,实现了断网重连功能。

实现部分主要在rt-thread\components\external\paho-mqtt\MQTTClient-C\samples\domoticz\DomoticzThread.c中。
在前一篇的源码基础上稍作改动,如下所示:

DomoticzThread.c:

#include <rtthread.h>
#include "MQTTClient.h"
//#include "led.h"
#include "DomoticzMessageParser.h"


//#define __DEBUG

#ifdef __DEBUG
#include <stdarg.h>
#include <string.h>
static const char *getCurrentFileName()
{
    const char *p = strrchr(__FILE__,'\\');
    return ++p;
}
#define dprintf(fmt,...) rt_kprintf("%s,line:%d,"fmt,getCurrentFileName(),__LINE__,##__VA_ARGS__)
#else
#define dprintf(fmt,...)
#endif

struct opts_struct
{
    char* clientid;
    int nodelimiter;
    char* delimiter;
    enum QoS qos;
    char* username;
    char* password;
    char* host;
    int port;
    int showtopics;
} opts =
{
    (char*)"subscriber on STM32", 0, (char*)"\n", QOS2, NULL, NULL, (char*)"192.168.1.230", 1883, 0
};

int is_over;

void quit_domoticz_thread(void)
{
    is_over = 1;
}

//================== Added 2017-Apr-27 8:06:53 start ==================
//处理连接的状态机结构
typedef struct 
{
    enum{
        UNCONNECTED = 0,
        NETWORK_CONNECTED=1,
        MQTT_CONNECTED=2,
        SUBSCRIBING_SUCCESS=3,
        WAIT_TIME_OUT=4,
        //SUBSCRIBING_FAILURE = 4
    }state;

    int timeout_s;//超时时间,单位为秒
    int times_count;//累计连续尝试连接次数,在连接成功后清零
}Connection_t;


void connect_time_out(void * data)
{
    Connection_t* con =(Connection_t*)data;

    if(con && con->timeout_s>0)
    {
        con->timeout_s --;
    }
}

#define NETWORK_CONNECT_TIMEOUT 5 //5s
#define MAX_NETWORK_CONNECT_TIMES 5
#define MQTT_CONNECT_TIMEOUT 1 //1s
#define MAX_MQTT_CONNECT_TIMES 5
#define SUBSCRIB_TIMEOUT 1 //1s
#define MAX_SUBSCRIB_TIMES 5
#define MAX_NO_PING_RESPONS_TIMES 10

Connection_t connection={UNCONNECTED,NETWORK_CONNECT_TIMEOUT,0};

//================== Added 2017-Apr-27 8:06:53  end ===================

void messageArrived(MessageData* md)
{
    MQTTMessage* message = md->message;

#if 0 /* Commented @ 2017-Apr-23 1:18:29 */
    if (opts.showtopics)
        rt_kprintf("%.*s\t", md->topicName->lenstring.len, md->topicName->lenstring.data);
    if (opts.nodelimiter)
        rt_kprintf("%.*s", (int)message->payloadlen, (char*)message->payload);
    else
        rt_kprintf("%.*s%s", (int)message->payloadlen, (char*)message->payload, opts.delimiter);
#endif /* Commented */
    dprintf("payloadlen=%d,%s\n",(int)message->payloadlen,(char*)message->payload);
    dprintf("strlen(payload)=%d\n",strlen((char*)message->payload));    
    //fflush(stdout);
    ParseDomoticzMessage((char*)message->payload);

    //dprintf("MSG: qos %d, retained %d, dup %d, packetid %d\n", message->qos, message->retained, message->dup, message->id);
}

void set_host(char *host)
{
    opts.host = host;
}



void domoticz_thread_entry(void* parameter)
{
    int rc = 0;
    unsigned char buf[512]={0};//buf[100];
    unsigned char readbuf[512]={0};//readbuf[100];

    char* topic = "domoticz/out";

    Network n;
    MQTTClient c;

    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;  

    rt_timer_t timer = rt_timer_create("connect_timer", connect_time_out, &connection, RT_TICK_PER_SECOND, RT_TIMER_FLAG_PERIODIC);
    is_over = 0;
    rt_kprintf("domoticz_thread_entry\n");

//================== Added 2017-Apr-26 2:36:53 start ==================
    RegisterHardware(Create_LED0(),2);
    RegisterHardware(Create_LED1(),3);
    OpenHardwares();
    SetupDomoitczMessageParser();   
    SetEnableParseItem(KEY_IDX);
    SetEnableParseItem(KEY_NVALUE);
    SetEnableParseItem(KEY_SWITCH_TYPE);
    initHardwareSettings();
//================== Added 2017-Apr-26 2:36:53  end ===================

    NetworkInit(&n);

    //dprintf("readbuf=%p,readbuf size=%u\n",readbuf,sizeof(readbuf));
    data.willFlag = 0;
    data.MQTTVersion = 3;
    data.clientID.cstring = opts.clientid;
    data.username.cstring = opts.username;
    data.password.cstring = opts.password;

    data.keepAliveInterval = 60;
    data.cleansession = 1;


    rt_timer_start(timer);
    while(!is_over)
    {   
        switch(connection.state)
        {
        case UNCONNECTED:
            if(connection.timeout_s>0)
                continue;
            rc = NetworkConnect(&n, opts.host, opts.port);
            if(rc==0)
            {
                connection.state = NETWORK_CONNECTED;
                connection.times_count = 0;
                rt_kprintf("NetworkConnect ok!\n");
                rt_kprintf("Connecting to %s:%d\n", opts.host, opts.port);
                MQTTClientInit(&c, &n, 1000, buf, sizeof(buf), readbuf, sizeof(readbuf));
            }
            else if(connection.times_count <MAX_NETWORK_CONNECT_TIMES)
            {
                connection.times_count++;
                connection.timeout_s = NETWORK_CONNECT_TIMEOUT;
            }
            else
            {//reset system cpu,restart
                connection.times_count=0;
                rt_thread_delay(RT_TICK_PER_SECOND*600);//10分钟后再连
                //goto exit;
            }
            break;
        case NETWORK_CONNECTED: 
            if(connection.timeout_s>0)
                continue;
            dprintf("\n");
            rc = MQTTConnect(&c, &data);
            dprintf("\n");
            if(rc == SUCCESS)
            {
                connection.state = MQTT_CONNECTED;
                connection.times_count = 0;

                rt_kprintf("MQTTConnected!\n");
                dprintf("Subscribing to %s\n", topic);
            }
            else if(connection.times_count <MAX_MQTT_CONNECT_TIMES)
            {
                rt_kprintf("MQTTConnect times=%d, err:%d! \n",connection.times_count,rc);
                connection.times_count++;
                connection.timeout_s = MQTT_CONNECT_TIMEOUT;
            }
            else
            {//重新进行network连接
                dprintf("\n");
                NetworkDisconnect(&n);
                connection.state = UNCONNECTED;
                connection.times_count=0;
                rt_thread_delay(RT_TICK_PER_SECOND*600);//10分钟后再连
            }
            break;
        case MQTT_CONNECTED:
            if(connection.timeout_s>0)
                continue;
            rc = MQTTSubscribe(&c, topic, opts.qos, messageArrived);
            if(rc == SUCCESS)
            {
                rt_kprintf("Subscribed %s\n", topic);
                connection.state = SUBSCRIBING_SUCCESS;
                connection.times_count = 0;
            }
            else if(connection.times_count <MAX_SUBSCRIB_TIMES)
            {
                rt_kprintf("MQTTSubscribe times=%d, err:%d! \n",connection.times_count,rc);
                connection.times_count++;
                connection.timeout_s = MQTT_CONNECT_TIMEOUT;
            }
            else
            {
                //1分钟后重新进行network连接
                rt_kprintf("MQTTSubscribe err! reconnect after 1 min\n");   
                MQTTDisconnect(&c);
                NetworkDisconnect(&n);
                connection.state = UNCONNECTED;
                connection.times_count=0;
                rt_thread_delay(RT_TICK_PER_SECOND*60);//1分钟后再连
            }
            break;
        case SUBSCRIBING_SUCCESS:
            MQTTYield(&c, 1000);
            if(c.ping_outstanding==1)
            {
                connection.times_count++;
                if(connection.times_count>MAX_NO_PING_RESPONS_TIMES)
                {
                    rt_kprintf("network err! reconnecting ...\n");  
                    MQTTDisconnect(&c);
                    NetworkDisconnect(&n);
                    connection.state = UNCONNECTED;
                    connection.times_count = 0;
                    //rt_thread_delay(RT_TICK_PER_SECOND*60);//1分钟后重连   
                }
            }
            else
            {
                connection.times_count = 0;
            }
            break;
        default:
            break;
        }

    }

exit:
    rt_kprintf("Stopping\n");   
    MQTTDisconnect(&c);
    NetworkDisconnect(&n);

    rt_timer_delete(timer);

}

void domoticz_thread_init(void)
{
    rt_thread_t domoticz_thread;
    domoticz_thread = rt_thread_create("DomoticzThread", domoticz_thread_entry, RT_NULL,
    0xf00, 28, 10);
    if (domoticz_thread != RT_NULL)
        rt_thread_startup(domoticz_thread);

}

#ifdef RT_USING_FINSH
#include <finsh.h>
FINSH_FUNCTION_EXPORT(set_host, set domoticz host ip addr);
FINSH_FUNCTION_EXPORT(domoticz_thread_init,to run domoticz thread );
FINSH_FUNCTION_EXPORT(quit_domoticz_thread,quit domoticz thread );
#endif

运行效果:
这里写图片描述

这里写图片描述

domoticz这边建立三个LED灯,idx分别为1,2,3

STM32开发板上的LED0的idx为2,LED1的idx为3。
也就是domoticz平台上的“LED灯2”对应开发板LED0;
domoticz平台上的“LED灯3”对应开发板LED1。

这里写图片描述

这里写图片描述

好了,现在在STM32开发板上看效果:
这里写图片描述

1、LED0亮:

这里写图片描述
这里写图片描述

2、LED1亮:

这里写图片描述
这里写图片描述

3、LED0、LED1都亮:

这里写图片描述
这里写图片描述

4、在mini2440板上运行前面做的mqtt客户端程序。

mini2440上也控制两个灯LED0,对应的idx为1;LED1,对应idx为2。
也就是说mini2440板上的LED1和STM32板上的LED0的idx是相同的,看看能不能同时点亮。

这里写图片描述

点亮mini2440的LED0:
这里写图片描述
这里写图片描述

下面将看到在domoticz上点亮LED2灯可以同时点亮mini2440上的LED1和STM32上的LED0:
这里写图片描述

这里写图片描述

都点亮:
这里写图片描述
这里写图片描述

5、Android手机实际控制效果:
这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

6、当MQTT的broker被关闭并重新打开后,STM32板的反应:

这里写图片描述

在程序中,其实只要ping 10次没有结果,就会断开MQTT连接和socket连接,并重新连接。
如果有网络错误,连接不上会,延时一段时间,然后重新连接socket,然后连MQTT的broker,然后订阅。
具体如上述源码中处理那样。

附:STM32开发板的整个源码工程下载地址:
http://download.csdn.net/download/sqshining/9828049

相关文章推荐

【STM8L】STM8L之内部16M晶振

本文介绍STM8L系列如何分别实现内部的16M晶振的使用

基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(十)使用domoticz+mosquitto+Android客户端实现控制STM32板上的LED(一)

本文将在前面mini2440建立的domoticz、mosquitto为服务器的基础上,以Android做远程客户端来实现对STM32芯片的开发板的LED进行灯控制,当然,这是一个基本功能的实现,如果...

基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(九)使用domoticz+mosquitto+Android客户端实现控制mini2440上的LED(二)

为了充分利用domoticz平台的对MQTT客户端的控制功能,现在,受控设备端代码的核心任务转移到了对domoticz/out主题的MQTT消息解析上。本文将设计一个简单框架来实现对其消息的解析和功能...

基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(六)使用domoticz联合arm上的mosquitto实现Android客户端远程控制

本篇将使用mini2440上的domoticz服务平台和mosquitto,以domoticz上的虚拟设备为例,实现对设备的控制,以及使用Android的客户端APP实现远程控制。...

基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(四)交叉编译OpenSSL、c-ares、e2fsprogs和mosquitto

本篇主旨是编译安装mosquitto,其他的库是它的依赖库。后面我们交叉编译的程序都将放置在主机的”/usr/local/arm/”目录中,以区别主机本地的应用程序。 我的mimi2440的根文件系...

基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(七)交叉编译paho.mqtt.embedded-c库和嵌入式linux样例程序

本篇将把paho.mqtt.embedded-c官方的源代码交叉编译成数据包封装库和应用程序两部分,并把样例应用程序在mini2440上运行。...

基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(五)交叉编译并安装zlib、curl、boost和domoticz

本篇是本次整合智能家居系统的重点,最终结果是将domoticz交叉编译并安装到mimi2440的嵌入式linux系统中,并让它运行起来,以供后续开发使用。1、交叉编译zlib: 解压zlib-1.2...

基于ZigBee和STM32的智能家居控制系统的设计与实现(二)

基于ZigBee和STM32的智能家居控制系统的设计与实现(二)  上一篇博客中总体介绍智能家居系统的基本实现原理,这篇博客和以后的几篇博客会详细进行相应的介绍。这里首先进行硬件电路的设计。硬件电路的...

基于ZigBee和STM32的智能家居控制系统的设计与实现(四)

简述在前几篇博客中介绍了智能家居系统的整体结构以及各个部分实现原理,感谢好多的朋友前来问候,给与了好多建议与支持,让我有了动力来写这篇博客,这篇博客作为本系统的终结篇,将会介绍剩下的问题。实现原理以下...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于mini2440嵌入式linux上整合一套Domoticz智能家居系统(十一)使用domoticz+mosquitto+Android客户端实现控制STM32板上的LED(二)
举报原因:
原因补充:

(最多只允许输入30个字)