一.硬件构成
arduino uno作为传感器节点微处理器,mq-2烟雾传感器,dh温湿度传感器,火焰传感器,舵机,ph监测传感器,esp8266通信模块,继电器,L298N等。(这里面接多少传感器就看怎么接,uno接口如果不过用arduino mega也行代码都一样)
二.物联网平台
使用易联智能物联网平台 (easyiothings.com),这个平台是免费的使用esp8266或esp32搞物联网小项目还是比较方便的。
三.代码烧录
下载arduino ide配置好相关库及环境,esp8266建议使用arduino直接编译烧录,arduino uno建议使用vscode方便代码编写,并可以配置vscode中arduino开发环境烧录单片机
esp8266烧录的代码
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#define BUILTIN_LED 2
char P_NAME[] = "pangchao"; //设置热点名称,根据自己的热点名称修改
char P_PSWD[] = "qq8164731"; //设置热点密码,根据自己的密码修改
char sub[] = "Sub/101099"; //设置设备SUB名称
char pub[] = "Pub/101099"; //设置设备PUB名称
const char *ssid = P_NAME;
const char *password = P_PSWD;
const char *mqtt_server = "easyiothings.com";
String reStr;
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;
void setup_wifi()
{
delay(10);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
}
randomSeed(micros());
}
void callback(char *topic, byte *payload, unsigned int length)
{
for (int i = 0; i < length; i++)
{
Serial.print((char)payload[i]);
}
Serial.println();
}
void reconnect()
{
while (!client.connected())
{
String clientId = "ESP8266Client";
clientId += String(random(0xffff), HEX);
if (client.connect(clientId.c_str()))
{
client.publish(pub, "{\"State\":\"OnLine\"}");
client.subscribe(sub);
}
else
{
Serial.print(client.state());
delay(5000);
}
}
}
void setup()
{
pinMode(BUILTIN_LED, OUTPUT);
Serial.begin(9600);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
digitalWrite(BUILTIN_LED, HIGH);
}
void loop()
{
if (!client.connected())
{
reconnect();
}
client.loop();
if (Serial.available() > 0)
{
reStr = Serial.readStringUntil('\n');
//检测json数据是否完整
int jsonBeginAt = reStr.indexOf("{");
int jsonEndAt = reStr.lastIndexOf("}");
if (jsonBeginAt != -1 && jsonEndAt != -1)
{
reStr = reStr.substring(jsonBeginAt, jsonEndAt + 1);
int str_len = reStr.length() + 1;
char char_array[str_len];
reStr.toCharArray(char_array, str_len);
client.publish(pub, char_array);
}
}
}
arduino烧录的代码
要增减功能直接在代码框架里删改就行了
#include <ArduinoJson.h> //导入JSON库,用来封装发送数据的格式
#include <Servo.h> //控制舵机的库
#include <Arduino.h>
#include <DHT.h> //导入温湿度传感器库
StaticJsonDocument<400> sendJson; // 创建JSON对象,用来存放发送数据
StaticJsonDocument<400> readJson; // 创建JSON对象,用来存放接收到的数据
unsigned long lastUpdateTime = 0; //记录上次上传数据时间
const unsigned long updateInterval = 4000; // 在这里设置数据发送至云平台的时间间隔,单位为毫秒
//定义传感器相关的引脚
#define FEED 9 //设定舵机的Arduino引脚为9
#define COPEN 10 //设定舵机的角度,投喂开启时舵机的角度
#define CCLOSE 100 //投喂关闭时舵机的角度
#define WATER 7 //设定LED灯引脚为7
#define Sensor_1 A0 //定义浊度传感器//
#define DHTPIN 11 //定义温湿度传感器引脚为10
#define DHTTYPE DHT11 //定义温湿度传感器型号为DHT11
#define SensorPin A1 //pH meter Analog output to Arduino Analog Input 1
#define Offset 6.677
#define samplingInterval 20
#define printInterval 800
#define ArrayLenth 40
int pHArray[ArrayLenth]; //Store the average value of the sensor feedback
int pHArrayIndex=0;
//定义相关的变量
long ID = 101099; // 定义设备ID号,替换成云平台生成的ID号
float temperature, humidity,smoke; // 定义温湿度变量
int sensorValue = analogRead(Sensor_1);//读取模拟口A0的数据并送给变量
float chaos = sensorValue * (5.0 / 1024.0); //将模拟读数从0-1023转换为电压0-5V
int waterState,feedState; // 定义灯光,窗户状态(0代表无或者关闭,1代表有或者打开)
DHT dht(DHTPIN, DHTTYPE); //创建dht对象,用于操作温湿度传感器
Servo feedServo; // 创建舵机对象,用来控制喂食的舵机
// Arduino的初始化函数,仅在通电时运行一次
void setup()
{
Serial.begin(9600); //初始化串口,用于和esp8266进行通信,完成数据的接收与上传
dht.begin(); //初始化温湿度传感器
feedServo.attach(FEED); //初始化9号引脚为舵机引脚
feedServo.write(CCLOSE);
pinMode(WATER, OUTPUT); //初始化LED灯引脚为输出模式
}
// Arduino的loop函数,当setup函数执行完毕后进入该函数并一直循环运行
void loop()
{
static float pHValue,voltage;
{
pHArray[pHArrayIndex++]=analogRead(SensorPin);
if(pHArrayIndex==ArrayLenth)pHArrayIndex=0;
voltage = avergearray(pHArray, ArrayLenth)*5.0/1024;
pHValue = -5.8887*voltage+Offset;
if(pHValue<=0.0){pHValue=0.0;}
if(pHValue>14.0){pHValue=14.0;}
}
// {
// Serial.print(" pH value: ");
// Serial.println(pHValue,2);
// }
// delay(1000);
sendJson["pHValue"] = pHValue;
}
double avergearray(int* arr, int number){
int i;
int max,min;
double avg;
long amount=0;
if(number<=0){
Serial.println("Error number for the array to avraging!/n");
return 0;
}
if(number<5){ //less than 5, calculated directly statistics
for(i=0;i<number;i++){
amount+=arr[i];
}
avg = amount/number;
return avg;
}else{
if(arr[0]<arr[1]){
min = arr[0];max=arr[1];
}
else{
min=arr[1];max=arr[0];
}
for(i=2;i<number;i++){
if(arr[i]<min){
amount+=min; //arr<min
min=arr[i];
}else {
if(arr[i]>max){
amount+=max; //arr>max
max=arr[i];
}else{
amount+=arr[i]; //min<=arr<=max
}
}//if
}//for
avg = (double)amount/(number-2);
}
// 该函数段可完成数据定时上报的功能,并且不会阻塞loop函数的运行
if (millis() - lastUpdateTime > updateInterval)
{
sendJsonData();
lastUpdateTime = millis();
}
// 当用户使用手机控制当前设备时ESP8266会通过串口向Arduino发送指令,该函数段可判断串口有没有接收到消息,并完成对用户消息的解析
while (Serial.available() > 0) { // 判断串口缓冲区是否有消息
String inputString = Serial.readStringUntil('\n'); //从串口缓冲区读入数据,并赋值给inputString变量(String变量为Arduino独有变量类型,可以简化字符串操作)
//检测json数据是否完整,若通过则进行下一步的处理
/*
云平台向硬件下发JSON的格式为 {"Light":"1"} 类型的字符串,通常叫键值对,C语言中叫做哈希表。
左边的"FAN"为我们在云平台中定义的标识符,右边为具体的指令
*/
int jsonBeginAt = inputString.indexOf("{");
int jsonEndAt = inputString.lastIndexOf("}");
if (jsonBeginAt != -1 && jsonEndAt != -1)
{
inputString = inputString.substring(jsonBeginAt, jsonEndAt + 1); //净化json数据
deserializeJson(readJson, inputString); //通过ArduinoJSON库将JSON字符串转换为方便操作的对象
// 判断接收的指令
if (readJson.containsKey("waterState")) //判断云平台下发的消息是否包含Light标识符,如果是则进行下一步处理
{
digitalWrite(WATER, (int)readJson["waterState"]); // 根据Light的值来控制小灯,0为关,1为开,由于是char类型,所以我们需要转换为int
delay(100);
waterState = digitalRead(WATER); // 及时更新小灯的状态信息,这样云平台才能知道是否控制成功
}
else if(readJson.containsKey("feedState")) // 若添加了多个功能,则使用else if隔开
{
//更新feedState的值
feedState = (int)readJson["feedState"];
}
delay(500);
sendJsonData(); //向云平台发送最新的信息
}
}
//判读feed的值是否为1,是则让舵机转到开启的角度,否则关闭
if(feedState){
feedServo.write(COPEN);
}
else{
feedServo.write(CCLOSE);
}
waterState = digitalRead(WATER);
temperature = dht.readTemperature();
humidity = dht.readHumidity();
}
//上传数值
void sendJsonData()
{
// 将数据添加到JSON对象中,左边为在云平台中定义的标识符,右边为变量
sendJson["chaos"] = chaos;
sendJson["Temperature"] = temperature;
sendJson["Humidity"] = humidity;
sendJson["waterState"] = waterState;
sendJson["feedState"] = feedState;
sendJson["ID"] = ID;
//将对象转换成字符串,并向ese8266发送消息
serializeJson(sendJson, Serial);
Serial.print("\n");
}
若有问题可联系作者qq:2917671185