一、项目背景

随着智慧城市建设的推进,社区管理也逐渐向智能化、自动化方向发展。本项目旨在通过物联网技术,构建一个集气象监测路灯智能控制于一体的系统,实现对社区环境的实时监测与智能调控,提升居民生活品质,同时达到节能减排的目的。

二、系统构成

系统由以下四个核心部分组成:

  1. 物联网小型气象站:采集温度、湿度、光照、风速、风向、降雨量、气压等数据。

  2. 物联网云服务器:采用华为云IoT平台,接收并处理气象数据,实现数据存储与设备联动。

  3. 微信小程序控制平台:提供可视化操作界面,支持手动控制与日志查看。

  4. 物联网可控路灯:通过4G网络接收云平台指令,实现远程开关控制。

三、技术方案

3.1 产品分析

系统通过传感器实时采集环境数据,上传至云平台,平台根据预设逻辑自动控制路灯开关,同时支持管理员通过微信小程序进行手动干预。

3.2 物联网四层架构

应用层

智慧社区气象监测与路灯智能控制系统

微信小程序

平台层

                                      IoT物联网华为云平台

网络层

                                                4G网络

感知层

检测设备(传感器)

控制设备

光线强度

空气温度

空气湿度

风速

风向

降雨量

气压

开关

3.3 功能设计

系统功能流程如下图所示:

  1. 数据采集:各类传感器周期性采集环境数据。

  2. 云平台处理:华为云平台接收数据并进行分析存储。

  3. 设备联动:根据环境数据自动控制路灯开关。

  4. 小程序控制:管理员可通过小程序手动控制路灯,查看操作日志。

四、系统可行性分析

  • 技术选型:华为云IoT平台 + MQTT协议,成熟稳定。

  • 网络连接:4G网络覆盖广,支持远程可靠通信。

  • 数据安全:SSL/TLS加密传输,设备身份认证。

  • 系统稳定性:云平台高可用,设备经严格测试,支持日志监控。

五、华为云平台配置

5.1 MQTT物模型定义

定义了两个服务:

  • BasicData:包含光照、温湿度、风速等属性。

  • LightControl:包含路灯开关命令。

物模型属性表如下:

序号

服务 ID

描述

属性名称

数据类型

访问方式

例子

1

BasicData

光线强度

luminance

int(整型)

可读,可写

30

2

BasicData

空气温度

temperature

decimal(小数)

可读,可写

27.3

3

BasicData

空气湿度

AirHumidity

decimal(小数)

可读,可写

80

4

BasicData

风速

WindSpeed

decimal(小数)

可读,可写

4

5

BasicData

风向

WindDirection

string(字符串)

可读,可写

South west Wind

6

BasicData

降雨量

Rainfall

decimal(小数)

可读,可写

906

7

BasicData

气压

AirPressure

int(整型)

可读,可写

814

8

BasicData

开关

button

enum(枚举)

可读,可写

0

表 属性表

序号

服务 ID

描述

命令名称

下发参数名称

数据类型

例子

1

LightControl

路灯开关

Switch

value

string(字符串)

ON, OFF

表 命令表 

注册物联网小型气象站、物联网可控路灯设备,设备标识码为本人学号,通过 MQTT 调试软件,对物联网小型气象站、物联网可控路灯进行数据上报(按照题目二中例子参数),附设备信息(截图)、MQTT 连接参数(文本)、阿里云物模型数据(截图)、指令(文本)、MQTT 调试软件连接成功(截图)。

5.2 设备注册与连接

通过MQTT调试软件连接华为云平台,成功上报数据并接收指令。

设备信息截图:

5.3 连接参数示例

clientId

676bf797ef99673c8ad94bd6_202202090134_0_0_2024122609

username

676bf797ef99673c8ad94bd6_202202090134

password

e5f92c857eea639b33162c84914f4bbf67913904ba712f32d01483491cdcedd2

hostname

3b1dbbb468.st1.iotda-device.cn-north-4.myhuaweicloud.com

port

8883

5.4 数据上报指令示例

