物联网浅尝:使用MQTT接入onenet平台,结合APP使用esp8266控制ws2812

手头有一块ws2812的灯板,想着能不能玩点什么。于是做了个APP去控制ws2812。写一篇博文记录下,废话不多说,看我怎么做。
(注:本文是小白简易教程)
首先来看下实际效果B站链接,点击这里
这是整体的框图,控制是单向的,并不需要接收反馈。
简单的整体框架图

一、简单概念介绍

MQTT协议:

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
在这里插入图片描述

简单来说,MQTT是一种轻量级小开销的网络协议,适合嵌入式等小型设备的云端通信,很适合物联网,在智能家居中有很多的应用。因为信息量小,所以也很快,但前提是得有网络接入点。
信息的传输是通过主题(topic)管理的。发布者有需要分发的数据时,其向连接的消息代理发送携带有数据的控制消息。代理会向订阅此主题的客户端分发此数据。发布者不需要知道订阅者的数据和具体位置;同样,订阅者不需要配置发布者的相关信息。
再多的就不多加深入了,有兴趣可以进一步自己去了解。

WS2812:

这是一个RGB灯,大概长这样(灯条状的也有,五花八门)。8*8矩阵WS2812
WS2812B是一个集控制电路与发光电路于一体的智能外控LED光源。其外型与一个5050LED灯珠相同,每个元件即为一个像素点。像素点内部包含了智能数字接口数据锁存信号整形放大驱动电路,还包含有高精度的内部振荡器和可编程定电流控制部分,有效保证了像素点光的颜色高度一致。
WS2812/2811只需一根信号线就能控制灯带上所有led。多个灯带间可以通过串联轻松延长。在30hz的刷新频率下一个信号线能够控制至多500个led。
简而言之啊,它就是一个可以任意调整RGB值的彩色灯,很酷,很炫。在这里插入图片描述
只要给他接上电源(VSS),接地(GND),再给一个输出(DIN),就可以控制复数个ws2812了,单个ws2812的引脚图如上,每个ws2812之间的DOUT和DIN是相互连接的,你输入的数据就像火车,从每个ws2812的DIN流进,再从DOUT流出,流向下一个ws2812的DIN一直到底。对整个灯板(条)来说,你只要接好以下三根线就可以了。
在这里插入图片描述
值得注意的是怎么去控制(怎么发送命令)。每个器件都有它自己的规则,ws2812也不例外。来看看它的01码(如下图)。我们发现,只要控制高电平和低电平的时间占比为2:1,就是1码,当这个比为1:2的时候则为0码,但是我们发现这个时间的误差为纳秒级的,这对你的控制装备的时钟就有要求。
有了01码后就好说了,我们知道设定RGB有三个值,分别是R值、G值和B值,三个值的范围是(0-255),换成二进制也就是八位,也就是说我们只要往(DIN)写入8*3=24位01码,我们就可以控制一个灯的颜色了。多个ws2812以此类推,它是串联过去的。
你或许觉得这样会很麻烦,但是不用担心,我们有现成的控制库可以使用,所以前面的内容懂个大概就好了。
在这里插入图片描述
ESP8266:

这个东西我相信有不少人都很熟悉的,简单来说就是一块可以接入互联网的小板子,它有WIFI模块,内部集成MCU可以实现单片机之间的通信。这里我们用它控制WS2812同时使它联网。在这里插入图片描述
Android 开发:

这里我们得准备一台手机,零基础也没有关系,因为我也差不多哈哈。但这并不妨碍我们在实际动手的过程中学习。

ONENET平台:

中国移动的一个物联网平台,我们就是在它提供的服务上,来实现APP与esp8266的通信的。

二、每个部分的开发操作流程

我们自下而上好了。

esp8266:

这边我用的是arduino的IDE,旁边写有注释的,自己留意。看不懂的地方可以再留言。

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#include <Adafruit_NeoPixel.h>//灯厂的库
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN            4//定义esp输出管脚,GPIO4,也就是板子上标的2
 
#define NUMPIXELS      64//用的是8*8的ws2812,自然是64个

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);//像素初始化,是库的标准使用方法,可以自己与GitHub上看

WiFiClient espClient;
PubSubClient client(espClient);
const char* wifissid = "your wifi"; //改成自己家wifi
const char* password = "your wifi password"; //改成自己家wifi
const char* mqtt_server = "183.230.40.39";//onenet的订阅IP地址
const char* mqtt_id = "device ID";   //设备ID,写自己的
const char* product_id="product ID";//产品ID,写自己的
const char* key="API_key";
const char* Mqtt_sub_topic = "topic_pub";   //订阅的TOPIC,用自己的topic名字
const char* Mqtt_pub_topic = "topic_sub";  //  上报消息给手机APP的TOPIC
long last_time=0;

