系统物联网的方案及功能设计_物联网系统设计

const char* mqttPassword = “password”; // 服务端连接密码(需要修改)
const char* clientId = “UserName_1_id”; // 客户端id (需要修改)
const char* subTopic1 = “UserName/phone”; // 订阅主题(需要修改)
const char* subTopic2 = “UserName/web”; // 订阅主题(需要修改)
const char* pubTopic1 = “UserName/esp8266_1”; // 发布主题(需要修改)
const char* pubTopic2 = “UserName/esp8266_2”; // 发布主题(需要修改)
const char* pubTopic3 = “UserName/esp8266_3”; // 发布主题(需要修改)
const char* pubTopic4 = “UserName/esp8266_4”; // 发布主题(需要修改)
const char* willTopic = “UserName/led_yz”; // 遗嘱主题名称(需要修改)
// ****************************************************

//遗嘱相关信息
const char* willMsg = “esp8266 offline”; // 遗嘱主题信息
const int willQos = 0; // 遗嘱QoS
const int willRetain = false; // 遗嘱保留

const int subQoS = 1; // 客户端订阅主题时使用的QoS级别(截止2020-10-07,仅支持QoS = 1,不支持QoS = 2)
const bool cleanSession = false; // 清除会话(如QoS>0必须要设为false)

//*****************************************************
const char* host = “api.seniverse.com”; // 将要连接的服务器地址
const int httpPort = 80; // 将要连接的服务器端口

// 心知天气HTTP请求所需信息
String reqUserKey = ""; // 私钥
String reqLocation = “你的城市所在地”; // 城市
String reqUnit = “c”; // 摄氏/华氏
//
*****************************************

void setup(){
Serial.begin(115200);

//设置ESP8266工作模式为无线终端模式
WiFi.mode(WIFI_STA);

// 连接WiFi
connectWiFi();

// 设置MQTT服务器和端口号
mqttClient.setServer(mqttServer, 1883);
mqttClient.setCallback(receiveCallback);

// 连接MQTT服务器
connectMQTTserver();
}



> 
>         由于主函数中涵盖了自适应天气运行部分的代码,因此具体代码放在文末与自适应天气部分一起放上。
> 
> 
> 


## **1.4  自适应天气运行控制策略**


### 1.4.1  自适应天气运行的需求


        **为实现系统避风、避雪,保护支架、组件,减少装置的受损概率,延长支架、组件的使用寿命,延长发电寿命,增加发电收益。**本系统针对天气对光伏发电的影响为跟踪装置设计了自适应天气运行,即适应天气的变化使跟踪装置作出相应的调整,以最大化地提高发电效益,力求将天气对光伏发电所带来的影响降到最低。


### 1.4.2  自适应天气运行的设计原理


        ①本系统采用的是混合跟踪方式,光电跟踪方式在尤其是在阴雨或者多云天气时,很难与太阳光线对正,有些情况下还会出现误跟踪、丢跟踪和往反跟踪等现象,没办法保证跟踪精度;而视日轨迹跟踪方式的主要缺点在于运行时会产生累积误差,该误差不能自行消除,往往需要人为定期调整跟踪累积误差。


        综合分析考虑决定,在晴朗天气下,系统将采用光电跟踪方式;而在阴天或多云天气时,系统将采用视日轨迹跟踪方式。


        ②本系统中配置风速风向监测仪用于监测光伏支架安装环境中风速的大小、风的方向(当接收到与风相关的天气信息方启动风速风向检测仪,以降低系统整体能耗);如果测量的风速大于设定值时,MCU即驱动执行机构,使太阳能电池板的侧面迎风,正面避开风的正面,减少迎风面积,从而减少受风力,降低受损概率;同时可以驱动俯仰角转动,使得俯仰角变小,张力变小,机械受外力不易损坏。


        ③本系统配置雨滴传感器用于检测雨雪量(当接收到与雨雪相关的天气信息方启动雨滴传感器,以降低系统整体能耗);如果雨雪量大于设定值时,容易造成组件或支架受雨雪压力受损,MCU即可驱动执行机构转动,使得太阳能电池板正面和地面垂直或接近垂直,雨雪就不容易积压到太阳能电池板表面上,严寒地区安装的组件表面也不易结冰,减少雨雪对组件的腐蚀和压力;当雨量小于设定值时,系统将采用视日轨迹跟踪方式,此时较小的雨量并不容易对组件造成损害,相反,还可利用雨水冲刷掉光伏组件表面的污垢和灰尘,从而增加光照强度,提高光伏发电系统的输出功率。


### 1.4.3  天气信息平台的选择


        互联网上有很多天气信息平台,心知天气是信息最准确,服务最稳定的平台。更重要的是,心知天气所提供的基础服务是完全免费的,其免费的天气信息就包含3天的天气预报信息,实时天气以及生活指数。