{
    "services": [{
            "service_id": "BasicData",
            "properties": {
                "luminance": 30,
       		"temperature": 27.3,
      		"AirHumidity": 80,
		"WindSpeed": 4,
        	"WindDirection":"South west Wind",
        	"Rainfall": 906,
        	"AirPressure": 814,
		"button": 1
        }
      }
   ]
}

5.5 MQTT调试软件连接成功截图

六、云平台联动控制

当出现大雾(湿度值>90%),天黑(光线强度<50Lux),需要开启路灯。当天亮(光线强度>150Lux),需要关闭路灯。请根据该联动控制逻辑,对阿里云 IoT 平台联动进行设置,并进行测试,附联动设置(截图)及三种状态测试上报数据。

设置设备联动规则:

  • 开启路灯:湿度 > 90% 且光照 < 50 Lux

  • 关闭路灯:光照 > 150 Lux

6.1 命令下发配置

6.2 设备联动配置




6.3 开启路灯测试

当出现大雾(湿度值>90%),天黑(光线强度<50Lux)

上报数据模拟大雾天黑环境:

{
    "services": [{
            "service_id": "BasicData",
            "properties": {
                "luminance": 48,
       		"temperature": 27.3,
      		"AirHumidity": 93,
		"WindSpeed": 4,
        	"WindDirection":"South west Wind",
        	"Rainfall": 906,
        	"AirPressure": 814
        }
      }
   ]
}


6.4 关闭路灯测试

当天亮(光线强度>150Lux)

上报数据模拟天亮环境:

{
    "services": [{
            "service_id": "BasicData",
            "properties": {
                "luminance": 152,
       		"temperature": 27.3,
      		"AirHumidity": 80,
		"WindSpeed": 4,
        	"WindDirection":"South west Wind",
        	"Rainfall": 906,
        	"AirPressure": 814
        }
      }
   ]
}


七、微信小程序开发

小程序包含四个页面:

7.1 页面设计

7.1.1 "连接到平台"页面

var app = getApp();
var self;
var mqtt = require('../../js/mqtt.js');
var CryptoJS = require('../../js/hmac-sha256.js');