uint8_t RDE,GRE,BLE,LIG;//RGB数值

//获取x的y次方; x^y
unsigned int power(int x, int y)
{
    unsigned int result = 1;
    while (y--)
        result *= x;
    return result;
}
//将字符串的内容转换为 16进制,这里用到了上面的power函数,是为了能够吧消息中的字符串信息转化为esp可以控制ws2812的数值
unsigned int hex_conver_dec(String src)
{   
    char str_array[src.length()+1];
    src.toCharArray(str_array, src.length()+1);
    char *tmp = str_array;
    int len = 0;
    unsigned int hexad = 0;
    char sub = 0;

    while (1)
    {
        if (*tmp == '0')            //去除字符串 首位0
        {
            tmp++;
            continue;
        }           
        else if (*tmp == 'X')
        {
            tmp++;
            continue;
        }
        else if (*tmp == 'x')
        {
            tmp++;
            continue;
        }
        else
            break;

    }

    len = strlen(tmp);
    for (len; len > 0; len--)
    {        
        sub = toupper(*tmp++) - '0';
        if (sub > 9)
            sub -= 7;
        hexad += sub * power(16, len - 1);      
    }

    return hexad;
}


void setup() {

#if defined (__AVR_ATtiny85__)
  if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif

  pixels.begin();
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 6002);
  client.setCallback(callback);
  
}
//设置WIFI信息
void setup_wifi() {
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(wifissid);
  WiFi.begin(wifissid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}
//回调函数
void callback(char* topic, byte* payload, unsigned int length) {
  String msg="";
  String LED_set = "";
  float k;
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    msg+= (char)payload[i];
  }
  Serial.println(msg);
  RDE=hex_conver_dec(msg.substring(0,2));
  GRE=hex_conver_dec(msg.substring(2,4));
  BLE=hex_conver_dec(msg.substring(4,6));
  LIG=hex_conver_dec(msg.substring(6,8));
  k=(float)LIG/100;
  show(RDE,GRE,BLE,k);
  Serial.println(RDE);
  Serial.println(GRE);
  Serial.println(BLE);
    Serial.println(k);
}
//检测连接
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect(mqtt_id,product_id,key)) {
      Serial.println("connected");
      //连接成功以后就开始订阅
      client.subscribe(Mqtt_sub_topic,1);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

//灯光部分,根据RGB值显示灯光矩阵控制色温,这里的代码写的有点烂,因为我是在原来的基础上改动的,当时写的和最近写的有不少出入,方便就这么改了,放心功能是正常的
void show(uint8_t r,uint8_t g,uint8_t b,float k)
{
    uint32_t rgb,RGB1;
    uint8_t RDE1,GRE1,BLE1;
    RGB1= ((uint32_t) r << 16) | ((uint32_t) g << 8) | b;
    rgb=changeL(RGB1,k);
    RDE1= (uint8_t) (rgb >> 16);
    GRE1= (uint8_t) (rgb >> 8);
    BLE1= (uint8_t) (rgb);
    pixels.fill(pixels.Color(RDE1,GRE1,BLE1),0,NUMPIXELS);//设置RGB的值
    pixels.show();//展示
}
//根据色彩亮度改变色温,依照公式,改变亮度不是简单的降低每个RGB的值,那样会改变颜色的,这个可以去网上查阅资料。亮度范围是0-1。
uint32_t changeL(uint32_t rgb, float k) {
  uint8_t r, g, b;
  float h, s, v;
  uint8_t cmax, cmin, cdes;
 
  r = (uint8_t) (rgb >> 16);
  g = (uint8_t) (rgb >> 8);
  b = (uint8_t) (rgb);
 
 
  cmax = r > g ? r : g;
  if (b > cmax)
    cmax = b;
  cmin = r < g ? r : g;
  if (b < cmin)
    cmin = b;
  cdes = cmax - cmin;
 
  v = cmax / 255.0f;
  s = cmax == 0 ? 0 : cdes / (float) cmax;
  h = 0;
 
  if (cmax == r && g >= b)
    h = ((g - b) * 60.0f / cdes) + 0;
  else if (cmax == r && g < b)
    h = ((g - b) * 60.0f / cdes) + 360;
  else if (cmax == g)
    h = ((b - r) * 60.0f / cdes) + 120;
  else
    h = ((r - g) * 60.0f / cdes) + 240;
 
 
  v *= k;
 
  float f, p, q, t;
  float rf, gf, bf;
  int i = ((int) (h / 60) % 6);
  f = (h / 60) - i;
  p = v * (1 - s);
  q = v * (1 - f * s);
  t = v * (1 - (1 - f) * s);
  switch (i) {
  case 0:
    rf = v;
    gf = t;
    bf = p;
    break;
  case 1:
    rf = q;
    gf = v;
    bf = p;
    break;
  case 2:
    rf = p;
    gf = v;
    bf = t;
    break;
  case 3:
    rf = p;
    gf = q;
    bf = v;
    break;
  case 4:
    rf = t;
    gf = p;
    bf = v;
    break;
  case 5:
    rf = v;
    gf = p;
    bf = q;
    break;
  default:
    break;
  }
 
  r = (uint8_t) (rf * 255.0);
  g = (uint8_t) (gf * 255.0);
  b = (uint8_t) (bf * 255.0);
 
  uint32_t returnColor = ((uint32_t) r << 16) | ((uint32_t) g << 8) | b;
  return returnColor;
}
//执行连接
void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();


}

