• 物联网实践: 树莓派+dht11+html5 实现远程温湿度查看


    (转载请注明来源:cnblogs coder-fang)

    1. 开发说明:python开发websocket服务与树莓派GPIO控制,html做为前端展示,这里使用uni-app UI框架。
    2. 服务及架构图示:
    3. websocket服务代码:
      from websocket_server import WebsocketServer
      import mymqtt
      import time,json
      class WebSock:
          def __init__(self,port):
              self.server = WebsocketServer(port, host='0.0.0.0')
              self.server.set_fn_new_client(self.new_client)
              self.server.set_fn_message_received(self.recv_fromclient)
              self.server.set_fn_client_left(self.client_left)
              self.clients=[]
              self.mqtt = mymqtt.MyMqtt(self.on_mqttconnect,self.on_mqttdisconnect,self.on_mqttmessage)
              
              self.status={"cmd":"gettemp","temp":25,"humi":33,"timespan":time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) }
      
          def on_mqttconnect(self,client, userdata, flags, rc):
              print("Conned broker with result code: " + str(rc))
          def on_mqttdisconnect(self,client, userdata, flags, rc):
              print("DisConned broker with result code: " + str(rc))
      
          def on_mqttmessage(self,client, userdata, msg):                        
              if msg.topic == "dev/up/temp":
                  newmsg = str(msg.payload, encoding="utf-8")
                  self.status = json.loads(newmsg)
                  self.server.send_message_to_all(json.dumps(self.status))
      
      
          def new_client(self,client, server):        
              self.clients.append(client)
              print("newclient:"+str(len(self.clients)))        
      
          def recv_fromclient(self,client, server, message):
              print("getsockreq:"+message)
              if(message =='gettemp'):            
                  self.mqtt.Pub('dev/get/temp',"")
      
          def client_left(self,client, server):
              self.clients.remove(client)
              print("client left:" +str(len(self.clients)))
          def Run(self):
              self.mqtt.Start("dev/up/temp")
              self.server.run_forever()
          def Stop(self):
              self.mqtt.Stop()
              self.server.shutdown()
      View Code
    4. 树莓派dht11 GPIO代码:
      import RPi.GPIO as GPIO
      import time
      
      class DHT11():
          def __init__(self,pin):
              self.channel=pin        
              GPIO.setmode(GPIO.BCM)        #以BCM编码格式        
              time.sleep(1)            #时延一秒        
              
          def GetTemp(self):
              try:
                  data=[]
                  j=0
                  GPIO.setup(self.channel, GPIO.OUT)
                  GPIO.output(self.channel, GPIO.LOW)
                  time.sleep(0.02)        #给信号提示传感器开始工作
                  GPIO.output(self.channel, GPIO.HIGH)        
                  GPIO.setup(self.channel, GPIO.IN)    
                  while GPIO.input(self.channel) == GPIO.HIGH:
                      continue     
                  while GPIO.input(self.channel) == GPIO.LOW:
                      continue        
                  while GPIO.input(self.channel) == GPIO.HIGH:
                      continue
                  
                  while j < 40:
                      k = 0
                      while GPIO.input(self.channel) == GPIO.LOW:
                          continue            
                      while GPIO.input(self.channel) == GPIO.HIGH:
                          k += 1
                          if k > 100:
                              break            
                      if k < 12:
                          data.append(0)
                      else:
                          data.append(1)
                  
                      j += 1        
                  
                          
                  humidity_bit = data[0:8]        #分组
                  humidity_point_bit = data[8:16]
                  temperature_bit = data[16:24]
                  temperature_point_bit = data[24:32]
                  check_bit = data[32:40]
                  
                  humidity = 0
                  humidity_point = 0
                  temperature = 0
                  temperature_point = 0
                  check = 0
                  
                  for i in range(8):
                      humidity += humidity_bit[i] * 2 ** (7 - i)                #转换成十进制数据
                      humidity_point += humidity_point_bit[i] * 2 ** (7 - i)
                      temperature += temperature_bit[i] * 2 ** (7 - i)
                      temperature_point += temperature_point_bit[i] * 2 ** (7 - i)
                      check += check_bit[i] * 2 ** (7 - i)
                  
                  tmp = humidity + humidity_point + temperature + temperature_point        #十进制的数据相加
                  
                  if check == tmp:                                #数据校验,相等则输出
                      print("temperature : "+str(temperature)+", humidity : " + str(humidity))
                      return True,temperature,humidity
                  else:                                        #错误输出错误信息,和校验数据
                      print("wrong")
                      print("temperature : "+ str(temperature)+", humidity : " + str(humidity)+
                       " check : "+ str(check)+ " tmp : "+ str(tmp))
                      return False,-20,0
              except:
                      return False,-20,0
      
          def Cleanup(self):
              GPIO.cleanup(self.channel)
      View Code
    5. 树莓派mqtt客户代码:
      import mymqtt,time,random,json
      from clients.dht11 import DHT11
      class DevCtrl:
          def __init__(self):        
              self.mqtt = mymqtt.MyMqtt(self.on_mqttconnect,self.on_mqttdisconnect,self.on_mqttmessage)
              self.dht11 = DHT11(4)
      
          def on_mqttconnect(self,client, userdata, flags, rc):
              print("Conned broker with result code: " + str(rc))
          def on_mqttdisconnect(self,client, userdata, flags, rc):
              print("DisConned broker with result code: " + str(rc))
      
          def on_mqttmessage(self,client, userdata, msg):        
              if(msg.topic == "dev/get/temp"):
                  print("gettemp reques")
                  ret,temp,humi = self.dht11.GetTemp()
                  status={"cmd":"gettemp","temp":temp,"humi":humi,"timespan":time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) }
                  self.mqtt.Pub("dev/up/temp",json.dumps( status))
      
      
          def Run(self):
              self.mqtt.Start("dev/get/temp",0,True)  
              
                  
          def Stop(self):
              self.dht11.Cleanup()
              self.mqtt.Stop(True)
              
      View Code
    6. UI代码:
      <template>
          <view class="content ">
              <view class=" uni-flex uni-row ">
      
                  <text>上次更新时间:{{updatetext}}</text>
                  <button @click="getData()" :disabled="isloading" style="height: 70%;margin: 10rpx;padding: 0rpx;" type="primary"
                   :loading="isloading" size="mini">刷新</button>
      
      
              </view>
              <view class="qiun-charts ">
                  <canvas canvas-id="canvasGauge" id="canvasGauge" class="charts"></canvas>
              </view>
      
              <view class="qiun-charts ">
                  <canvas canvas-id="canvasGaugeshidu" id="canvasGaugeshidu" class="charts"></canvas>
              </view>
              <Prompt title="输入设备密码" :visible.sync="promptVisible" placeholder="输入密码" @confirm="clickPromptConfirm" mainColor="#e74a39">
                  <!-- 这里放入slot内容-->
      
              </Prompt>
          </view>
      </template>
      
      <script>
          import uCharts from '@/components/u-charts/u-charts/u-charts.js';
          import Prompt from '@/components/zz-prompt/index.vue'
          var _self;
          var canvaGauge = null;
      
          export default {
              components: {
                  Prompt
              },
              data() {
                  return {
                      cWidth: '',
                      cHeight: '',
                      updatetext: '',
                      isloading: true,
                      pixelRatio: 1,
                      gaugeWidth: 15,
                      IsOpen: false,
                      promptVisible: true
                  }
              },
      
      
      
              onLoad() {
                  _self = this;
                  this.cWidth = uni.upx2px(750);
                  this.cHeight = uni.upx2px(500);
                  //this.getServerData();
                  uni.connectSocket({
                      url: 'ws://192.168.3.71:40000',
      
                      fail: () => {
                          console.log("disconnected sock");
                          uni.showModal({
                              content: 'Can not connect web server',
                              showCancel: false
                          });
                      }
                  });
                  uni.onSocketOpen(function() {
                      console.log("WebSock opened");
                      _self.IsOpen = true;
                  });
      
                  uni.onSocketClose(function(res) {
                      console.log('WebSocket 已关闭!');
                      _self.IsOpen = false;
                  });
                  uni.onSocketError(function(res) {
                      uni.showModal({
                          content: 'Can not connect web server',
                          showCancel: false
                      });
                      _self.IsOpen = false;
                  });
                  uni.onSocketMessage(function(res) {
                      console.log("recvmsg:" + res.data);
                      var ret = JSON.parse(res.data);
                      if (ret.cmd == "gettemp")
                      {
                          _self.DrawData(ret.temp, ret.humi)
                          _self.updatetext = ret.timespan
                      }
                          
      
                  });
              },
              methods: {
                  clickPromptConfirm(val) {
      
                      if (val == "123123") {
                          this.promptVisible = false;
                          _self.getData();
                          _self.isloading = true
                      } else {
                          uni.showModal({
                              content: '密码不正确',
                              showCancel: false
                          });
                      }
                  },
                  getData() {
                      _self = this;
                      _self.isloading = true;
                      uni.sendSocketMessage({
                          data: "gettemp"
                      });
                      setTimeout(() => {
                          _self.isloading = false;
                      }, 3000)
      
                  },
                  DrawData(temp, humi) {
                      let Gauge = {
                          categories: [],
                          series: []
                      };
                      //这里我后台返回的是数组,所以用等于,如果您后台返回的是单条数据,需要push进去
                      Gauge.categories = [{
                          "value": 0.43,
                          "color": "#1890ff"
                      }, {
                          "value": 0.56,
                          "color": "#2fc25b"
                      }, {
                          "value": 1,
                          "color": "#f04864"
                      }];
                      Gauge.series = [{
                          "name": "温度",
                          "data": ((temp) / 100 + 0.2) / 0.8,
                          "value": temp
                      }];
      
                      let Gaugeshidu = {
                          categories: [],
                          series: []
                      };
                      //这里我后台返回的是数组,所以用等于,如果您后台返回的是单条数据,需要push进去
                      Gaugeshidu.categories = [{
                          "value": 0.45,
                          "color": "#1890ff"
                      }, {
                          "value": 0.75,
                          "color": "#2fc25b"
                      }, {
                          "value": 1,
                          "color": "#f04864"
                      }];
                      Gaugeshidu.series = [{
                          "name": "湿度",
                          "data": humi / 100
                      }];
      
                      _self.showGauge("canvasGauge", Gauge, Gauge.series[0].value+"°C", -20, 60, 8);
                      _self.showGauge("canvasGaugeshidu", Gaugeshidu, humi+"%");
                  },
                  showGauge(canvasId, chartData, name, start = 0, end = 100, step = 10) {
                      canvaGauge = new uCharts({
                          $this: _self,
                          canvasId: canvasId,
                          type: 'gauge',
                          fontSize: 11,
                          legend: false,
                          title: {
                              name: name,
                              color: chartData.categories[1].color,
                              fontSize: 25 * _self.pixelRatio,
                              offsetY: 50 * _self.pixelRatio, //新增参数,自定义调整Y轴文案距离
                          },
                          subtitle: {
                              name: chartData.series[0].name,
                              color: '#666666',
                              fontSize: 15 * _self.pixelRatio,
                              offsetY: -50 * _self.pixelRatio, //新增参数,自定义调整Y轴文案距离
                          },
                          extra: {
                              gauge: {
                                  type: 'default',
                                   _self.gaugeWidth * _self.pixelRatio, //仪表盘背景的宽度
                                  startAngle: 0.75,
                                  endAngle: 0.25,
                                  startNumber: start,
                                  endNumber: end,
                                  splitLine: {
                                      fixRadius: 0,
                                      splitNumber: step,
                                       _self.gaugeWidth * _self.pixelRatio, //仪表盘背景的宽度
                                      color: '#FFFFFF',
                                      childNumber: 5,
                                      childWidth: _self.gaugeWidth * 0.2 * _self.pixelRatio, //仪表盘背景的宽度
                                  },
                                  pointer: {
                                       _self.gaugeWidth * 0.8 * _self.pixelRatio, //指针宽度
                                      color: 'auto'
                                  }
                              }
                          },
                          background: '#FFFFFF',
                          pixelRatio: _self.pixelRatio,
                          categories: chartData.categories,
                          series: chartData.series,
                          animation: true,
                           _self.cWidth * _self.pixelRatio,
                          height: _self.cHeight * _self.pixelRatio,
                          dataLabel: true,
                      });
      
                  }
              }
          }
      </script>
      
      <style>
          /*样式的width和height一定要与定义的cWidth和cHeight相对应*/
          .qiun-charts {
              width: 750upx;
              height: 500upx;
              background-color: #FFFFFF;
          }
      
          .charts {
              width: 750upx;
              height: 500upx;
              background-color: #FFFFFF;
          }
      
          .content {
              align-content: center;
              -webkit-box-align: center;
              margin-left: 50rpx;
          }
      
          .fixheader {
              align-items: center;
              z-index: 9000;
              background-color: transparent;
              position: fixed;
              width: 100%;
              height: auto;
              overflow-y: auto;
          }
      </style>
      View Code
    7. 手机远程访问效果图:
  • 相关阅读:
    Android 微信分享信息
    微信朋友圈如何同时分享(图片+文字)
    Android应用加入微信分享
    讨论IT选定的技术招聘企业几点
    MSSQL发现第五到数据的第十
    STL 源代码分析 算法 stl_algo.h -- binary_search
    加快XCode编译链接速度(200%+)—XCode编译慢液
    linux复制文件命令scp
    写出高性能的多核并行编程
    SSH—Struts(三)—跑步者(Action)
  • 原文地址:https://www.cnblogs.com/coder-fang/p/12190601.html
Copyright © 2020-2023  润新知