端点物联开发教程之(二)开发演示

news2024/12/23 18:40:52

目录

一、产品定义

二、基础资源下载

三、嵌入式端开发

3.1 工程搭建

3.2 模型文件修改

3.3 头文件定义

3.4 模型功能开发

3.5 mqtt应用层配置

3.6启动任务

四、用户后端开发

4.1 功能分析

4.2 创建模型文件

4.3 添加基础功能

4.4 数据更新

4.5 阈值设置

4.6 模型添加

五、用户前端开发

5.1 界面分析

5.2 简易模型

5.3 完整模型

六、模型联调


本项目的交流QQ群:701889554

物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html

物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_12631333.html

物联网实战--平台篇https://blog.csdn.net/ypp240124016/category_12653350.html

资源文件下载https://download.csdn.net/download/ypp240124016/89425313

一、产品定义

        这是开发的第一步,首先要明确开发内容和目标。作为演示项目,我们定义为一个温湿度计,它的功能较为简单,就是定时上报温湿度数据,同时用户可以设置高温和高湿报警阈值,当温度或湿度超过阈值时候用户端界面会变成红色。

        那么,有上述定义可知,主要变量就是温度、湿度和两个各自的阈值,还有各自的报警状态,以下是字段定义表格:

        表格最后一列中的N是转正基数,避免在传输时出现负数;M是精度值,如果精度是小数点后一位那么M就等于10,后两位M就等于100,以此类推。这样做的好处在之前的净化器文章中有说过了,核心目的是为了保证传输的数据类型都是正整数,便于字节流传输时分解与整合,因为长度大于1字节的数据在网络传输中会出现网络序大小端的问题,不同的CPU架构大小端是不一样的,具体可以看下这篇文章。所以我们在设计传输协议的时候要规避这个问题,把所有的数值都转成正整数,然后统一高位先传输的原则转成字节流,这样就不存在大小端的问题了。

        有了具体字段之后就可以定义命令类型了,具体看下面表格:

        有了以上这些定义,我们就可以进行设备端的开发了。

二、基础资源下载

资源文件下载https://download.csdn.net/download/ypp240124016/89425313

        上图是资源结构图,我们现在要使用的是嵌入式端源码这个压缩包,把它解压出来就可以进行下一步的开发了。

三、嵌入式端开发
3.1 工程搭建

解压后目录如下:

点开Project文件夹,内容如下图所示,我们复制 Project-净化器(M2M) 整个文件夹在同目录下粘贴。

然后将副本改名为 演示温湿度计。

接着把下图这几个名字都改下就可以打开工作空间了,

最后打开目录里的工作空间,此时还没有温湿度计的项目,需要添加进来,顺序如下所示。同时把项目名称也改下,这样就完成了新项目的基础搭建了。

3.2 模型文件修改

        接下里就可以进入正式的开发了,首先删除app_ap01.c文件,这是原来净化器项目的文件,我们这里需要根据型号重新定义一个文件,型号就定义为TH01,所以新文件就是app_th01.c了,修改后的文件结构如下图所示,Keil的文件编辑格式最好改成UTF-8的,便于汉字注释。

        下图的两个头文件名称也改下,这样就可以编译了,编译后原来工程的相关内容会报错,删除或者注释掉就行,再编译一次,应该就能编译通过了,一个具体的工程模板就完成了,剩下的是具体产品内容定义了。

        

3.3 头文件定义

        模型文件从app_th01.h开始,根据第一节的产品定义,头文件定义如下:

        其中的温湿度报警阈值需要掉电保存,所以定义了一个存储结构体,为了确保数据的准确性,读取时候采用CRC校验,如果校验出错就使用默认的阈值。

3.4 模型功能开发

        首先进行配置参数读取,这里就是温湿度的报警阈值了。如果是第一次读取或者存储出错,那么就是用默认阈值,默认报警温度是50℃,默认报警湿度是95%。

        传感器部分只有温湿度了,这里沿用净化器项目的配置,接线是SDA--PB8,SCL--PB9。

        剩下的就是数据传输的内容了,根据定义,数据上行有状态数据和阈值数据,具体代码如下,其中状态数据发送前对报警状态做了判别,数据流根据定义里的N M值做了转换,发送时命令值也是根据头文件的定义传入。

        下行数据有三种类型,其中阈值数据并不需要实时发送,只有当用户端需要查看时再立刻发送即可,所以在用户端的物模型前端里设置请求指令进行请求一次即可,这样可以减少无效数据传输。这种需求在传统的物联网开发中比较难以实现,倒不是技术上有什么难度,而是沟通成本太高,正常嵌入式开发人员很难直接跟前端人员进行需求沟通的;那么,对于我们端到端的开发模式,这个需求可以内部自行消化。

        阈值设置就是赋值+保存了,没什么特别的;最后再即时返回当前阈值即可。

        最后就是将整个任务运行起来就行了。

        模型app_th01.c的所有C代码如下:


#include "app_th01.h" 
#include "app_mqtt.h" 

Th01SaveStruct g_sTh01Save={0};
Th01WorkStruct g_sTh01Work={0};

/*		
================================================================================
描述 : 配置参数读取
输入 : 
输出 : 
================================================================================
*/
void app_th01_read(void) 
{
  EEPROM_Read(TH01_EEPROM_ADDR, (u8 *)&g_sTh01Save, sizeof(g_sTh01Save));
  
  if(g_sTh01Save.crcValue!=drv_crc16((u8*)&g_sTh01Save, sizeof(g_sTh01Save)-2))
  {
    g_sTh01Save.temp_thresh=1500;//高于50℃报警
    g_sTh01Save.humi_thresh=950;//高于95%报警
    app_th01_write();
    printf("app th01 read new!\n");
  }  
  printf("alarm temp=%.1fC, humi=%.1f%%\n", (g_sTh01Save.temp_thresh-1000)/10.f, g_sTh01Save.humi_thresh/10.f);
}

/*		
================================================================================
描述 : 配置参数保存
输入 : 
输出 : 
================================================================================
*/
void app_th01_write(void)
{
  g_sTh01Save.crcValue=drv_crc16((u8*)&g_sTh01Save, sizeof(g_sTh01Save)-2);
  EEPROM_Write(TH01_EEPROM_ADDR, (u8 *)&g_sTh01Save, sizeof(g_sTh01Save));  
}

/*		
================================================================================
描述 : SHT30温湿度初始化
输入 : 
输出 : 
================================================================================
*/
void app_sht30_init(void)
{
  //SDA--PB8   SCL--PB9
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//开启引脚时钟
  I2cDriverStruct *pIIC=&g_sTh01Work.tag_sht30.tag_iic;
  
  //引脚赋值
  pIIC->pin_sda=GPIO_Pin_8;
  pIIC->port_sda=GPIOB;
  
  pIIC->pin_scl=GPIO_Pin_9;
  pIIC->port_scl=GPIOB;  
  
  drv_sht30_init(&g_sTh01Work.tag_sht30);//初始化
}

/*		
================================================================================
描述 : 整体初始化
输入 : 
输出 : 
================================================================================
*/
void app_th01_init(void)
{
  app_th01_read();//参数读取
  app_mqtt_init();  //mqtt应用层配置初始化
  app_sht30_init(); //温湿度传感器初始化
} 

/*		
================================================================================
描述 : 发送设备的状态数据
输入 : 
输出 : 
================================================================================
*/
void app_th01_send_status(void)
{
  u8 cmd_buff[20]={0};
  u16 cmd_len=0;
  u16 tmp_u16=0;
  
  tmp_u16=g_sTh01Work.tag_sht30.temp_value*10+1000;
  u8 temp_alarm=tmp_u16>=g_sTh01Save.temp_thresh;//报警检测
  cmd_buff[cmd_len++]=tmp_u16>>8;
  cmd_buff[cmd_len++]=tmp_u16;  //温度
  
  tmp_u16=g_sTh01Work.tag_sht30.humi_value*10;
  u8 humi_alarm=tmp_u16>=g_sTh01Save.humi_thresh;//报警检测
  cmd_buff[cmd_len++]=tmp_u16>>8;
  cmd_buff[cmd_len++]=tmp_u16;  //湿度
  
  g_sTh01Work.alarm_type=temp_alarm<<4 | humi_alarm;
  cmd_buff[cmd_len++]=g_sTh01Work.alarm_type;//报警类型  

  drv_server_send_msg(TH01_CMD_DATA, cmd_buff, cmd_len);//底层发送  
}