ONENET:

onenet的本质就是一台服务器,我选择它的原因是它是免费的而且比较可靠,当然你也可以选择阿里云或者其他的什么云或者物联网接入平台,反正我们的根本目的就是找到一台可以为我们提供MQTT协议的服务器。
既然要在这个平台上操作,我们首先得有自己的账号,然后进入控制台,我习惯用旧版,点击切换至旧版,
在这里插入图片描述

如下选择多协议接入
在这里插入图片描述
然后添加产品,记得协议选择MQTT
在这里插入图片描述
信息自己填,放心大胆,创建成功后,点击产品,从左侧的设备列表中添加设备,信息自己填,放心大胆
在这里插入图片描述
注意以下几个信息:产品ID,设备ID,APIkey。服务器的地址和端口号我们是知道的,但是想想onenet上这么多用户这么多产品设备我们怎么知道信息从哪里发往哪里呢。我们可以这么理解,onenet是一个小区,产品ID就是楼栋的几幢几幢(楼号),而设备ID就是某栋楼的某扇门,但是开门还需要钥匙,这就是我们的APIkey了。通过层层问路,就到达了我们的目的地。所以这几个信息我们是要留意的,我们要把相应的信息填入到我们发送端APP中去和esp8266中,这样才能建立通信不是么。
在这里插入图片描述
这样我们云端的部分就完成了,就差我们的APP啦。
注:onenet有自己的调试工具,相关信息可以去查找其他网络资料。

Android APP开发:

如果我自己来说,绝对是长篇了,因为这本来就是一个大块知识。这里我推荐一个up主:阿正啷个哩个啷。他讲的简短易用,学了之后就能开发简单的APP了。
这里我直接把我的工程放上来,当然直接拿过去用可能会存在版本问题,所以可以打开来自己参考。用的是Android Studio,怎么搭配环境都是基本的了,老生常谈自己领会吧。当然我会把apk也直接放上来,可以直接体会下我这个小项目。
度盘链接:
https://pan.baidu.com/s/18fANWXFaUWuhEhBZSW_LYg
提取码:
chgi

三、总结

物联网也总是这么一个把东西接入网络,然后互相通信。都说了是Internet of thing了嘛。这个工程虽然看上去很简单,但也融合了不少的知识,比如嵌入式开发,安卓开发,一些基本的网络知识等等。坐而言不如起而行,有时候实际动手才是学知识的最快来源。感谢你阅读到最后,大家一起勉励!

  • 5
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
stm32f1是一种单片机,可以用来实现各种功能的控制。阿里云是一家提供物联网平台的公司,可以通过他们的mqtt协议来实现设备之间的通信。智能配网是指通过手机app来连接并配置设备,使其能够通过网络进行控制,这在物联网应用中非常常见。继电器是一种电子开关,可以用来控制电路的通断。而温度传感器可以用来感知环境的温度变化。 在这个场景中,可以使用stm32f1来连接阿里云mqtt服务器,实现设备之间的通信。手机app上可以通过配网功能将设备与网络连接起来,并进行配置。然后,通过mqtt协议,手机app可以向stm32f1发送控制指令,从而控制继电器的开关状态。通过连接温度传感器到stm32f1,可以实时感知温度的变化,并将温度数据上传到阿里云,手机app可以通过mqtt协议接收到温度数据并进行展示。 在实现过程中,可以使用esp8266作为stm32f1的wifi模块,使其能够连接到网络。通过阿里云mqtt库,可以方便地实现mqtt通信功能。同时,可以使用stm32f1的GPIO引脚来控制继电器的通断。温度传感器可以通过类似DS18B20的数字传感器连接到stm32f1的GPIO引脚上。 总之,通过使用stm32f1单片机、阿里云mqtt协议、智能配网的手机app、继电器和温度传感器,可以实现通过app控制继电器和获取温度数据的功能,为物联网应用提供了一种便捷的解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值