项目源于我在B站刷到的氛围灯设计,利用ThingsCloud云平台与ESP32完成,具有炫彩氛围灯的效果,我对官方给出的例程完成了复现。
文章目录
前言
本项目是个人对ThingsCloud分享的开源项目的复现
`
一、前期准备
1、VScode:作为esp32编写代码及调试下载的平台,使用platform插件配置esp32编译环境,具体参考其他大佬的讲解。
2、ESP32硬件开发板一块:淘宝购买普通款即可
3、WS2812灯环(注意是灯环)
4、杜邦线、面包板等
二、硬件介绍
1、ESP-WROOM-32
2、WS2812灯环
WS2812数字灯带采用串行通讯方式进行数据传输,每个灯带芯片都包含了一个控制器和三个LED灯。在传输过程中,控制器会接收到来自外部的RGB颜色值和亮度信息,并通过内部控制电路对LED灯进行控制。
具体地说,WS2812使用了一种特殊的时序控制方式,将RGB颜色值和亮度信息转化为一系列高低电平信号,通过串行通讯方式传输到下一个灯带芯片。每个灯带芯片会根据接收到的数据控制三个LED灯的亮度和颜色,同时将剩余的数据传输给下一个芯片,最终形成一个连续的灯带效果。
由于WS2812芯片集成了控制电路和LED灯,使得其具有简单、紧凑的结构和较低的功耗。同时,该灯带支持大量的颜色、亮度、变化效果组合,可以满足不同场景的需求。
通俗的说,WS2812只有一个输入口,但可以通过控制每一个芯片接收数据的不同来控制RGB颜色。
三、软件介绍
打开vscode,创建一个ESP32工程,导入thingscloud开源的氛围灯例程代码,我将详细的进行分析:
1.引入库
代码如下:
#include <Arduino.h>
#include <Adafruit_NeoPixel.h>//RGB外设库头文件
#include <DHT.h>//DHT11温湿度监测
#include <ThingsCloudMQTT.h>//thingscloud的MQTT协议头文件
#include <ThingsCloudWiFiManager.h>//wifi管理头文件
#include <ArduinoJson.h>
#include <WiFi.h>
#include <PubSubClient.h>
//=========================================================================
//mqtt相比htpp是更适合于物联网云端与用户端通信的协议,htpp仅适合于云端接收设备数据,而mqtt还另外具有上位机向设备发送命令的作用
#ifdef __AVR__
#include <avr/power.h>
#endif
2.配置wifi、mqtt、RGB
由于我对代码进行了详细注释,故不做额外解释,代码如下:
const char ssid[] = ""; // WIFI账户
const char password[] = ""; // WIFI密码
//thingscloud云平台配置
// 在 ThingsCloud 控制台的设备详情页中,复制以下设备连接信息
#define mqtt_broker "bj-2-mqtt.iot-api.com"
#define mqtt_port 1883
#define PROJECT_KEY ""
String ACCESS_TOKEN = "";
//=============================================================================
WiFiClient net;//给库WIFiclient实例化一个类net
void callback(char *topic,byte *payload,unsigned int length);
PubSubClient mqtt(mqtt_broker,mqtt_port,callback,net);//实例化库PUBsubclient的一个类mqtt
//RGB灯配置
#define LED_COUNT 12//告诉字符串特定字符串上有多少个像素,即彩灯数量
#define PIN_PIXS 18//设置使18号引脚来控制灯环
#define BRIGHTNESS 50 // 设置亮度,从0到255取值
Adafruit_NeoPixel strip=Adafruit_NeoPixel(LED_COUNT,PIN_PIXS,NEO_GBR+NEO_KHZ800);//该函数用于实例化一个此类
//Adafruit_NeoPixel(LED_COUNT,PIN_PIXS,NEO_GBR+NEO_KHZ800);//该函数用于实例化一个此类,三个参数分别为灯环LED数,引脚号,800KHz比特流设定
int red =0;
int green =0;
int blue =0;
int rgb=255;
String glow_mode ="1";//发光模式
u8_t speed=50;
bool led_state=false;
unsigned long lastMillis = 0;
3.自定义RGB显示效果
这些显示效果均来自库Adafruit_NeoPixel,github有开源库和例程。
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
delay(wait);
}
}
void rainbow(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256; j++) {
for(i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i+j) & 255));
}
strip.show();
delay(wait);
}
}
void rainbowCycle(uint8_t wait) {
uint16_t i, j;
for(j=0; j<256*5; j++) {
// 5 cycles of all colors on wheel
for(i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
delay(wait);
}
}
4.wifi连接及提示函数
void connect()
{
Serial.print("check wifi connect......");
while (WiFi.status()!=WL_CONNECTED)//若没有连接成功
{
Serial.print(".");
delay(1000);
}
Serial.print("\nconnecting...");
if(mqtt.connect("", ACCESS_TOKEN.c_str(), PROJECT_KEY))//connect函数的三个参数为:id,username,password
//connect函数说明:连接mqtt服务,布尔型,判断是否连接成功
{
//subscribe函数的参数topic是主题,用于查看是否订阅成功,订阅主题只需要在设备mqtt成果连接云平台后执行一次即可
mqtt.subscribe("command/send/+");//这个主题是接收下发的命令
mqtt.subscribe("attributes/push");//这个主题是:当云平台下发属性给设备时,设备会通过以上订阅主题,收到json结构的消息
mqtt.subscribe("attributes/get/response/+");//这个主题是:接收属性获取的响应
}
Serial.print("\nconnecting successful!");
}
5.解析云平台的属性
void parse_cloud_attributes(JsonObject obj){
if(obj.containsKey("red")){
//obj调用其方法containskey,判断是否包含指定的键值red
red = obj["red"];
}
if(obj.containsKey("green")){
green = obj["green"];
}
if(obj.containsKey("blue")){
blue = obj["blue"];
}
if(obj.containsKey("rgb_number")){
rgb = obj["rgb_number"];
}
if(obj.containsKey("glow_mode")){
const char *mode =obj["glow_mode"];
glow_mode=String(mode);
}
if(obj.containsKey("speed")){
speed = obj["speed"];
speed=100-speed;
}
if(obj.containsKey("led_state")){
led_state = obj["led_state"];
}
}
6.回调函数
void callback(char *topic,byte *payload,unsigned int length){
unsigned int termination_pos;//定义无符号整型变量t_p
if(strlen(topic)+length+9>=mqtt.getBufferSize()){
//strlen计算第一个字符到\0之间字符个数,getbuffersize函数获取页面缓冲区的大小,默认8KB大小
termination_pos = length-1;
}
else
termination_pos = length;
payload[termination_pos] = '\0';
String payload_str((char*)payload);
String topic_str(topic);
Serial.printf("%s -> %s\n",topic,payload_str.c_str());
//调用
DynamicJsonDocument doc(512);
DeserializationError error = deserializeJson(doc,payload_str);
if(error)
{
Serial.printf("deserialize error : %s\n",error.f_str());
return;
}
JsonObject obj = doc.as<JsonObject>();
if(String(topic)=="attributes/get/response/1000"){
//如果接收到了属性获取的响应
if(obj.containsKey("result")&&obj.containsKey("attributes")){
JsonObject attributes = doc["attributes"];
parse_cloud_attributes(attributes);
}
}
if(String(topic)=="attributes/push"){
//如果接收下发的属性
parse_cloud_attributes(obj);
}
}
7.setup函数
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
WiFi.begin(ssid,password);
connect();
delay(1000);
mqtt.publish("attributes/get/1000","{}");//publish发布对应主题消息
strip.begin();//配置ws2812的输入引脚
strip.show(); // Turn OFF all pixels ASAP
strip.setBrightness(BRIGHTNESS);//亮度约为五分之一
// client.enableDebuggingMessages(); // 允许 SDK 的日志输出
// client.setWifiCredentials(ssid, password); // 连接 WiFi AP
//dht11.begin();//初始化dht11
}
8.loop函数
void loop() {
// put your main code here, to run repeatedly:
if(led_state)
{
if(glow_mode=="1"){
colorWipe(rgb,speed);}
else if (glow_mode=="2")
{
theaterChase(rgb,speed);
}
else if (glow_mode=="3")
{
rainbow(5);
}
else if (glow_mode=="4")
{
rainbowCycle(2);
}
else if(glow_mode=="5"){
theaterChaseRainbow(1);
}
}
else{
//由于led_state初值是false,则一开始执行该语句,显示流水LED灯
for(uint16_t i=0;i<strip.numPixels();i++)
{
strip.setPixelColor(i,0);
strip.show();
}
}
if(!mqtt.connected())//若mqtt没有连接成功,则重复进行连接
{
connect();
}
mqtt.loop();//处理消息以及保持心跳
}
四、效果展示
对于thingscloud的相关主题订阅、下发以及数据的传输等我还没有掌握,目前先记录下实践效果,等后续进一步理解esp32与mqtt协议后,将对以上代码中关于解析json函数与回调函数做进一步说明。