Page({

  /**
   * 页面的初始数据
   */
  data: {
      host: '3b1dbbb468.st1.iotda-device.cn-north-4.myhuaweicloud.com',
      deviceId:'676bf797ef99673c8ad94bd6_202202090134',
      password:'95e201b217caed1468b7b4f2849b9af8',
      log:''
  },

  getHost(e) {
    this.setData({
      host: e.detail.value
    })
  },

  getDeviceId(e) {
    this.setData({
      deviceId: e.detail.value
    })
  },

  getPassword(e) {
    this.setData({
      password: e.detail.value
    })
  },

//事件处理函数
connect: function (e) {
  self = this;
  var serverUrl = 'wxs://3b1dbbb468.st1.iotda-device.cn-north-4.myhuaweicloud.com/mqtt'; //IoT平台mqtt对接地址
  var deviceId = '676bf797ef99673c8ad94bd6_202202090134'; //请填写在平台注册的设备ID
  var secret = '95e201b217caed1468b7b4f2849b9af8'; //请填写在平台注册的设备密钥
  
  //退避重连参数
  var minBackoff = 1000;
  var maxBackoff = 30 * 1000;
  var defaultBackoff = 1000;
  var retryTimes = 0;
  
  //连接参数设置
  var timestamp = dateFormat('YYYYmmddHH', new Date())
  const options = {
    username: deviceId,
    password: CryptoJS.HmacSHA256(secret, timestamp).toString(),
    clientId: getClientId(deviceId),
    keepalive: 120, //120s
    clean: true, //cleanSession不保持持久会话
    reconnectPeriod: 0, 
    connectTimeout: 1000,
    protocolVersion: 4 //MQTT v3.1.1
  }

  startConnect();
  
  function startConnect() {
    var client = mqtt.connect(serverUrl, options);
    app.globalData.client = client;
    app.globalData.deviceId = deviceId;
    client.on('connect', () => {
        log('mqttOverWebsocket onConnect');
      });

    client.on('error', (e) => {
        log('mqtt error: ' + e);
        reconnect();
      });

    client.on('close', () => {
        log('mqtt server is disconnected');
        reconnect();
      });

    client.on('offline', () => {
        log('mqtt client is offline');
        reconnect();
      });
  }

  function reconnect() {
      log("reconnect is starting");
      //退避重连
      let lowBound = Number(defaultBackoff)*Number(0.8);
      let highBound = Number(defaultBackoff)*Number(1.2);
      let randomBackOff = parseInt(Math.random()*(highBound-lowBound+1),10);
      let backOffWithJitter = (Math.pow(2.0, retryTimes)) * (randomBackOff + lowBound);
      let waitTImeUtilNextRetry = (minBackoff + backOffWithJitter) > maxBackoff ? maxBackoff : (minBackoff + backOffWithJitter);
      log("next retry time: " + waitTImeUtilNextRetry);
      setTimeout(()=> { 
        startConnect();
      }, waitTImeUtilNextRetry);
      retryTimes++;
  }

  function getClientId(deviceId) {
      return deviceId + '_0_0_' + timestamp;
  }

  function dateFormat(fmt, date) {
      let ret;
      const opt = {
          'Y+': date.getFullYear().toString(), // 年
          'm+': (date.getMonth() + 1).toString(), // 月
          'd+': date.getDate().toString(), // 日
          'H+': date.getHours().toString(), // 时
          'M+': date.getMinutes().toString(), // 分
          'S+': date.getSeconds().toString(), // 秒
          // 有其他格式化字符需求可以继续添加,必须转化成字符串
      };
      for (let k in opt) {
          ret = new RegExp('(' + k + ')').exec(fmt);
          if (ret) {
              fmt = fmt.replace(
                  ret[1],
                  ret[1].length === 1
                      ? opt[k]
                      : opt[k].padStart(ret[1].length, '0')
              );
          }
      }
      return fmt;
  }

  function log(msg) {
      console.log(new Date() + ' - ' + msg);
      //this.data.password
      self.data.log = self.data.log + new Date() + ' - ' + msg + '\r\n';
      self.setData({
        log: self.data.log
      })
  }
  
}

})
7.1.2 "上报数据"页面

// miniprogram/pages/userAuth.js
var app = getApp();
var self;
var mqtt = require('../../js/mqtt.js');

Page({
    /**
     * 页面的初始数据
     */
    data: {
        topic: '',
        payload: '',
        log: ''
    },

    onLoad: function (options) {
        this.setData({
            topic: '$oc/devices/676bf797ef99673c8ad94bd6_202202090134/sys/properties/report',
            payload: '{"services": [{ "service_id": "BasicData", "properties": {"button": 0}}]}'
        });
    },

    getTopic(e) {
        this.setData({
            topic: e.detail.value
        })
    },

    getPayload(e) {
        this.setData({
            payload: e.detail.value
        })
    },

    //事件处理函数
    reportData: function (e) {
        const client = app.globalData.client;
        if (client == null || client.connected == false) {
            this.log('device is not connect to platform');
            return;
        }
        this.log('topic:' + this.data.topic);
        client.publish(this.data.topic, this.data.payload);
        this.log('publish message successful');
    },

    log: function (msg) {
        console.log(new Date() +' -'+ msg);
        this.data.log = this.data.log + new Date() +' -'+ msg + '\r\n';
        this.setData({
            log: this.data.log
        });
    }
});
7.1.3 "订阅topic"页面

// miniprogram/pages/userAuth.js
var app = getApp();
var mqtt = require('../../js/mqtt.js');