/*		
================================================================================
描述 : 发送阈值数据
输入 : 
输出 : 
================================================================================
*/
void app_th01_send_thresh(void)
{
  u8 cmd_buff[20]={0};
  u16 cmd_len=0;
  u16 tmp_u16=0;
  
  tmp_u16=g_sTh01Save.temp_thresh;
  cmd_buff[cmd_len++]=tmp_u16>>8;
  cmd_buff[cmd_len++]=tmp_u16;  //温度阈值
  tmp_u16=g_sTh01Save.humi_thresh;
  cmd_buff[cmd_len++]=tmp_u16>>8;
  cmd_buff[cmd_len++]=tmp_u16;  //湿度阈值

  drv_server_send_msg(TH01_CMD_THRESH, cmd_buff, cmd_len); //底层发送    
}


/*		
================================================================================
描述 : 设备解析服务器下发的数据
输入 : 
输出 : 
================================================================================
*/
u16 app_th01_recv_parse(u8 cmd_type, u8 *buff, u16 len)
{
  u8 *pData=buff;
  switch(cmd_type)
  {
    case TH01_CMD_THRESH://请求阈值数据
    {
      app_th01_send_thresh();//返回阈值数值
      break;
    }
    case TH01_CMD_SET_TEMP://设置温度阈值
    {
      u16 temp_thresh=pData[0]<<8|pData[1];
      pData+=2;
      g_sTh01Save.temp_thresh=temp_thresh;
      app_th01_write();//保存
      app_th01_send_thresh();//返回阈值数值
      break;
    }        
    case TH01_CMD_SET_HUMI://设置湿度阈值
    {
      u16 humi_thresh=pData[0]<<8|pData[1];
      pData+=2;
      g_sTh01Save.humi_thresh=humi_thresh;
      app_th01_write();//保存
      app_th01_send_thresh();//返回阈值数值
      break;
    }   
  }
  return 0;
}

/*		
================================================================================
描述 : 温湿度计总任务线程
输入 : 
输出 : 
================================================================================
*/
void app_th01_thread_entry(void *parameter) 
{
  u16 run_cnts=0;
  printf("app_th01_thread_entry start ****\n");
  delay_os(1000);
  app_th01_init();//初始化
   
  while(1)
  {
    app_mqtt_main(); //MQTT主程序
    delay_os(20);//延时,每个任务线程都要添加,才不会阻塞,最小延时5ms, 即delay_os(5);
    
    if(run_cnts%200==0)//20*200=4000ms 执行一次
    {
      drv_sht30_read_th(&g_sTh01Work.tag_sht30);//读取温湿度值
      
      app_th01_send_status();//上报状态数据
    }
  
    run_cnts++;
  }
  
}


3.5 mqtt应用层配置

        根据自己的应用需求,需要对app_mqtt.c的内容做配置修改,首先是测试的SN码要根据定义的设备型号进行设置,我们这里定义的型号值是A108,测试的SN是A1080123。

        其它要修改的就是模型的命令解析函数,通过函数接口注册即可。至于通讯密码,暂时跟之前的一样就行了,自己也可以随机生成,只要到时候跟QT的C++后端有对应就行了。

3.6启动任务

        最后,就是在user_app.c中启动任务就行了,至此,嵌入式端的开发就基本完成,剩下的就是等用户端的物模型完成后进行联调即可。

四、用户后端开发
4.1 功能分析

        下图是参考界面,我们只要在这个界面的基础上再加一个阈值设置即可。所以主要功能就是解析温湿度数据并发送到前端显示,同时根据报警类型设置提示文字和改变颜色;最后就是温湿度的阈值设置功能。

4.2 创建模型文件

        首先创建C++模型文件ModelTh01,该类继承于BaseModel类,

        

4.3 添加基础功能

        首先定义跟嵌入式端一样的命令类型,这个务必保持一致,命令值有修改需要两端同时修改;然后是基本的模型显示、隐藏函数和数据接口函数,这些接口都是通用的,不过不同的物模型需要自定义,具体如下图所示,都有注释。

        这些函数的具体代码如下,有些还不完善:

#include "ModelTh01.h"

ModelTh01::ModelTh01(QObject *parent) : BaseModel(parent)
{
    m_secTickets=0;
    checkTimer = new QTimer(this);
    checkTimer->setInterval(1*1000);//心跳检测
    checkTimer->start(); 
    connect(checkTimer, SIGNAL(timeout()),this,SLOT(slotCheckTimeout()));
}