![](https://img-blog.csdnimg.cn/773fa25059fd4e63bddbc9ba632e0cee.png)


### 1.3.4  自适应天气运行的设计方案


        ①对WiFi模块进行初始化设置,设置成STA模式,WiFi模块通过路由器/手机热点可连接互联网;**建立“心知天气”API当前天气请求资源地址**,通过互联网向**“心知天气”**服务器发送HTTP请求,并获取服务器返回的天气信息,从服务器响应中**解析出天气代码**(如图2所示)。


        ②设定特殊天气的转换程序,即将所需响应的天气情况所对应的天气代码转换为控制系统可识别的字符。此时WiFi模块同时作为上位机,与单片机进行串行通信,将可识别的天气字符传送给单片机。




![](https://img-blog.csdnimg.cn/acb68d3655314a3e82f3294f3269303b.png)

 图2    部分天气现象代码说明 
 



        ③对单片机进行初始化设置,设计**接收到不同的天气字符即运行不同的舵机驱动代码**。当单片机接收到实时的天气信息后,配合雨滴传感器、风速风向传感器来确认天气信息属实后,才会驱动跟踪装置执行相应的动作。


        目前仅对四种天气情况进行了设置:


        晴天时,单片机将运行光电跟踪模式;


        阴天或多云时,单片机将运行视日轨迹跟踪模式,确保光伏板始终朝向太阳,以提供最佳的能量收集效果,最大限度地提高能量输出效率;


        雨天时,单片机将中断当前所执行的模式,转而驱动控制俯仰角的舵机将光伏电池板置于倾斜45°的状态,令雨水冲刷板面,以清理尘土、落叶等遮挡物, 从而减弱热斑效应,延长系统寿命。


        雪天时,单片机将中断当前所执行的模式,转而驱动控制俯仰角的舵机将光伏电池板置于垂直地面的状态,系统能够自动调整光伏板角度,使其正面和地面垂直或接近垂直,减少积雪对 组件的腐蚀和压力。


        自适应天气运行控制策略的流程图如图3所示。




![](https://img-blog.csdnimg.cn/1f4da5c20d2f4632af2b395f089bd72c.png)

 图3    自适应天气运行控制策略的程序流程图 
 


         补充:图中在执行雨雪天气时,漏了得先经过雨滴传感器的数据辅助判断当前天气情况是否属实这一步。


### 1.4.5  代码实现


####         1、使用心知天气数据服务的准备工作


        ①注册心知天气账户


        打开心知天气网页:[www.seniverse.com]( )


![](https://img-blog.csdnimg.cn/372a2b894d45401a8d3f20cd6f46f2ac.png)


         ②申请免费天气数据API服务


        完成注册后进行登录,然后从首页进入控制台页面(如下图所示)


![](https://img-blog.csdnimg.cn/2d019ea1dde84ff5a5098a70263d23ec.png)


         申请天气数据API免费版


![](https://img-blog.csdnimg.cn/62abcf11ad1948f78a09a3e751927455.png)


         申请成功后可以在控制台中看到(如下图所示)


![](https://img-blog.csdnimg.cn/93a3324972c444e9b1f6fe38109cf874.png)


         点击该服务链接,进入天气数据API免费服务页面


        ③获取用户私钥、 


![](https://img-blog.csdnimg.cn/b8be6b8f57d846d991c20aae14d99ac1.png)


        点击私钥旁边的 闭合上的眼睛 即可查看自己的私钥信息 


####         2、ESP8266获取并解析心知天气数据


        这里可以先使用“太极创客团队”的代码来实现 获取实时天气信息(温度、天气)



> 
>         要实现本系统的自适应天气运行功能,照搬太极创客的代码是行不通的。
> 
> 
> 



#include <ArduinoJson.h>
#include <ESP8266WiFi.h>

const char* ssid = “taichimaker”; // 连接WiFi名(此处使用taichi-maker为示例)
// 请将您需要连接的WiFi名填入引号中
const char* password = “12345678”; // 连接WiFi密码(此处使用12345678为示例)
// 请将您需要连接的WiFi密码填入引号中

const char* host = “api.seniverse.com”; // 将要连接的服务器地址
const int httpPort = 80; // 将要连接的服务器端口

// 心知天气HTTP请求所需信息
String reqUserKey = “XXXXXXXXXXXXXXXXX”; // 私钥
String reqLocation = “Beijing”; // 城市
String reqUnit = “c”; // 摄氏/华氏

void setup(){
Serial.begin(9600);
Serial.println(“”);

// 连接WiFi
connectWiFi();
}

void loop(){
// 建立心知天气API当前天气请求资源地址
String reqRes = “/v3/weather/now.json?key=” + reqUserKey +
+ “&location=” + reqLocation +
“&language=en&unit=” +reqUnit;

// 向心知天气服务器服务器请求信息并对信息进行解析
httpRequest(reqRes);
delay(3000);
}

// 向心知天气服务器服务器请求信息并对信息进行解析
void httpRequest(String reqRes){
WiFiClient client;

// 建立http请求信息
String httpRequest = String(“GET “) + reqRes + " HTTP/1.1\r\n” +
“Host: " + host + “\r\n” +
“Connection: close\r\n\r\n”;
Serial.println(””);
Serial.print("Connecting to "); Serial.print(host);

// 尝试连接服务器
if (client.connect(host, 80)){
Serial.println(" Success!");

// 向服务器发送http请求信息
client.print(httpRequest);
Serial.println("Sending request: ");
Serial.println(httpRequest);  

// 获取并显示服务器响应状态行 
String status_response = client.readStringUntil('\n');
Serial.print("status_response: ");
Serial.println(status_response);

// 使用find跳过HTTP响应头
if (client.find("\r\n\r\n")) {
  Serial.println("Found Header End. Start Parsing.");
}

// 利用ArduinoJson库解析心知天气响应信息
parseInfo(client); 

} else {
Serial.println(" connection failed!");
}
//断开客户端与服务器连接工作
client.stop();
}

// 连接WiFi
void connectWiFi(){
WiFi.begin(ssid, password); // 启动网络连接
Serial.print(“Connecting to “); // 串口监视器输出网络连接信息
Serial.print(ssid); Serial.println(” …”); // 告知用户NodeMCU正在尝试WiFi连接

int i = 0; // 这一段程序语句用于检查WiFi是否连接成功
while (WiFi.status() != WL_CONNECTED) { // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。
delay(1000); // 如果WiFi连接成功则返回值为WL_CONNECTED
Serial.print(i++); Serial.print(’ '); // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值
} // 同时NodeMCU将通过串口监视器输出连接时长读秒。
// 这个读秒是通过变量i每隔一秒自加1来实现的。
Serial.println(“”); // WiFi连接成功后
Serial.println(“Connection established!”); // NodeMCU将通过串口监视器输出"连接成功"信息。
Serial.print("IP address: "); // 同时还将输出NodeMCU的IP地址。这一功能是通过调用
Serial.println(WiFi.localIP()); // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。
}

// 利用ArduinoJson库解析心知天气响应信息
void parseInfo(WiFiClient client){
const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6) + 230;
DynamicJsonDocument doc(capacity);

deserializeJson(doc, client);

JsonObject results_0 = doc[“results”][0];

JsonObject results_0_now = results_0[“now”];
const char* results_0_now_text = results_0_now[“text”]; // “Sunny”
const char* results_0_now_code = results_0_now[“code”]; // “0”
const char* results_0_now_temperature = results_0_now[“temperature”]; // “32”

const char* results_0_last_update = results_0[“last_update”]; // “2020-06-02T14:40:00+08:00”

// 通过串口监视器显示以上信息
String results_0_now_text_str = results_0_now[“text”].as();
int results_0_now_code_int = results_0_now[“code”].as();
int results_0_now_temperature_int = results_0_now[“temperature”].as();

String results_0_last_update_str = results_0[“last_update”].as();

Serial.println(F(“Weahter Now=”));
Serial.print(F("Weather Now: “));
Serial.print(results_0_now_text_str);
Serial.print(F(” "));
Serial.println(results_0_now_code_int);
Serial.print(F("Temperature: "));
Serial.println(results_0_now_temperature_int);
Serial.print(F(“Last Update: “));
Serial.println(results_0_last_update_str);
Serial.println(F(”========================”));
}


####         3、自适应天气运行+远程监控代码


         代码后的注释能解释清楚每一句代码的作用。



void loop(){
//*****************************************************
// 建立心知天气API当前天气请求资源地址
String reqRes = “/v3/weather/now.json?key=” + reqUserKey +
+ “&location=” + reqLocation +
“&language=en&unit=” +reqUnit;

// 向心知天气服务器服务器请求信息并对信息进行解析
httpRequest(reqRes);
//*****************************************************

//*****************************************************
// 如果开发板未能成功连接服务器,则尝试连接服务器
if (!mqttClient.connected()) {
connectMQTTserver();
}

// 处理信息以及心跳
mqttClient.loop();
//*****************************************************
char a[20] = “”; //定义字符数组,接受来自串口的数据
char b;
int i = 0;
while (Serial.available()) //当发现缓存中有数据时,将数据送至字符数组a中
{
a[i] = Serial.read();
i++;
}

b = a[0];
if (b == ‘1’){
mqttClient.publish(pubTopic4, “YES”); //向Web端发送雨滴传感器的状态,有雨或无雨
Serial.print(‘5’);
}else{
mqttClient.publish(pubTopic4, “NO”);
}

if(Serial.available() == 0){
mqttClient.publish(pubTopic3, a); //向Web端和移动端发送跟踪装置的俯仰角度和水平角度
}

}

// 向心知天气服务器服务器请求信息并对信息进行解析
void httpRequest(String reqRes){
WiFiClient client;

// 建立http请求信息
String httpRequest = String("GET “) + reqRes + " HTTP/1.1\r\n” +
"Host: " + host + “\r\n” +
“Connection: close\r\n\r\n”;

// 尝试连接服务器
if (client.connect(host, 80)){

// 向服务器发送http请求信息
client.print(httpRequest);

// 获取并显示服务器响应状态行 
String status_response = client.readStringUntil('\n');

// 使用find跳过HTTP响应头
if (client.find("\r\n\r\n")) {

// Serial.println(“Found Header End. Start Parsing.”);
}

// 利用ArduinoJson库解析心知天气响应信息
parseInfo(client);
delay(1000);

} else {
// Serial.println(" connection failed!");
}
//断开客户端与服务器连接工作
client.stop();
}

// 连接WiFi
void connectWiFi(){
WiFi.begin(ssid, password); // 启动网络连接

int i = 0; // 这一段程序语句用于检查WiFi是否连接成功
while (WiFi.status() != WL_CONNECTED) { // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。
delay(1000);

}

}

// 利用ArduinoJson库解析心知天气响应信息
void parseInfo(WiFiClient client){
const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(6) + 230;
DynamicJsonDocument doc(capacity);

deserializeJson(doc, client);

JsonObject results_0 = doc[“results”][0];

JsonObject results_0_now = results_0[“now”];
const char* results_0_now_text = results_0_now[“text”]; // “Sunny”
const char* results_0_now_code = results_0_now[“code”]; // “0”
const char* results_0_now_temperature = results_0_now[“temperature”]; // “32”

const char* results_0_last_update = results_0[“last_update”]; // “2020-06-02T14:40:00+08:00”

String results_0_now_text_str = results_0_now[“text”].as();
int results_0_now_code_int = results_0_now[“code”].as();
int results_0_now_temperature_int = results_0_now[“temperature”].as();

String results_0_last_update_str = results_0[“last_update”].as();

mqttClient.publish(pubTopic2, results_0_now_text);//将天气情况发送到Web端,使其可显示当前天气情况

//转换成单片机可识别的天气状态字符,然后通过串口传给单片机
if(results_0_now_code_int == 24 || results_0_now_code_int == 25)//雪天
{
Serial.print(‘3’);
}
if(results_0_now_code_int == 13 || results_0_now_code_int == 14 || results_0_now_code_int == 15 || results_0_now_code_int == 16 || results_0_now_code_int == 17 || results_0_now_code_int == 18)//雨天
{
Serial.print(‘5’);
}
if(results_0_now_code_int == 0)//晴天
{
Serial.print(‘0’);
}
if(results_0_now_code_int == 4 || results_0_now_code_int == 5 || results_0_now_code_int == 6 || results_0_now_code_int == 7 || results_0_now_code_int == 8 || results_0_now_code_int == 9)//阴天
{
Serial.print(‘1’);
}

//将天气情况发送到移动端,使其可显示当前天气情况
char* pubMessage;
pubMessage = “天气:”;
if(mqttClient.publish(pubTopic1, results_0_now_text)){
mqttClient.publish(pubTopic1, pubMessage);
}
}

// 连接MQTT服务器并订阅信息
void connectMQTTserver(){
// 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)

/* 连接MQTT服务器
boolean connect(const char* id, const char* user,
const char* pass, const char* willTopic,
uint8_t willQos, boolean willRetain,
const char* willMessage, boolean cleanSession);
若让设备在离线时仍然能够让qos1工作,则connect时的cleanSession需要设置为false
*/
if (mqttClient.connect(clientId, mqttUserName,
mqttPassword, willTopic,
willQos, willRetain, willMsg, cleanSession)) {

subscribeTopic(); // 订阅指定主题

} else {
delay(5000);
}
}

// 收到信息后的回调函数。
void receiveCallback(char* topic, byte* payload, unsigned int length) {

for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]); // 订阅了Web端和移动端发布的主题,当收到这两端发布信息后,便会通过串口传给单片机
}

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

dp5Fhz0-1715796924360)]

[外链图片转存中…(img-YJyMNzgc-1715796924361)]

[外链图片转存中…(img-wxzdn5Z9-1715796924362)]

[外链图片转存中…(img-DMuKNHGh-1715796924362)]

[外链图片转存中…(img-uQwQrzDU-1715796924363)]

[外链图片转存中…(img-26qmfYMX-1715796924364)]

[外链图片转存中…(img-3tkFhLyF-1715796924365)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新!!

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值