Page({
    /**
     * 页面的初始数据
     */
    data: {
        topic: '',
        log: ''
    },

    onLoad: function (options) {
        var self = this;
        self.setData({
            topic: '$oc/devices/676bf797ef99673c8ad94bd6_202202090134/commands/#'
        });
    },

    getTopic(e) {
        this.setData({
            topic: e.detail.value
        })
    },

    //事件处理函数
    subscribe: function (e) {
        self = this;
        const client = app.globalData.client;
        console.log(app.globalData.deviceId);
        if (client == null || client.connected == false) {
            log('device is not connect to platform');
            return;
        }
        log('subscribe topic:' + self.data.topic);
        client.subscribe(self.data.topic, {qos: 1}, function (err, granted) {
            if (!err) {
                log('subscribe message successful');
            }
        });

        client.on('message', (topic, message, packet) => {
            log('receive message topic:' + topic);
            log('receive message content:' + message.toString());
            const messageData = JSON.parse(message.toString());
            // 根据消息中的操作类型处理响应
            if (messageData.operation === 'open') {
                sendResponse(topic.split("=")[1], 'open');
            } else if (messageData.operation === 'close') {
                sendResponse(topic.split("=")[1], 'close');
            }
        });

        function sendResponse(requestId, operation) {
            let responseReqJson;
            if (operation === 'open') {
                responseReqJson = {
                    result_code: 0,
                    response_name: 'COMMAND_RESPONSE',
                    paras: {result: 'success', action: 'open'}
                };
            } else if (operation === 'close') {
                responseReqJson = {
                    result_code: 0,
                    response_name: 'COMMAND_RESPONSE',
                    paras: {result: 'success', action: 'close'}
                };
            }
            let responseReq = JSON.stringify(responseReqJson);
            log('receive message topic:' + getResponseTopic(requestId));
            log('receive message content:' + responseReq);
            client.publish(getResponseTopic(requestId), responseReq);
        }

        function getResponseTopic(requestId) {
            return (
                '$oc/devices/' +
                app.globalData.deviceId +
                '/sys/commands/response/request_id=' +
                requestId
            );
        }

        function log(msg) {
            console.log(new Date() + ' - ' + msg);
            self.data.log = self.data.log + new Date() + ' - ' + msg + '\r\n';
            self.setData({
                log: self.data.log
            });
        }
    }
});
7.1.4 "控制"页面

// pages/control/control.js
var app = getApp();

Page({
  /**
   * 页面的初始数据
   */
  data: {
    topic: '',
    payload: '',
    log: ''
  },

  onLoad: function (options) {
    this.setData({
      topic: '$oc/devices/' + app.globalData.deviceId + '/sys/properties/report'
    });
  },

  openStreetLight: function () {
    const client = app.globalData.client;
    if (client == null || client.connected == false) {
      this.log('device is not connect to platform');
      return;
    }
    const payload = '{"services": [{"service_id": "BasicData", "properties": {"button": 0}}]}';
    this.log('topic: ' + this.data.topic);
    client.publish(this.data.topic, payload);
    this.log('publish message successful: ' + payload);
  },

  turnOffStreetLight: function () {
    const client = app.globalData.client;
    if (client == null || client.connected == false) {
      this.log('device is not connect to platform');
      return;
    }
    const payload = '{"services": [{"service_id": "BasicData", "properties": {"button": 1}}]}';
    this.log('topic: ' + this.data.topic);
    client.publish(this.data.topic, payload);
    this.log('publish message successful: ' + payload);
  },

  log: function (msg) {
    console.log(new Date() + ' - ' + msg);
    this.setData({
      log: this.data.log + new Date() + ' - ' + msg + '\r\n'
    });
  }
});

7.2 连接设备


7.3 上报数据


7.4 命令下发


7.5 开启路灯测试

7.5.1 大雾天黑条件触发

当出现大雾(湿度值>90%),天黑(光线强度<50Lux)

7.5.2 开关状态触发(button=0)

7.5.3 手动点击"打开路灯"

7.6 关闭路灯测试

7.6.1 天亮条件触发

当天亮(光线强度>150Lux)

7.6.2 开关状态触发(button=1)

7.6.3 手动点击"关闭路灯"

八、总结

本项目基于华为云IoT平台,结合MQTT协议与微信小程序,实现了社区气象监测与路灯智能控制的完整闭环。系统具备高可靠性、易扩展性和良好的用户体验,适用于智慧社区、园区等场景。

https://developer.huawei.com/consumer/cn/training/classDetail/0e5a7e7a9a324608848b1475d5c8ee1a?type=1?ha_source=hmosclass&ha_sourceId=89000248

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