void ModelTh01::slotCheckTimeout(void)
{
        m_secTickets++;
        if(m_onlineState>0)//离线检测
        {
            if(m_secTickets - m_onlineTime>40)
            {
                m_onlineState=DEV_STATE_OFF_LINE;       
            }
            else
            {
                m_onlineState=DEV_STATE_ON_LINE;
            }
//            emit siqUpdateOnlineState(m_onlineState);   
        }

}

QByteArray ModelTh01::takeModelPassword(u8 index)
{
    static u8 passwd_table[5][16]={
        0x9D, 0x53, 0x09, 0xBF, 0x75, 0x28, 0xDE, 0x94, 0x4A, 0xFD, 0xB3, 0x69, 0x1F, 0xD2, 0x88, 0x3E, 
        0xF4, 0xAA, 0x5D, 0x13, 0xC9, 0x7F, 0x31, 0xE7, 0x9D, 0x53, 0x06, 0xBC, 0x72, 0x28, 0xDB, 0x91,
        0x47, 0xFD, 0xB3, 0x66, 0x1C, 0xD2, 0x88, 0x3B, 0xF1, 0xB5, 0x75, 0x39, 0xFA, 0xBE, 0x7E, 0x42,
        0x03, 0xC7, 0x88, 0x4B, 0x0C, 0xD0, 0x91, 0x54, 0x15, 0xD9, 0x9A, 0x5E, 0x21, 0xE2, 0xA6, 0x67, 
        0x2A, 0xEB, 0xAF, 0x70, 0x34, 0xF4, 0xB8, 0x79, 0x3D, 0xFD, 0xC1, 0x82, 0x46, 0x06, 0xCA, 0x8B, 
    };
    if(index>=5)index=0;
    
    QByteArray ba;
    ba.setRawData((char*)&passwd_table[index][0], 16);
    return ba;
    
}


void ModelTh01::showModel(QObject *parent)
{
    hideModel();
    m_modelParent=parent; 
    if(m_modelEngine==nullptr)
    {
        m_modelEngine=new QQmlApplicationEngine(this);
        m_modelEngine->rootContext()->setContextProperty("theModelTh01", this);
        m_modelEngine->rootContext()->setContextProperty("theCenterMan", this->parent());
    }
    m_modelEngine->load("qrc:/qmlRC/modelQml/TH01/ModelTh01.qml");
}

void ModelTh01::hideModel(void)
{
    if(m_modelEngine)
        delete m_modelEngine;
    m_modelEngine=nullptr;
    m_modelParent=nullptr;
}


void ModelTh01::showSimple(QObject *parent)
{
    m_simpleParent=parent; 
    if(m_simpleEngine==nullptr)
    {
        m_simpleEngine=new QQmlApplicationEngine(this);
        m_simpleEngine->rootContext()->setContextProperty("theModelTh01", this);
        m_simpleEngine->rootContext()->setContextProperty("theCenterMan", this->parent());
    }
    m_simpleEngine->load("qrc:/qmlRC/modelQml/TH01/SimpleTh01.qml");
}

void ModelTh01::hideSimple(void)
{
    if(m_simpleEngine)
        delete m_simpleEngine;
    m_simpleEngine=nullptr;
    m_simpleParent=nullptr;
}

int ModelTh01::setRawData(u32 app_id, u32 dev_sn, u8 pack_num, u8 msg_type, u8 *msg_buff, u16 msg_len)
{
    if(dev_sn!=m_devSn)
        return 0;
    
    u8 *pData=msg_buff;
    msg_len=msg_len;
    if(m_upPackNum==pack_num)
        return 0;
    m_upPackNum=pack_num;
    m_appID=app_id;
//    qDebug()<<"msg_type="<<msg_type;
    switch(msg_type)
    {
        case TH01_CMD_DATA://状态数据
        {

            break;
        }
        case TH01_CMD_THRESH://阈值数据
        {
    
            break;
        }
    }
    QDateTime current_date_time = QDateTime::currentDateTime();
    m_updateTime=current_date_time.toString("hh:mm:ss");

    m_onlineTime=m_secTickets;
    m_onlineState=DEV_STATE_ON_LINE;
    return 0;
}
4.4 数据更新

        现在,我们需要对温湿度本身的功能进行完善,首先是定义信号函数,把状态数据发送到前端显示,内容有温度值、温度报警状态,湿度值、湿度报警状态;另一方面,还有温度阈值和湿度阈值,所以在此定义了两个信号函数:

        这两个函数是在数据解析函数里调用的,数据解析跟嵌入式端的数据组合正好是相反的过程,具体看下面的代码;同时,我们对设备的在线状态进行了更新。


int ModelTh01::setRawData(u32 app_id, u32 dev_sn, u8 pack_num, u8 msg_type, u8 *msg_buff, u16 msg_len)
{
    if(dev_sn!=m_devSn)
        return 0;
    
    u8 *pData=msg_buff;
    msg_len=msg_len;
    if(m_upPackNum==pack_num)
        return 0;
    m_upPackNum=pack_num;
    m_appID=app_id;
//    qDebug()<<"msg_type="<<msg_type;
    switch(msg_type)
    {
        case TH01_CMD_DATA://状态数据
        {
            int temp=pData[0]<<8|pData[1];//温度 原始数据
            float temp_f=(temp-1000)/10.f;//温度浮点数据
            pData+=2;
            int humi=pData[0]<<8|pData[1];
            float humi_f=humi/10.f;
            pData+=2;
            u8 alarm_type=pData[0];
            pData+=1;
            
            QString temp_str=QString::asprintf("%.1f", temp_f);
            QString humi_str=QString::asprintf("%.1f", humi_f);
            emit siqUpdateSensorValues(temp_str, humi_str, alarm_type>>4, alarm_type&0x0F);
            break;
        }
        case TH01_CMD_THRESH://阈值数据
        {
            int temp=pData[0]<<8|pData[1];//温度 原始数据
            float temp_f=(temp-1000)/10.f;//温度浮点数据
            pData+=2;
            int humi=pData[0]<<8|pData[1];
            float humi_f=humi/10.f;
            pData+=2;
            
            QString temp_str=QString::asprintf("%.1f", temp_f);
            QString humi_str=QString::asprintf("%.1f", humi_f);
            emit siqUpdateThresh(temp_str, humi_str);
            break;
        }
    }
    QDateTime current_date_time = QDateTime::currentDateTime();
    m_updateTime=current_date_time.toString("hh:mm:ss");

    m_onlineTime=m_secTickets;
    m_onlineState=DEV_STATE_ON_LINE;
    return 0;
}
4.5 阈值设置

        阈值设置需要提供函数接口给前端调用,根据QML的特性,C++端的函数加上Q_INVOKABLE关键字后就可以暴露给前端QML了,传入参数一般是字符串,具体内容让C++方面来判断比较方便,最后把结果返回显示就行。对于阈值设置,根据文档定义组合数据,具体的以下两个函数就解决了。


QString ModelTh01::setTempThresh(QString temp_str)
{
    float temp_f=temp_str.toFloat();
    if(temp_f<0.f || temp_f>120.f)
    {
        return QString("输入范围有误!");
    }
    
    u16 temp_u16=temp_f*10+1000;
    u8 make_buff[100]={0};
    u16 make_len=0;
    make_buff[make_len++]=temp_u16>>8;
    make_buff[make_len++]=temp_u16;
    emit sigSendDownMsg(m_appID, m_devSn, m_downPackNum++, TH01_CMD_SET_TEMP, make_buff, make_len);
    return "";
}

QString ModelTh01::setHumiThresh(QString humi_str)
{
    float humi_f=humi_str.toFloat();
    if(humi_f<20.f || humi_f>100.f)
    {
        return QString("输入范围有误!");
    }
    
    u16 humi_u16=humi_f*10;
    u8 make_buff[100]={0};
    u16 make_len=0;
    make_buff[make_len++]=humi_u16>>8;
    make_buff[make_len++]=humi_u16;
    emit sigSendDownMsg(m_appID, m_devSn, m_downPackNum++, TH01_CMD_SET_HUMI, make_buff, make_len);
    return "";
}

        这样,物模型的C++后端就完成了,整体看来,跟C++也没多大关系,所以只要有点C语言的基础,开发物模型很容易就上手了。

4.6 模型添加

        基本模型开发完成后可以添加到主程序内,这样便于后续前端的调试开发,根据下面图片步骤在CenterMan类中操作即可。


      密码添加

五、用户前端开发
5.1 界面分析

        再次看下这个界面,主要就是一个渐变色背景+数值显示,温湿度有各自的状态提示;最后就是在合适的位置加入阈值设置的功能。

5.2 简易模型

        先搞定网格内的简易模型,对于温湿度计较为简单,就是图片替换,底部温湿度值显示即可。那么,我们要先准备好图片和创建简易模型文件,简易模型继承于BaseSimpleView,这个文件已经有了基本布局,只要修改内容即可。添加或者删除QML文件后需要鼠标右键项目工程,点击  执行qmake 才能正确编译。

        然后再加入一些模型自身的内容,即温湿度显示,主要就是接收来自后端的更新数据了,在温湿度显示那里,我们对报警状态用红色字体显示。

有了这个基本模型,就可以添加看看效果了。在主页的右上角 手动添加即可,SN要输入正确,具体效果如下,照片可以选择自己喜欢的。

        

5.3 完整模型

        完整模型也需要再建立文件,该文件继承于BaseModelView,文件主要是对颜色进行了配置,整体效果如下。

        然后就是数据显示模块了,由于温湿度显示结构基本一致,主要是内容差异,所以显示单元可以做成一个组件模块,然后在主页面里配置即可。该模块的效果和代码如下:

import QtQuick 2.7
import "../base"

//数据显示单元
Item {
    
    signal siqThreshClicked()
    property var headText: "温度 | 正常"
    property var valueText: "26.3"
    property var valueColor: "white"
    property var unionText: "℃"
    property var threshText: "50.0"
    implicitWidth: 300
    implicitHeight: 200
    
    
    Text{
        id:id_headText //头部标题
        height: 40
        width: 160
        anchors
        {
            horizontalCenter:parent.horizontalCenter
            top:parent.top
        }
        text: headText
        font.pointSize: 18
        font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"
        color: "white"
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignHCenter
    }
    
    Text{
        id:id_valueText //数值
        height: 100
        width: 150
        anchors
        {
            horizontalCenter:parent.horizontalCenter
            top:id_headText.bottom
            topMargin:10
        }
        text: valueText
        font.pointSize: 50
        font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"
        color: valueColor
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignHCenter
    }
    
    Text{
        id:id_unionText //单位
        height: 40
        width: 60
        anchors
        {
            right:id_headText.right
            top:id_valueText.top
        }
        text: unionText
        font.pointSize: 15
        font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"
        color: "white"
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignRight
    }
    
    Text{
        id:id_threshText //阈值
        height: 40
        width: 40
        anchors
        {
            horizontalCenter:id_valueText.horizontalCenter
            top:id_valueText.bottom
        }
        text: threshText
        font.pointSize: 15
        font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"
        font.bold: id_mouseArea.pressed
        color: "white"
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignRight
        MouseArea
        {
            id:id_mouseArea
            anchors.fill: parent
            onClicked: 
            {
                siqThreshClicked()
            }
        }
    }
    Text{
        id:id_union2Text //单位
        height: 40
        width: 60
        anchors
        {
            left:id_threshText.right
            verticalCenter:id_threshText.verticalCenter
        }
        text: unionText
        font.pointSize: 15
        font.family: Qt.platform.os === "windows" ? "宋体" : "黑体"
        color: "white"
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignLeft
    }
    
}

        底部比较小的数值即阈值,点击文本就会弹出设置对话框。这里的对话框与主程序的对话框类似,因为物模型的qml和主程序的qml是隔离的,所以主程序的基础文件可以根据需要迁移到物模型这边过来。

        那么,对于阈值对话框就可以从BaseEditDialog这边继承过来了。

        在完整模型文件内,对模块参数进行配置,定义了温度模块和湿度模块,设置对话框根据打开类型进行温湿度设置的区分,具体如下:

        完整模型内,数据更新是通过后端发送过来的数据进行判断显示,具体如下:

        最后,在打开完整模型后,前端应该主动请求一下阈值数据,

        这样,整个物模型的开发基本完成了。

六、模型联调

        接下来就是整个物模型的联调了,首先设备端直接用代码配置一下app_id和dev_sn,然后注释再重新编译烧录,这样设备就变成有设备号的初始状态了。

        QT端重新执行qmake,然后编译运行,等设备差不多联网成功后,手动添加设备,SN为A1080123,添加成功后简易模型和完整模型的界面如下所示:

                     

        下面是演示视频:

温湿度计

        如果设置和颜色变化没问题,那这个模型基本上也就成了。

        总体来讲,整个物模型的开发和上线还是挺简单的,相比于用json描述物模型,直接代码操作灵活性会更好;在编写物模型的过程中,虽然用到了C语言和QT的C++、QML,但是后端内容跟C++关系并不大,照着其它已有模型做更改就行了,只要遵循一些C++的代码格式即可;而QML类似于js语言,js语言与C语言本质上属于同一语系,语法上很相似,只要多做几个界面,QML很容易就上手了。

        所以,端点物联的开发套件很适合嵌入式端的开发人员做一些自己的创意产品,有C语言基础之后,对照着其它模型、按自己的想法更改,就能快速开发、上线一款自己的物联网产品。相比于米家、涂鸦、阿里云这些大平台,流程和难度降低了很多,很适合个人开发者。

本节的嵌入式工程:https://download.csdn.net/download/ypp240124016/89428338

本节的QT工程:https://download.csdn.net/download/ypp240124016/89428344

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1818780.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python私教张大鹏 Vue3整合AntDesignVue之Checkbox 多选框

何时使用 在一组可选项中进行多项选择时&#xff1b; 单独使用可以表示两种状态之间的切换&#xff0c;和 switch 类似。区别在于切换 switch 会直接触发状态改变&#xff0c;而 checkbox 一般用于状态标记&#xff0c;需要和提交操作配合。 案例&#xff1a;多选框组件 核心…

计算机图形学入门10:着色

1.真实的世界 经过前面的变换&#xff0c;再到三角形遍历&#xff0c;深度缓存后&#xff0c;屏幕上每个像素都有了对应的颜色&#xff0c;显示的结果大概是如下左图的样子&#xff0c;我们发现物体每个面的颜色都一样&#xff0c;看起来不够真实。而如下右图显得更加真实&…

java学生考勤管理系统

学生考勤管理系统 学生考勤管理系统。功能&#xff1a;登录&#xff0c;班级管理&#xff0c;课程管理&#xff0c;用户管理&#xff0c;课程表管理&#xff0c;个人信心&#xff0c;修改密码。 技术&#xff1a;java&#xff0c;ssh&#xff0c;struts&#xff0c;spring&…

动手学操作系统(七、实现内存分页机制)

动手学操作系统&#xff08;七、实现内存分页机制&#xff09; 在上一节中&#xff0c;我们成功读取了物理内存的容量&#xff0c;并且在之前的学习中&#xff0c;我们的程序已经进入了保护模式&#xff0c;地址空间能够达到4GB&#xff0c;但是所有的进程&#xff08;包括操作…

开发TEE的踩坑之配置PCCS

系统&#xff1a;Ubuntu20.04&#xff08;双系统&#xff0c;非虚拟机&#xff09; 一、解决node.js的版本问题二、解决开启PCCS服务的问题1、解决开启PCCS服务2、解决访问本地的8081端口 本系列为笔者开发TEE&#xff08;Trusted Execution Environment&#xff0c;可信执行环…

k8s metrics-server服务监控pod 的 cpu、内存

项目场景&#xff1a; 需要开启指标服务&#xff0c;依据pod 的 cpu、内存使用率进行自动的扩容或缩容 pod 的数量 解决方案&#xff1a; 下载 metrics-server 组件配置文件&#xff1a; wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/…

【已解决】Python 中 AttributeError: ‘NoneType‘ object has no attribute ‘X‘ 报错

本文摘要&#xff1a;本文已解决 AttributeError: ‘NoneType‘ object has no attribute ‘X‘ 的相关报错问题&#xff0c;并总结提出了几种可用解决方案。同时结合人工智能GPT排除可能得隐患及错误。 &#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱…

HTML静态网页成品作业(HTML+CSS+JS)—— 美食企业曹氏鸭脖介绍网页(4个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;使用Javacsript代码实现 图片轮播切换&#xff0c;共有4个页面。 二、…

称重显示模块 Modbus RTU 通信

目录 一、智能称重数字显示器模块(带通信)1、称重传感器接线说明称重显示模块称重传感器USB 转 TTL 2、校准传感器&#xff08;标定&#xff1a;零点标定、满度标定&#xff09; 二、Modbus RTU 协议1、Modbus RTU 数据帧2、数据帧格式请求帧响应帧 三、上位机电脑与称重显示模…

使用神卓互联来访问单位内部web【内网穿透神器】

在现代工作环境中&#xff0c;有时我们需要从外部访问单位内部的 web 资源&#xff0c;而神卓互联这款内网穿透神器就能完美地满足这一需求。 使用神卓互联来访问单位内部 web 其实并不复杂&#xff0c;以下是大致的使用步骤和配置方法。 首先&#xff0c;我们需要在单位内部的…

基于Unet++在kaggle—2018dsb数据集上实现图像分割

目录 1. 作者介绍2. 理论知识介绍2.1 Unet模型介绍 3. 实验过程3.1 数据集介绍3.2 代码实现3.3 结果 4. 参考链接 1. 作者介绍 郭冠群&#xff0c;男&#xff0c;西安工程大学电子信息学院&#xff0c;2023级研究生 研究方向&#xff1a;机器视觉与人工智能 电子邮件&#xff…

【电机】开环控制系统和闭环控制系统

1 什么是控制系统 控制系统是指由控制主体、控制客体和控制媒体组成的具有自身目标和功能的管理系统。也可以理解为&#xff1a;为了使控制对象达到预期的稳定状态。例如一个水箱的温度控制&#xff0c;可以通过控制加热设备输出的功率进而来改变水温达到目标温度&#xff0c;…

Linux发邮件的工具推荐有哪些?如何配置?

Linux发邮件的功能怎么样&#xff1f;Linux系统如何设置服务器&#xff1f; 在Linux操作系统中&#xff0c;有多种工具可供选择用来发送电子邮件&#xff0c;每种工具都有其独特的特点和适用场景。AokSend将介绍几种常用的Linux发邮件工具&#xff0c;并分析它们的优缺点和适用…

接口自动化测试的全面解析与实战指南!

&#x1f680; 【引言】&#x1f680; 接口自动化测试&#xff0c;作为现代软件开发生命周期中的关键一环&#xff0c;扮演着“质量守门员”的角色。它不仅关乎提升开发速度&#xff0c;更在于确保每一次更新都能可靠地满足用户期待。接下来&#xff0c;我们将踏上一场深入浅出…

Redis分布式锁的实现、优化与Redlock算法探讨

Redis分布式锁最简单的实现 要实现分布式锁,首先需要Redis具备“互斥”能力,这可以通过SETNX命令实现。SETNX表示SET if Not Exists,即如果key不存在,才会设置它的值,否则什么也不做。利用这一点,不同客户端就能实现互斥,从而实现一个分布式锁。 举例: 客户端1申请加…

RH850---注意问题积累--1

硬件规格(引脚分配&#xff0c;内存映射&#xff0c;外设功能规格、电气特性、时序图)和操作说明 注意:有关使用的详细信息&#xff0c;请参阅应用说明 ---------外围函数。。。 1:存储指令完成与后续同步指令的一代 当控制寄存器被存储指令更新时&#xff0c;从存储的执行开始…

在网站建设时,如何选择适合自己的网站模版

可以根据以下几个地方选择适合的网站模板 1.公司的核心业务 根据公司的业务内容来确定网站展示的内容之一&#xff0c;不同的业务内容可以有不同的展示方式&#xff0c;以此来确定网站的展示风格之一&#xff0c;公司肯定是要有明确的业务内容&#xff0c;并且能够在网站…

[C#]winform使用onnxruntime部署LYT-Net轻量级低光图像增强算法

【训练源码】 https://github.com/albrateanu/LYT-Net 【参考源码】 https://github.com/hpc203/Low-Light-Image-Enhancement-onnxrun 【算法介绍】 一、研究动机 1.研究目标 研究的目标是提出一种轻量级的基于YUV Transformer 的网络&#xff08;LYT-Net&#xff09;&…

neo4j-官网学习

1、cypher 代码学习文档 https://neo4j.com/docs/cypher-cheat-sheet/5/auradb-enterprise 2、APOC函数包安装&#xff08;desktop&#xff09; 直接点击就可以安装&#xff0c;安装完之后重启一下&#xff0c;Cypher查询中使用CALL apoc.help(‘apoc’)来检查APOC插件是否已…

Java技术驱动的工程项目管理系统源码:工程管理的数字化解决方案

工程项目管理系统是一款基于Java技术的专业工程管理软件&#xff0c;它采用了Spring Cloud、Spring Boot、Mybatis、Vue和ElementUI等前沿技术&#xff0c;通过前后端分离架构构建了一个功能全面的工程项目管理系统。 随着公司的发展&#xff0c;工程管理的需求日益增长&#x…