跳到內容
  • 版面
  • 最新
  • 標籤
  • 熱門
  • World
  • 使用者
  • 群組
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • 預設 (Yeti)
  • 未使用主題設計
Collapse
品牌標誌
adminA

鬍子哥

@admin
About
貼文
25
主題
23
Shares
0
群組
1
追隨者
0
追隨
0

貼文

最新 最佳 Controversial

  • 🚀開源專案平台正式啟用!🎉
    adminA admin

    大家好!歡迎來到 開源專案平台 🎊,這裡是一個專為 開源專案、技術交流、專案分享 而打造的討論平台,無論你是開發者、技術愛好者,還是有創新想法的朋友,都歡迎在這裡交流討論!

    🌟 這裡能做什麼?
    ✅ 專案分享 – 發表你的開源專案,讓更多人看見你的成果!
    ✅ 技術討論 – 針對程式開發、IoT、機電整合、再生能源等技術議題進行交流。
    ✅ 錯誤排除 – 遇到 Bug?發問尋求解決方案,社群一起幫忙 Debug!
    ✅ 功能建議 – 如果你覺得平台可以優化,請讓我們知道!

    📢 遇到問題或有建議?
    ⚡ 如果你在 使用平台時遇到任何問題,或是有 新功能建議,歡迎在這篇文章下方留言!
    ⚡ 你也可以發表新主題,讓更多人看到你的問題,討論更有效率!

    系統公告 開源專案平台 南臺科大 藏碳蘊漁團隊

  • TDS Sensor水質硬度傳感器-NB-IoT
    adminA admin

    4.TDS Sensor-NB-IoT.pdf

    #include <WiFi.h>
    #include <Wire.h>
    #include "MatrixInt.h" //安裝方式:https://www.nmking.io/index.php/2022/12/15/701/
    
    #define TdsSensorPin 33       //TDS感測器接入腳位GPIO 33
    #define VREF 3.3              // analog reference voltage(Volt) of the ADC
    #define SCOUNT  30            // sum of sample point
    
    int analogBuffer[SCOUNT];     // store the analog value in the array, read from ADC
    int analogBufferTemp[SCOUNT];
    int analogBufferIndex = 0;
    int copyIndex = 0;
    long WNB303Timeout = 10000; //返回0=Timeout
    int WNB303ResetPIN = 14;      //  設定 WNB303 重置腳位為輸出腳位
    int WNB303PowerPIN = 15;      //  設定 WNB303 電源控制腳位為輸出腳位
    
    float averageVoltage = 0;
    float tdsValue = 0;
    float temperature = 25;       // 設定當前環境溫度 (計算PPM需使用溫度資訊)
    
    // median filtering algorithm
    int getMedianNum(int bArray[], int iFilterLen){
      int bTab[iFilterLen];
      for (byte i = 0; i<iFilterLen; i++)
      bTab[i] = bArray[i];
      int i, j, bTemp;
      for (j = 0; j < iFilterLen - 1; j++) {
        for (i = 0; i < iFilterLen - j - 1; i++) {
          if (bTab[i] > bTab[i + 1]) {
            bTemp = bTab[i];
            bTab[i] = bTab[i + 1];
            bTab[i + 1] = bTemp;
          }
        }
      }
      if ((iFilterLen & 1) > 0){
        bTemp = bTab[(iFilterLen - 1) / 2];
      }
      else {
        bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
      }
      return bTemp;
    }
    // ------ 以下修改成你MQTT設定 ------
    String MQTTServer = "mqttgo.io";//免註冊MQTT伺服器
    String MQTTPort = "1883";//MQTT Port
    String MQTTUser = "";//不須帳密
    String MQTTPassword = "";//不須帳密
    //推播主題1:推播PPM(記得改Topic)
    String MQTTPubTopic = "YourTopic/class/TDSPPM";
    long MQTTLastPublishTime = 0;//此變數用來記錄推播時間
    long MQTTPublishInterval = 5000;//每5秒推撥一次
    
    void setup() {
      Serial.begin(115200);       //  設定序列埠監控視窗的鮑率
      Serial2.begin(115200);      //  設定 WNB303 的鮑率
      Wire.begin(26, 27);         //  Matrix I2C
      for (int i = 0; i <= 7; ++i) MatrixInt(i, 0);//關閉所有燈號
      pinMode(TdsSensorPin,INPUT);
      pinMode(WNB303ResetPIN, OUTPUT);        //  設定 WNB303 電源控制腳位為輸出腳位
      pinMode(WNB303PowerPIN, OUTPUT);        //  設定 WNB303 重置腳位為輸出腳位
      delay(1000);
    
      Serial.println("\r\n\r\n======================\r\nSystem Starting....");
      String result = "";
      //  開啟 Modem 的電源,開啟關閉之間須間隔10秒(延時電路)
      WNB303Restart(10);
      //檢查網路註冊狀態,5分鐘內無法註冊,則重新啟動WNB303
      int tryCount = 0;
      while (1) {
        boolean resultb = WNB303CheckReg();
        Serial.print("WNB303CheckNetReg result="); Serial.println(resultb);
        if (resultb == false) {
          Serial.println("時間內無法註冊網路(" + String(tryCount) + ")");
          delay(10000);
        }
        else break;
        if (tryCount++ >= 30) { //無法註冊已經超過5分鐘
          tryCount = 0;
          WNB303Restart(30);
        }
      }
      //檢查網路訊號品質
      result = WNB303CheckRSSI();
      Serial.print("WNB303CheckRSSI result="); Serial.println(result);
      delay(10000);
    }
    
    void loop() {
      ReadPPM();
      //檢查時間,傳輸步驟:檢查網路、讀取距離、MQTT連線、推播、關閉
      if ((millis() - MQTTLastPublishTime) >= MQTTPublishInterval ) {
        MatrixInt(7, 1);
        //沒有網路,則重新啟動WNB303
        String result = "";
        //檢查網路狀態
        if (!(WNB303CheckReg())) {
          WNB303Restart(60); //60秒後重新檢測網路
          return;
        }else result = WNB303CheckRSSI();
         
        //連線mqtt
        result = mqttConnect(MQTTServer, MQTTPort, MQTTUser, MQTTPassword);
        if (result == "OK") Serial.println("MQTT Connected");
        ReadPPM();
        byte tds1 = 0;
        tds1 = tdsValue,0;
         String payload = String((int)tds1);
        //推播訊息
        result = mqttPublish(MQTTPubTopic, "0", "0", "0", payload);
        if (result == "OK") Serial.println("Data:\"" + payload + "\" Published to " + MQTTPubTopic);
        //關閉mqtt
        result = mqttDisconnect();
        if (result == "OK") Serial.println("MQTT Disconnected");
        MQTTLastPublishTime = millis(); //更新最後傳輸時間
        MatrixInt(7, 0);
      }
      delay(1000);
    }
    
    void ReadPPM() {
      static unsigned long analogSampleTimepoint = millis();
      if(millis()-analogSampleTimepoint > 40U){     //every 40 milliseconds,read the analog value from the ADC
        analogSampleTimepoint = millis();
        analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin);    //read the analog value and store into the buffer
        analogBufferIndex++;
        if(analogBufferIndex == SCOUNT){ 
          analogBufferIndex = 0;
        }
      }   
      
      static unsigned long printTimepoint = millis();
      if(millis()-printTimepoint > 800U){
        printTimepoint = millis();
        for(copyIndex=0; copyIndex<SCOUNT; copyIndex++){
          analogBufferTemp[copyIndex] = analogBuffer[copyIndex];
          
          // read the analog value more stable by the median filtering algorithm, and convert to voltage value
          averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 4096.0;
          
          //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0)); 
          float compensationCoefficient = 1.0+0.02*(temperature-25.0);
          //temperature compensation
          float compensationVoltage=averageVoltage/compensationCoefficient;
          
          //convert voltage value to tds value
          tdsValue=(133.42*compensationVoltage*compensationVoltage*compensationVoltage - 255.86*compensationVoltage*compensationVoltage + 857.39*compensationVoltage)*0.5;
          
          //Serial.print("voltage:");
          //Serial.print(averageVoltage,2);
          //Serial.print("V   ");
          Serial.print("TDS Value:");
          Serial.print(tdsValue,0);
          Serial.println("ppm");
        }
      }
    }
    
    //連線mqtt
    String mqttConnect(String Host, String Port, String MQTTUser, String MQTTPassword) {
      //1.取得IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      result = AT2WNB303("AT+EMQNEW=\"" + IP + "\",\"" + Port + "\"" + "," + 60000  + "," + 1024, "+EMQNEW:");
      String mqttid = split( result, ':', 1);
      //Serial.print("MQTTCreate result="); Serial.println(mqttid);
      //以亂數為ClientID
      String  MQTTClientid = "NBIoT-" + String(random(1000000, 9999999));
      result = AT2WNB303("AT+EMQCON=" + mqttid + ",3,\"" + MQTTClientid + "\"" + "," + 60000  + ",0,0,\"" + MQTTUser + "\",\"" + MQTTPassword + "\"", "OK");
      //Serial.print("MQTTConnect result="); Serial.println(result);
      return result;
    }
    
    //推播訊息
    String mqttPublish(String Topic, String QoS, String retained, String dup , String Payload) {
      String result = "" ;
      String hexPayload = Str2Hex(Payload);
      String lenHexPayload = String(hexPayload.length());
      result = AT2WNB303("AT+EMQPUB=0," + Topic + "," + QoS + "," + retained + "," + dup + "," + lenHexPayload + "," + hexPayload, "OK");
      return result;
    }
    
    //關閉mqtt連線
    String mqttDisconnect() {
      String result = "" ;
      result = AT2WNB303("AT+EMQDISCON=0", "OK");
      return result;
    }
    
    //檢查網路註冊狀態 return true or false
    boolean WNB303CheckReg() {
      String result = "";
      boolean CEREG = false;
      result = AT2WNB303("AT+CEREG?", "+CEREG:");
      if (result.indexOf("0,1") >= 0 || result.indexOf("1,1") >= 0) { //註冊成功
        MatrixInt(5, 0);//亮紅燈
        MatrixInt(6, 1);//亮綠燈
        CEREG = true;
      }
      else {
        MatrixInt(5, 1);//亮紅燈
        MatrixInt(6, 0);//亮綠燈
        CEREG = false;
      }
      return CEREG;
    }
    
    //檢查網路訊號品質 return RSSI,當RSSI=0或99代表沒訊號
    int WNB303CheckRSSI() {
      String result = "";
      int RSSI = 0;
      result = AT2WNB303("AT+CESQ", "+CESQ:");
      //處理+CESQ:
      if (!(result == "-1")) {
        int CESQ = split(split(result, ':', 1), ',', 0).toInt();
        RSSI = CESQ - 111;
      }
      if (RSSI == -111 || RSSI == 210) RSSI = 0;
      MatrixLEDrssi(RSSI);
      return RSSI;
    }
    
    //重新啟動WNB303(單位為秒)
    void WNB303Restart(int dalayTime) {
      AT2WNB303("POWEROFF", "");
      delay(5000);
      AT2WNB303("POWERON", "");
      delay(dalayTime * 1000) ;
    }
    
    
    
    //HTTP GET
    String HTTPGET(String Protocol, String Host, String port, String Url) {
      //例如 http://x.x.x.x/update?api_key=xxxxx&field1=60
      //拆解成Protocol="http" host="x.x.x.x" port="80" Url="/update?api_key=CxxxxxxJ&field1=60"
      //1.轉換網址IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      String PIP = Protocol + "://" + IP + ":" + port + "/";
      int PIPlen = PIP.length();
      //Serial.println("PIP=" + PIP + ",len=" + String(PIPlen));
      result = AT2WNB303("AT+EHTTPCREATE=0," + String(PIPlen) + "," + String(PIPlen) + ",\"" + PIP + "\"", "+EHTTPCREAT");
      result.trim(); String clientid = split(result, ':', 1);
      if (result == "") return "Error: Can't Create Connection";
      else {
        //3.開啟連線
        result = AT2WNB303("AT+EHTTPCON=" + clientid, "OK");
        result.trim();
        if (!(result == "OK")) result = "Error: Can't Connect to Server";
        //4.組成網址並傳送
        int LenUrl = Url.length();
        Url = clientid + ",0," + String(LenUrl) + "," + Url + ",0,,0,,0,";
        Url = "0," + String(Url.length()) + "," + String(Url.length()) + "," + Url;
        result = AT2WNB303("AT+EHTTPSEND=" + Url, "OK");
        if (!(result == "OK")) result = "Error: Can't Send to Server";
      }
      delay(1000);
      //關閉連線
      AT2WNB303("AT+EHTTPDISCON=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      AT2WNB303("AT+EHTTPDESTROY=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      return result;
    }
    
    //HTTP POST
    String HTTPPOST(String Protocol, String Host, String port, String Url , String contType , String Data) {
      //1.轉換網址IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      String PIP = Protocol + "://" + IP + ":" + port + "/";
      int PIPlen = PIP.length();
      //Serial.println("PIP=" + PIP + ",len=" + String(PIPlen));
      result = AT2WNB303("AT+EHTTPCREATE=0," + String(PIPlen) + "," + String(PIPlen) + ",\"" + PIP + "\"", "+EHTTPCREAT");
      result.trim(); String clientid = split(result, ':', 1);
      if (result == "") return "Error: Can't Create Connection";
      else {
        //3.開啟連線
        result = AT2WNB303("AT+EHTTPCON=" + clientid, "OK");
        result.trim();
        if (!(result == "OK")) result = "Error: Can't Connect to Server";
        //4.組成網址並傳送
        int i = 0;
        String PostCommand[10];
        PostCommand[i++] = clientid + ",1," + Url.length() + "," + Url + ",0,," + contType.length() + "," + contType + ",";
        //Serial.println("command1=" + PostCommand[i - 1]);
        String hexData = Str2Hex(Data);
        int lenHexData = hexData.length();
        PostCommand[i++] = String(lenHexData) + ",";
        //Serial.println("command2=" + PostCommand[i - 1]);
        int num = 30;
        for (int n = 0; n < lenHexData; n = n + num) {
          String DataSend = "";
          if (n + num < lenHexData) {
            //切割字串
            DataSend = hexData.substring(n, n + num);
          } else if (lenHexData % num > 0) {
            int remainder = lenHexData % num;
            //切割字串
            DataSend = hexData.substring(n, n + remainder);
          }
          PostCommand[i++] = DataSend;
          //Serial.println("command2=" + PostCommand[i - 1]);
        }
        //求出每條命令長度
        int totalLenHexData = 0;
        for (int j = 0; j <= i - 1; j++) {
          totalLenHexData = totalLenHexData + PostCommand[j].length();
          PostCommand[j] = String(PostCommand[j].length()) + "," + PostCommand[j];
        }
        //完成命令組合
        for (int j = 0; j <= i - 1; j++) {
          if (j == 1) PostCommand[j] = "AT+EHTTPSEND=1," + String(totalLenHexData) + "," + PostCommand[j];
          else if (j == i - 1) PostCommand[j] = "AT+EHTTPSEND=0," + String(totalLenHexData) + "," + PostCommand[j];
          else PostCommand[j] = "AT+EHTTPSEND=1," + String(totalLenHexData) + "," + PostCommand[j];
          result = AT2WNB303(PostCommand[j], "OK");
          //Serial.println("POST" + String(j) + + ":" + result);
        }
    
      }
      delay(1000);
      //關閉連線
      AT2WNB303("AT+EHTTPDISCON=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      AT2WNB303("AT+EHTTPDESTROY=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      return result;
    }
    
    //將訊息傳到WNB303,並讀取回傳訊息 0代表timeout
    String AT2WNB303(String ATdata, String StartWith) {
      Serial.println("你的命令是:" + ATdata);
      if (ATdata.length() > 0) { //送出AT命令
        ATdata.trim();
        String command = ATdata;
        command.toUpperCase();
    
        if (command == "RESET") {  //重置 WNB303
          digitalWrite(WNB303ResetPIN, HIGH);
          delay(10000);
          digitalWrite(WNB303ResetPIN, LOW);
          return "RESET OK";
        }
        else if (command == "POWERON") {  //開啟 WNB303 的電源
          digitalWrite(WNB303PowerPIN, HIGH);
          return "POWERON OK";
        }
        else if (command == "POWEROFF") {  //關閉 WNB303 的電源
          digitalWrite(WNB303PowerPIN, LOW);
          return "POWEROFF OK";
        }
        else  {  //送出AT命令
          Serial2.println(ATdata);
        }
      }
      else return "";
      String result = "";
      //等候回應資料
      long StartTime = millis();
      while (1) {
        result = "";
        while (Serial2.available()) { //WNB303有資料回傳
          char c = Serial2.read();    //從WNB303讀取一個位元組
          result += c;                //將讀到的字元 c 加進字串 Xfer
          if (c == '\n') break;
        }
        result.trim();
        if (result.startsWith(StartWith)) break; //結尾OK返回
        if ((millis() - StartTime) >= WNB303Timeout ) { //Timeout返回
          result = "0";
          break;
        }
      }
      return result;
    }
    
    //字串轉HEX
    String Str2Hex(String msg) {
      String a = "";
      for (int i = 0; i < msg.length(); i++)  {
        a = a + String(msg.charAt(i), HEX);
      }
      return a;
    }
    
    //HEX轉字串
    String Hex2Str(String msg) {
      char input[msg.length() + 1];
      msg.toCharArray(input, msg.length() + 1);
      char c[sizeof(input)];
      String a = "";
      for (int i = 0; i < sizeof(input) - 1; i += 2) {
        char temp[3];
        temp[0] = input[i];
        temp[1] = input[i + 1];
        int val = ASCIIHexToInt(temp[0]) * 16 + ASCIIHexToInt(temp[1]);
        c[i] = toascii(val);
        a = a + String(c[i]);
      }
      return a;
    }
    
    //ASC轉INT
    int ASCIIHexToInt(char c) {
      int ret = 0;
      if ((c >= '0') && (c <= '9')) ret = (ret << 4) + c - '0';
      else ret = (ret << 4) + toupper(c) - 'A' + 10;
      return ret;
    }
    
    //split拆解,範例:String a1=split(“aa,bb,cc”,’,’,0);
    String split(String data, char separator, int index) {
      int found = 0;
      int strIndex[] = { 0, -1 };
      int maxIndex = data.length() - 1;
      for (int i = 0; i <= maxIndex && found <= index; i++) {
        if (data.charAt(i) == separator || i == maxIndex) {
          found++;
          strIndex[0] = strIndex[1] + 1;
          strIndex[1] = (i == maxIndex) ? i + 1 : i;
        }
      }
      return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
    }
    
    TDS Sensor水質硬度傳感器 水質硬度傳感器 tds sensor nb-iot esp32

  • TDS Sensor水質硬度傳感器-MQTT
    adminA admin

    2.TDS Sensor-MQTT.pdf

    #include <WiFi.h>
    #include <PubSubClient.h> //請先安裝PubSubClient程式庫
    
    #define TdsSensorPin 33       //TDS感測器接入腳位GPIO 33
    #define VREF 3.3              // analog reference voltage(Volt) of the ADC
    #define SCOUNT  30            // sum of sample point
    // ------ 以下修改成你自己的WiFi帳號密碼 ------
    char* ssid = "SSID";
    char* password = "PASSWORD";
    
    int analogBuffer[SCOUNT];     // store the analog value in the array, read from ADC
    int analogBufferTemp[SCOUNT];
    int analogBufferIndex = 0;
    int copyIndex = 0;
    
    float averageVoltage = 0;
    float tdsValue = 0;
    float temperature = 25;       // 設定當前環境溫度 (計算PPM需使用溫度資訊)
    
    // median filtering algorithm
    int getMedianNum(int bArray[], int iFilterLen){
      int bTab[iFilterLen];
      for (byte i = 0; i<iFilterLen; i++)
      bTab[i] = bArray[i];
      int i, j, bTemp;
      for (j = 0; j < iFilterLen - 1; j++) {
        for (i = 0; i < iFilterLen - j - 1; i++) {
          if (bTab[i] > bTab[i + 1]) {
            bTemp = bTab[i];
            bTab[i] = bTab[i + 1];
            bTab[i + 1] = bTemp;
          }
        }
      }
      if ((iFilterLen & 1) > 0){
        bTemp = bTab[(iFilterLen - 1) / 2];
      }
      else {
        bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
      }
      return bTemp;
    }
    // ------ 以下修改成你MQTT設定 ------
    char* MQTTServer = "broker.mqttgo.io";//免註冊MQTT伺服器
    int MQTTPort = 1883;//MQTT Port
    char* MQTTUser = "";//不須帳密
    char* MQTTPassword = "";//不須帳密
    //推播主題1:推播PPM(記得改Topic)
    char* MQTTPubTopic1 = "YourTopic/class/TDSPPM";
    long MQTTLastPublishTime;//此變數用來記錄推播時間
    long MQTTPublishInterval = 1000;//每10秒推撥一次
    WiFiClient WifiClient;
    PubSubClient MQTTClient(WifiClient);
    
    void setup() {
      Serial.begin(115200);
      pinMode(TdsSensorPin,INPUT);
    
      //開始WiFi連線
      WifiConnecte();
    
      //開始MQTT連線
      MQTTConnecte();
    }
    
    void loop() {
       static unsigned long analogSampleTimepoint = millis();
      if(millis()-analogSampleTimepoint > 40U){     //every 40 milliseconds,read the analog value from the ADC
        analogSampleTimepoint = millis();
        analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin);    //read the analog value and store into the buffer
        analogBufferIndex++;
        if(analogBufferIndex == SCOUNT){ 
          analogBufferIndex = 0;
        }
      }   
      
      static unsigned long printTimepoint = millis();
      if(millis()-printTimepoint > 800U){
        printTimepoint = millis();
        for(copyIndex=0; copyIndex<SCOUNT; copyIndex++){
          analogBufferTemp[copyIndex] = analogBuffer[copyIndex];
          
          // read the analog value more stable by the median filtering algorithm, and convert to voltage value
          averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 4096.0;
          
          //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0)); 
          float compensationCoefficient = 1.0+0.02*(temperature-25.0);
          //temperature compensation
          float compensationVoltage=averageVoltage/compensationCoefficient;
          
          //convert voltage value to tds value
          tdsValue=(133.42*compensationVoltage*compensationVoltage*compensationVoltage - 255.86*compensationVoltage*compensationVoltage + 857.39*compensationVoltage)*0.5;
          
          //Serial.print("voltage:");
          //Serial.print(averageVoltage,2);
          //Serial.print("V   ");
          Serial.print("TDS Value:");
          Serial.print(tdsValue,0);
          Serial.println("ppm");
    
        }
      }
    
      //如果WiFi連線中斷,則重啟WiFi連線
      if (WiFi.status() != WL_CONNECTED) { WifiConnecte(); }
    
      //如果MQTT連線中斷,則重啟MQTT連線
      if (!MQTTClient.connected()) {  MQTTConnecte(); }
    
      //如果距離上次傳輸已經超過10秒,則Publish
      if ((millis() - MQTTLastPublishTime) >= MQTTPublishInterval ) {
        byte tds1 = 0;
        tds1 = tdsValue,0;
        // ------ 將TDS送到MQTT主題 ------
        MQTTClient.publish(MQTTPubTopic1, String(tds1).c_str());
        Serial.println("已推播到MQTT Broker");
        MQTTLastPublishTime = millis(); //更新最後傳輸時間
      }
      MQTTClient.loop();//更新訂閱狀態
      delay(50);
    }
    
    //開始WiFi連線
    void WifiConnecte() {
      //開始WiFi連線
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("WiFi連線成功");
      Serial.print("IP Address:");
      Serial.println(WiFi.localIP());
    }
    
    //開始MQTT連線
    void MQTTConnecte() {
      MQTTClient.setServer(MQTTServer, MQTTPort);
      while (!MQTTClient.connected()) {
        //以亂數為ClietID
        String  MQTTClientid = "esp32-" + String(random(1000000, 9999999));
        if (MQTTClient.connect(MQTTClientid.c_str(), MQTTUser, MQTTPassword)) {
          //連結成功,顯示「已連線」。
          Serial.println("MQTT已連線");
    
        } else {
          //若連線不成功,則顯示錯誤訊息,並重新連線
          Serial.print("MQTT連線失敗,狀態碼=");
          Serial.println(MQTTClient.state());
          Serial.println("五秒後重新連線");
          delay(5000);
        }
      }
    }```
    TDS Sensor水質硬度傳感器 tds sensor 水質硬度傳感器 mqtt esp32

  • TDS Sensor水質硬度傳感器-序列埠視窗監控
    adminA admin

    1.TDS Sensor-序列埠視窗監控.pdf

    // Original source code: https://wiki.keyestudio.com/KS0429_keyestudio_TDS_Meter_V1.0#Test_Code
    // Project details: https://RandomNerdTutorials.com/esp32-tds-water-quality-sensor/
    
    #define TdsSensorPin 33       //TDS感測器腳位
    #define VREF 3.3              // analog reference voltage(Volt) of the ADC
    #define SCOUNT  30            // sum of sample point
    
    int analogBuffer[SCOUNT];     // store the analog value in the array, read from ADC
    int analogBufferTemp[SCOUNT];
    int analogBufferIndex = 0;
    int copyIndex = 0;
    
    float averageVoltage = 0;
    float tdsValue = 0;
    float temperature = 25;       // 當前環境溫度
    
    // median filtering algorithm
    int getMedianNum(int bArray[], int iFilterLen){
      int bTab[iFilterLen];
      for (byte i = 0; i<iFilterLen; i++)
      bTab[i] = bArray[i];
      int i, j, bTemp;
      for (j = 0; j < iFilterLen - 1; j++) {
        for (i = 0; i < iFilterLen - j - 1; i++) {
          if (bTab[i] > bTab[i + 1]) {
            bTemp = bTab[i];
            bTab[i] = bTab[i + 1];
            bTab[i + 1] = bTemp;
          }
        }
      }
      if ((iFilterLen & 1) > 0){
        bTemp = bTab[(iFilterLen - 1) / 2];
      }
      else {
        bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
      }
      return bTemp;
    }
    
    void setup(){
      Serial.begin(115200);
      pinMode(TdsSensorPin,INPUT);
    }
    
    void loop(){
      static unsigned long analogSampleTimepoint = millis();
      if(millis()-analogSampleTimepoint > 40U){     //every 40 milliseconds,read the analog value from the ADC
        analogSampleTimepoint = millis();
        analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin);    //read the analog value and store into the buffer
        analogBufferIndex++;
        if(analogBufferIndex == SCOUNT){ 
          analogBufferIndex = 0;
        }
      }   
      
      static unsigned long printTimepoint = millis();
      if(millis()-printTimepoint > 800U){
        printTimepoint = millis();
        for(copyIndex=0; copyIndex<SCOUNT; copyIndex++){
          analogBufferTemp[copyIndex] = analogBuffer[copyIndex];
          
          // read the analog value more stable by the median filtering algorithm, and convert to voltage value
          averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 4096.0;
          
          //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0)); 
          float compensationCoefficient = 1.0+0.02*(temperature-25.0);
          //temperature compensation
          float compensationVoltage=averageVoltage/compensationCoefficient;
          
          //convert voltage value to tds value
          tdsValue=(133.42*compensationVoltage*compensationVoltage*compensationVoltage - 255.86*compensationVoltage*compensationVoltage + 857.39*compensationVoltage)*0.5;
          
          //Serial.print("voltage:");
          //Serial.print(averageVoltage,2);
          //Serial.print("V   ");
          Serial.print("TDS Value:");
          Serial.print(tdsValue,0);
          Serial.println("ppm");
        }
      }
    }
    
    TDS Sensor水質硬度傳感器 tds sensor 水質硬度傳感器 序列埠視窗監控 esp32

  • HC-SR04超聲波測距-NB-IoT
    adminA admin

    4.土壤溼度感測器-NB-IoT.pdf

    #include <WiFi.h>
    #include <Wire.h>
    #include "MatrixInt.h" //安裝方式:https://www.nmking.io/index.php/2022/12/15/701/
    
    long WNB303Timeout = 10000; //返回0=Timeout
    int trigPin=18; //發出聲波腳位(ESP32 GPIO18)
    int echoPin=19; //接收聲波腳位(ESP32 GPIO19)
    //使用小霸王Matrix板
    int WNB303ResetPIN = 14;      //  設定 WNB303 重置腳位為輸出腳位
    int WNB303PowerPIN = 15;      //  設定 WNB303 電源控制腳位為輸出腳位
    
    // ------ 以下修改成你MQTT設定 ------
    String MQTTServer = "mqttgo.io";//免註冊MQTT伺服器
    String MQTTPort = "1883";//MQTT Port
    String MQTTUser = "";//不須帳密
    String MQTTPassword = "";//不須帳密
    String MQTTPubTopic = "YourTopic/class402/UltraSound";//推播主題:推播距離(記得改成你自己的Topic)
    long MQTTLastPublishTime = 0;//此變數用來記錄推播時間
    long MQTTPublishInterval = 5000;//每5秒推撥一次
    
    void setup() {
      Serial.begin(115200);       //  設定序列埠監控視窗的鮑率
      Serial2.begin(115200);      //  設定 WNB303 的鮑率
      Wire.begin(26, 27);         //  Matrix I2C
      for (int i = 0; i <= 7; ++i) MatrixInt(i, 0);//關閉所有燈號
      pinMode(trigPin, OUTPUT); 
      pinMode(WNB303ResetPIN, OUTPUT);        //  設定 WNB303 電源控制腳位為輸出腳位
      pinMode(WNB303PowerPIN, OUTPUT);        //  設定 WNB303 重置腳位為輸出腳位
      delay(1000);
    
      Serial.println("\r\n\r\n======================\r\nSystem Starting....");
      String result = "";
      //  開啟 Modem 的電源,開啟關閉之間須間隔10秒(延時電路)
      WNB303Restart(10);
      //檢查網路註冊狀態,5分鐘內無法註冊,則重新啟動WNB303
      int tryCount = 0;
      while (1) {
        boolean resultb = WNB303CheckReg();
        Serial.print("WNB303CheckNetReg result="); Serial.println(resultb);
        if (resultb == false) {
          Serial.println("時間內無法註冊網路(" + String(tryCount) + ")");
          delay(10000);
        }
        else break;
        if (tryCount++ >= 30) { //無法註冊已經超過5分鐘
          tryCount = 0;
          WNB303Restart(30);
        }
      }
      //檢查網路訊號品質
      result = WNB303CheckRSSI();
      Serial.print("WNB303CheckRSSI result="); Serial.println(result);
      delay(10000);
    }
    
    void loop() {
    
      //檢查時間,傳輸步驟:檢查網路、讀取距離、MQTT連線、推播、關閉
      if ((millis() - MQTTLastPublishTime) >= MQTTPublishInterval ) {
        MatrixInt(7, 1);
        //沒有網路,則重新啟動WNB303
        String result = "";
        //檢查網路狀態
        if (!(WNB303CheckReg())) {
          WNB303Restart(60); //60秒後重新檢測網路
          return;
        }else result = WNB303CheckRSSI();
         
        //連線mqtt
        result = mqttConnect(MQTTServer, MQTTPort, MQTTUser, MQTTPassword);
        if (result == "OK") Serial.println("MQTT Connected");
         ReadLD();
         String payload = String((int)ping()/58);
        //推播訊息
        result = mqttPublish(MQTTPubTopic, "0", "0", "0", payload);
        if (result == "OK") Serial.println("Data:\"" + payload + "\" Published to " + MQTTPubTopic);
        //關閉mqtt
        result = mqttDisconnect();
        if (result == "OK") Serial.println("MQTT Disconnected");
        MQTTLastPublishTime = millis(); //更新最後傳輸時間
        MatrixInt(7, 0);
      }
      delay(1000);
    }
    
    //連線mqtt
    String mqttConnect(String Host, String Port, String MQTTUser, String MQTTPassword) {
      //1.取得IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      result = AT2WNB303("AT+EMQNEW=\"" + IP + "\",\"" + Port + "\"" + "," + 60000  + "," + 1024, "+EMQNEW:");
      String mqttid = split( result, ':', 1);
      //Serial.print("MQTTCreate result="); Serial.println(mqttid);
      //以亂數為ClientID
      String  MQTTClientid = "NBIoT-" + String(random(1000000, 9999999));
      result = AT2WNB303("AT+EMQCON=" + mqttid + ",3,\"" + MQTTClientid + "\"" + "," + 60000  + ",0,0,\"" + MQTTUser + "\",\"" + MQTTPassword + "\"", "OK");
      //Serial.print("MQTTConnect result="); Serial.println(result);
      return result;
    }
    
    //推播訊息
    String mqttPublish(String Topic, String QoS, String retained, String dup , String Payload) {
      String result = "" ;
      String hexPayload = Str2Hex(Payload);
      String lenHexPayload = String(hexPayload.length());
      result = AT2WNB303("AT+EMQPUB=0," + Topic + "," + QoS + "," + retained + "," + dup + "," + lenHexPayload + "," + hexPayload, "OK");
      return result;
    }
    
    //關閉mqtt連線
    String mqttDisconnect() {
      String result = "" ;
      result = AT2WNB303("AT+EMQDISCON=0", "OK");
      return result;
    }
    
    //檢查網路註冊狀態 return true or false
    boolean WNB303CheckReg() {
      String result = "";
      boolean CEREG = false;
      result = AT2WNB303("AT+CEREG?", "+CEREG:");
      if (result.indexOf("0,1") >= 0 || result.indexOf("1,1") >= 0) { //註冊成功
        MatrixInt(5, 0);//亮紅燈
        MatrixInt(6, 1);//亮綠燈
        CEREG = true;
      }
      else {
        MatrixInt(5, 1);//亮紅燈
        MatrixInt(6, 0);//亮綠燈
        CEREG = false;
      }
      return CEREG;
    }
    
    //檢查網路訊號品質 return RSSI,當RSSI=0或99代表沒訊號
    int WNB303CheckRSSI() {
      String result = "";
      int RSSI = 0;
      result = AT2WNB303("AT+CESQ", "+CESQ:");
      //處理+CESQ:
      if (!(result == "-1")) {
        int CESQ = split(split(result, ':', 1), ',', 0).toInt();
        RSSI = CESQ - 111;
      }
      if (RSSI == -111 || RSSI == 210) RSSI = 0;
      MatrixLEDrssi(RSSI);
      return RSSI;
    }
    
    //重新啟動WNB303(單位為秒)
    void WNB303Restart(int dalayTime) {
      AT2WNB303("POWEROFF", "");
      delay(5000);
      AT2WNB303("POWERON", "");
      delay(dalayTime * 1000) ;
    }
    
    
    
    //HTTP GET
    String HTTPGET(String Protocol, String Host, String port, String Url) {
      //例如 http://x.x.x.x/update?api_key=xxxxx&field1=60
      //拆解成Protocol="http" host="x.x.x.x" port="80" Url="/update?api_key=CxxxxxxJ&field1=60"
      //1.轉換網址IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      String PIP = Protocol + "://" + IP + ":" + port + "/";
      int PIPlen = PIP.length();
      //Serial.println("PIP=" + PIP + ",len=" + String(PIPlen));
      result = AT2WNB303("AT+EHTTPCREATE=0," + String(PIPlen) + "," + String(PIPlen) + ",\"" + PIP + "\"", "+EHTTPCREAT");
      result.trim(); String clientid = split(result, ':', 1);
      if (result == "") return "Error: Can't Create Connection";
      else {
        //3.開啟連線
        result = AT2WNB303("AT+EHTTPCON=" + clientid, "OK");
        result.trim();
        if (!(result == "OK")) result = "Error: Can't Connect to Server";
        //4.組成網址並傳送
        int LenUrl = Url.length();
        Url = clientid + ",0," + String(LenUrl) + "," + Url + ",0,,0,,0,";
        Url = "0," + String(Url.length()) + "," + String(Url.length()) + "," + Url;
        result = AT2WNB303("AT+EHTTPSEND=" + Url, "OK");
        if (!(result == "OK")) result = "Error: Can't Send to Server";
      }
      delay(1000);
      //關閉連線
      AT2WNB303("AT+EHTTPDISCON=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      AT2WNB303("AT+EHTTPDESTROY=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      return result;
    }
    
    //HTTP POST
    String HTTPPOST(String Protocol, String Host, String port, String Url , String contType , String Data) {
      //1.轉換網址IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      String PIP = Protocol + "://" + IP + ":" + port + "/";
      int PIPlen = PIP.length();
      //Serial.println("PIP=" + PIP + ",len=" + String(PIPlen));
      result = AT2WNB303("AT+EHTTPCREATE=0," + String(PIPlen) + "," + String(PIPlen) + ",\"" + PIP + "\"", "+EHTTPCREAT");
      result.trim(); String clientid = split(result, ':', 1);
      if (result == "") return "Error: Can't Create Connection";
      else {
        //3.開啟連線
        result = AT2WNB303("AT+EHTTPCON=" + clientid, "OK");
        result.trim();
        if (!(result == "OK")) result = "Error: Can't Connect to Server";
        //4.組成網址並傳送
        int i = 0;
        String PostCommand[10];
        PostCommand[i++] = clientid + ",1," + Url.length() + "," + Url + ",0,," + contType.length() + "," + contType + ",";
        //Serial.println("command1=" + PostCommand[i - 1]);
        String hexData = Str2Hex(Data);
        int lenHexData = hexData.length();
        PostCommand[i++] = String(lenHexData) + ",";
        //Serial.println("command2=" + PostCommand[i - 1]);
        int num = 30;
        for (int n = 0; n < lenHexData; n = n + num) {
          String DataSend = "";
          if (n + num < lenHexData) {
            //切割字串
            DataSend = hexData.substring(n, n + num);
          } else if (lenHexData % num > 0) {
            int remainder = lenHexData % num;
            //切割字串
            DataSend = hexData.substring(n, n + remainder);
          }
          PostCommand[i++] = DataSend;
          //Serial.println("command2=" + PostCommand[i - 1]);
        }
        //求出每條命令長度
        int totalLenHexData = 0;
        for (int j = 0; j <= i - 1; j++) {
          totalLenHexData = totalLenHexData + PostCommand[j].length();
          PostCommand[j] = String(PostCommand[j].length()) + "," + PostCommand[j];
        }
        //完成命令組合
        for (int j = 0; j <= i - 1; j++) {
          if (j == 1) PostCommand[j] = "AT+EHTTPSEND=1," + String(totalLenHexData) + "," + PostCommand[j];
          else if (j == i - 1) PostCommand[j] = "AT+EHTTPSEND=0," + String(totalLenHexData) + "," + PostCommand[j];
          else PostCommand[j] = "AT+EHTTPSEND=1," + String(totalLenHexData) + "," + PostCommand[j];
          result = AT2WNB303(PostCommand[j], "OK");
          //Serial.println("POST" + String(j) + + ":" + result);
        }
    
      }
      delay(1000);
      //關閉連線
      AT2WNB303("AT+EHTTPDISCON=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      AT2WNB303("AT+EHTTPDESTROY=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      return result;
    }
    
    //將訊息傳到WNB303,並讀取回傳訊息 0代表timeout
    String AT2WNB303(String ATdata, String StartWith) {
      Serial.println("你的命令是:" + ATdata);
      if (ATdata.length() > 0) { //送出AT命令
        ATdata.trim();
        String command = ATdata;
        command.toUpperCase();
    
        if (command == "RESET") {  //重置 WNB303
          digitalWrite(WNB303ResetPIN, HIGH);
          delay(10000);
          digitalWrite(WNB303ResetPIN, LOW);
          return "RESET OK";
        }
        else if (command == "POWERON") {  //開啟 WNB303 的電源
          digitalWrite(WNB303PowerPIN, HIGH);
          return "POWERON OK";
        }
        else if (command == "POWEROFF") {  //關閉 WNB303 的電源
          digitalWrite(WNB303PowerPIN, LOW);
          return "POWEROFF OK";
        }
        else  {  //送出AT命令
          Serial2.println(ATdata);
        }
      }
      else return "";
      String result = "";
      //等候回應資料
      long StartTime = millis();
      while (1) {
        result = "";
        while (Serial2.available()) { //WNB303有資料回傳
          char c = Serial2.read();    //從WNB303讀取一個位元組
          result += c;                //將讀到的字元 c 加進字串 Xfer
          if (c == '\n') break;
        }
        result.trim();
        if (result.startsWith(StartWith)) break; //結尾OK返回
        if ((millis() - StartTime) >= WNB303Timeout ) { //Timeout返回
          result = "0";
          break;
        }
      }
      return result;
    }
    
      /*副程式
     *Send 10us pulse to HC-SR04 trigger pin
     */
    unsigned long ping() { 
      digitalWrite(trigPin, HIGH); //啟動超音波
      delayMicroseconds(10);  //sustain at least 10us HIGH pulse
      digitalWrite(trigPin, LOW);  //關閉超音波
      return pulseIn(echoPin, HIGH); //計算傳回時間
    }
    
    void ReadLD(){
      unsigned long d=ping()/58; //計算距離
         Serial.print(d);
         Serial.println("cm");
    }
    
    //字串轉HEX
    String Str2Hex(String msg) {
      String a = "";
      for (int i = 0; i < msg.length(); i++)  {
        a = a + String(msg.charAt(i), HEX);
      }
      return a;
    }
    
    //HEX轉字串
    String Hex2Str(String msg) {
      char input[msg.length() + 1];
      msg.toCharArray(input, msg.length() + 1);
      char c[sizeof(input)];
      String a = "";
      for (int i = 0; i < sizeof(input) - 1; i += 2) {
        char temp[3];
        temp[0] = input[i];
        temp[1] = input[i + 1];
        int val = ASCIIHexToInt(temp[0]) * 16 + ASCIIHexToInt(temp[1]);
        c[i] = toascii(val);
        a = a + String(c[i]);
      }
      return a;
    }
    
    //ASC轉INT
    int ASCIIHexToInt(char c) {
      int ret = 0;
      if ((c >= '0') && (c <= '9')) ret = (ret << 4) + c - '0';
      else ret = (ret << 4) + toupper(c) - 'A' + 10;
      return ret;
    }
    
    //split拆解,範例:String a1=split(“aa,bb,cc”,’,’,0);
    String split(String data, char separator, int index) {
      int found = 0;
      int strIndex[] = { 0, -1 };
      int maxIndex = data.length() - 1;
      for (int i = 0; i <= maxIndex && found <= index; i++) {
        if (data.charAt(i) == separator || i == maxIndex) {
          found++;
          strIndex[0] = strIndex[1] + 1;
          strIndex[1] = (i == maxIndex) ? i + 1 : i;
        }
      }
      return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
    }
    
    
    超聲波測距 hc-sr04超聲波測距 nb-iot esp32

  • HC-SR04超聲波測距-MQTT
    adminA admin

    2.土壤溼度感測器-MQTT.pdf

    #include <WiFi.h>
    #include <PubSubClient.h> //請先安裝PubSubClient程式庫
    
    // ------ 以下修改成你自己的WiFi帳號密碼 ------
    char* ssid = "YourSSID";
    char* password = "YourPASSWORD";
    //------ 以下修改成你的超聲波感測器腳位 ------
    int trigPin=18; //發出聲波腳位(ESP32 GPIO18)
    int echoPin=19; //接收聲波腳位(ESP32 GPIO19)
    // ------ 以下修改成你MQTT設定 ------
    char* MQTTServer = "broker.mqttgo.io";//免註冊MQTT伺服器
    int MQTTPort = 1883;//MQTT Port
    char* MQTTUser = "";//不須帳密
    char* MQTTPassword = "";//不須帳密
    //推播主題1:推播距離(記得改Topic)
    char* MQTTPubTopic1 = "YourTopic/class402/UltraSound";
    long MQTTLastPublishTime;//此變數用來記錄推播時間
    long MQTTPublishInterval = 1000;//每1秒推撥一次
    WiFiClient WifiClient;
    PubSubClient MQTTClient(WifiClient);
    
    void setup() {
      Serial.begin(9600);
      pinMode(trigPin, OUTPUT); 
    
    
      //開始WiFi連線
      WifiConnecte();
    
      //開始MQTT連線
      MQTTConnecte();
    }
    
    void loop() {
      //如果WiFi連線中斷,則重啟WiFi連線
      if (WiFi.status() != WL_CONNECTED) { WifiConnecte(); }
    
      //如果MQTT連線中斷,則重啟MQTT連線
      if (!MQTTClient.connected()) {  MQTTConnecte(); }
    
      //如果距離上次傳輸已經超過1秒,則Publish距離
      if ((millis() - MQTTLastPublishTime) >= MQTTPublishInterval ) {
       
      byte D1 = 0;
      D1=ping()/58;
        // ------ 將距離送到MQTT主題 ------
        MQTTClient.publish(MQTTPubTopic1, String((int)D1).c_str());
        Serial.println("超聲波距離已推播到MQTT Broker");
        MQTTLastPublishTime = millis(); //更新最後傳輸時間
      }
      MQTTClient.loop();//更新訂閱狀態
      delay(50);
    
      unsigned long d=ping()/58; //計算距離
      Serial.print(d);
      Serial.println("cm");
      delay(1000);
      }
    
    /*副程式
     *Send 10us pulse to HC-SR04 trigger pin
     */
    unsigned long ping() { 
      digitalWrite(trigPin, HIGH); //啟動超音波
      delayMicroseconds(10);  //sustain at least 10us HIGH pulse
      digitalWrite(trigPin, LOW);  //關閉超音波
      return pulseIn(echoPin, HIGH); //計算傳回時間
    }
    
    //開始WiFi連線
    void WifiConnecte() {
      //開始WiFi連線
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("WiFi連線成功");
      Serial.print("IP Address:");
      Serial.println(WiFi.localIP());
    }
    
    //開始MQTT連線
    void MQTTConnecte() {
      MQTTClient.setServer(MQTTServer, MQTTPort);
      while (!MQTTClient.connected()) {
        //以亂數為ClietID
        String  MQTTClientid = "esp32-" + String(random(1000000, 9999999));
        if (MQTTClient.connect(MQTTClientid.c_str(), MQTTUser, MQTTPassword)) {
          //連結成功,顯示「已連線」。
          Serial.println("MQTT已連線");
    
        } else {
          //若連線不成功,則顯示錯誤訊息,並重新連線
          Serial.print("MQTT連線失敗,狀態碼=");
          Serial.println(MQTTClient.state());
          Serial.println("五秒後重新連線");
          delay(5000);
        }
      }
    }
    
    
    超聲波測距 hc-sr04超聲波測距 esp32 mqtt

  • HC-SR04超聲波測距-序列埠視窗監控
    adminA admin

    1.超聲波距離感測HC-SR04-序列埠視窗監控.pdf

    int trigPin=18; //發出聲波腳位(ESP32 GPIO18)
    int echoPin=19; //接收聲波腳位(ESP32 GPIO19)
    
    void setup() {
      pinMode(trigPin, OUTPUT); 
      Serial.begin(9600);
      }
    
    void loop() {
      unsigned long d=ping()/58; //計算距離
      Serial.print(d);
      Serial.println("cm");
      delay(1000);
      }
    
    /*副程式
     *Send 10us pulse to HC-SR04 trigger pin
     */
    unsigned long ping() { 
      digitalWrite(trigPin, HIGH); //啟動超音波
      delayMicroseconds(10);  //sustain at least 10us HIGH pulse
      digitalWrite(trigPin, LOW);  //關閉超音波
      return pulseIn(echoPin, HIGH); //計算傳回時間
     }
    
    超聲波測距 hc-sr04超聲波測距 esp32 序列埠視窗監控

  • 土壤濕度感測器-NB-IoT
    adminA admin

    4.土壤溼度感測器-NB-IoT.pdf

    #include <WiFi.h>
    #include <Wire.h>
    #include "MatrixInt.h" //安裝方式:https://www.nmking.io/index.php/2022/12/15/701/
    
    long WNB303Timeout = 10000; //返回0=Timeout
    int soil_sensor = 36; //土壤濕度感測器AO信號腳 連接到ESP32 GPIO36
    //使用小霸王Matrix板
    int WNB303ResetPIN = 14;      //  設定 WNB303 重置腳位為輸出腳位
    int WNB303PowerPIN = 15;      //  設定 WNB303 電源控制腳位為輸出腳位
    
    // ------ 以下修改成你MQTT設定 ------
    String MQTTServer = "mqttgo.io";//免註冊MQTT伺服器
    String MQTTPort = "1883";//MQTT Port
    String MQTTUser = "";//不須帳密
    String MQTTPassword = "";//不須帳密
    String MQTTPubTopic = "YourTopic/class402/SoilWater";//推播主題:推播土壤濕度(記得改成你自己的Topic)
    long MQTTLastPublishTime = 0;//此變數用來記錄推播時間
    long MQTTPublishInterval = 5000;//每5秒推撥一次
    
    void setup() {
      Serial.begin(115200);       //  設定序列埠監控視窗的鮑率
      Serial2.begin(115200);      //  設定 WNB303 的鮑率
      Wire.begin(26, 27);         //  Matrix I2C
      for (int i = 0; i <= 7; ++i) MatrixInt(i, 0);//關閉所有燈號
      pinMode(soil_sensor,INPUT); //定義土壤濕度感測器接口為輸入接口。
      pinMode(WNB303ResetPIN, OUTPUT);        //  設定 WNB303 電源控制腳位為輸出腳位
      pinMode(WNB303PowerPIN, OUTPUT);        //  設定 WNB303 重置腳位為輸出腳位
      delay(1000);
    
      Serial.println("\r\n\r\n======================\r\nSystem Starting....");
      String result = "";
      //  開啟 Modem 的電源,開啟關閉之間須間隔10秒(延時電路)
      WNB303Restart(10);
      //檢查網路註冊狀態,5分鐘內無法註冊,則重新啟動WNB303
      int tryCount = 0;
      while (1) {
        boolean resultb = WNB303CheckReg();
        Serial.print("WNB303CheckNetReg result="); Serial.println(resultb);
        if (resultb == false) {
          Serial.println("時間內無法註冊網路(" + String(tryCount) + ")");
          delay(10000);
        }
        else break;
        if (tryCount++ >= 30) { //無法註冊已經超過5分鐘
          tryCount = 0;
          WNB303Restart(30);
        }
      }
      //檢查網路訊號品質
      result = WNB303CheckRSSI();
      Serial.print("WNB303CheckRSSI result="); Serial.println(result);
      delay(10000);
    }
    
    void loop() {
    
      //檢查時間,傳輸步驟:檢查網路、讀取距離、MQTT連線、推播、關閉
      if ((millis() - MQTTLastPublishTime) >= MQTTPublishInterval ) {
        MatrixInt(7, 1);
        //沒有網路,則重新啟動WNB303
        String result = "";
        //檢查網路狀態
        if (!(WNB303CheckReg())) {
          WNB303Restart(60); //60秒後重新檢測網路
          return;
        }else result = WNB303CheckRSSI();
         
        //連線mqtt
        result = mqttConnect(MQTTServer, MQTTPort, MQTTUser, MQTTPassword);
        if (result == "OK") Serial.println("MQTT Connected");
      int val= analogRead(soil_sensor); //土壤濕度值給val
      Serial.print(val);
      Serial.println(" val");
         String payload = String((int)val);
        //推播訊息
        result = mqttPublish(MQTTPubTopic, "0", "0", "0", payload);
        if (result == "OK") Serial.println("Data:\"" + payload + "\" Published to " + MQTTPubTopic);
        //關閉mqtt
        result = mqttDisconnect();
        if (result == "OK") Serial.println("MQTT Disconnected");
        MQTTLastPublishTime = millis(); //更新最後傳輸時間
        MatrixInt(7, 0);
      }
      delay(1000);
    }
    
    //連線mqtt
    String mqttConnect(String Host, String Port, String MQTTUser, String MQTTPassword) {
      //1.取得IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      result = AT2WNB303("AT+EMQNEW=\"" + IP + "\",\"" + Port + "\"" + "," + 60000  + "," + 1024, "+EMQNEW:");
      String mqttid = split( result, ':', 1);
      //Serial.print("MQTTCreate result="); Serial.println(mqttid);
      //以亂數為ClientID
      String  MQTTClientid = "NBIoT-" + String(random(1000000, 9999999));
      result = AT2WNB303("AT+EMQCON=" + mqttid + ",3,\"" + MQTTClientid + "\"" + "," + 60000  + ",0,0,\"" + MQTTUser + "\",\"" + MQTTPassword + "\"", "OK");
      //Serial.print("MQTTConnect result="); Serial.println(result);
      return result;
    }
    
    //推播訊息
    String mqttPublish(String Topic, String QoS, String retained, String dup , String Payload) {
      String result = "" ;
      String hexPayload = Str2Hex(Payload);
      String lenHexPayload = String(hexPayload.length());
      result = AT2WNB303("AT+EMQPUB=0," + Topic + "," + QoS + "," + retained + "," + dup + "," + lenHexPayload + "," + hexPayload, "OK");
      return result;
    }
    
    //關閉mqtt連線
    String mqttDisconnect() {
      String result = "" ;
      result = AT2WNB303("AT+EMQDISCON=0", "OK");
      return result;
    }
    
    //檢查網路註冊狀態 return true or false
    boolean WNB303CheckReg() {
      String result = "";
      boolean CEREG = false;
      result = AT2WNB303("AT+CEREG?", "+CEREG:");
      if (result.indexOf("0,1") >= 0 || result.indexOf("1,1") >= 0) { //註冊成功
        MatrixInt(5, 0);//亮紅燈
        MatrixInt(6, 1);//亮綠燈
        CEREG = true;
      }
      else {
        MatrixInt(5, 1);//亮紅燈
        MatrixInt(6, 0);//亮綠燈
        CEREG = false;
      }
      return CEREG;
    }
    
    //檢查網路訊號品質 return RSSI,當RSSI=0或99代表沒訊號
    int WNB303CheckRSSI() {
      String result = "";
      int RSSI = 0;
      result = AT2WNB303("AT+CESQ", "+CESQ:");
      //處理+CESQ:
      if (!(result == "-1")) {
        int CESQ = split(split(result, ':', 1), ',', 0).toInt();
        RSSI = CESQ - 111;
      }
      if (RSSI == -111 || RSSI == 210) RSSI = 0;
      MatrixLEDrssi(RSSI);
      return RSSI;
    }
    
    //重新啟動WNB303(單位為秒)
    void WNB303Restart(int dalayTime) {
      AT2WNB303("POWEROFF", "");
      delay(5000);
      AT2WNB303("POWERON", "");
      delay(dalayTime * 1000) ;
    }
    
    
    
    //HTTP GET
    String HTTPGET(String Protocol, String Host, String port, String Url) {
      //例如 http://x.x.x.x/update?api_key=xxxxx&field1=60
      //拆解成Protocol="http" host="x.x.x.x" port="80" Url="/update?api_key=CxxxxxxJ&field1=60"
      //1.轉換網址IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      String PIP = Protocol + "://" + IP + ":" + port + "/";
      int PIPlen = PIP.length();
      //Serial.println("PIP=" + PIP + ",len=" + String(PIPlen));
      result = AT2WNB303("AT+EHTTPCREATE=0," + String(PIPlen) + "," + String(PIPlen) + ",\"" + PIP + "\"", "+EHTTPCREAT");
      result.trim(); String clientid = split(result, ':', 1);
      if (result == "") return "Error: Can't Create Connection";
      else {
        //3.開啟連線
        result = AT2WNB303("AT+EHTTPCON=" + clientid, "OK");
        result.trim();
        if (!(result == "OK")) result = "Error: Can't Connect to Server";
        //4.組成網址並傳送
        int LenUrl = Url.length();
        Url = clientid + ",0," + String(LenUrl) + "," + Url + ",0,,0,,0,";
        Url = "0," + String(Url.length()) + "," + String(Url.length()) + "," + Url;
        result = AT2WNB303("AT+EHTTPSEND=" + Url, "OK");
        if (!(result == "OK")) result = "Error: Can't Send to Server";
      }
      delay(1000);
      //關閉連線
      AT2WNB303("AT+EHTTPDISCON=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      AT2WNB303("AT+EHTTPDESTROY=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      return result;
    }
    
    //HTTP POST
    String HTTPPOST(String Protocol, String Host, String port, String Url , String contType , String Data) {
      //1.轉換網址IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      String PIP = Protocol + "://" + IP + ":" + port + "/";
      int PIPlen = PIP.length();
      //Serial.println("PIP=" + PIP + ",len=" + String(PIPlen));
      result = AT2WNB303("AT+EHTTPCREATE=0," + String(PIPlen) + "," + String(PIPlen) + ",\"" + PIP + "\"", "+EHTTPCREAT");
      result.trim(); String clientid = split(result, ':', 1);
      if (result == "") return "Error: Can't Create Connection";
      else {
        //3.開啟連線
        result = AT2WNB303("AT+EHTTPCON=" + clientid, "OK");
        result.trim();
        if (!(result == "OK")) result = "Error: Can't Connect to Server";
        //4.組成網址並傳送
        int i = 0;
        String PostCommand[10];
        PostCommand[i++] = clientid + ",1," + Url.length() + "," + Url + ",0,," + contType.length() + "," + contType + ",";
        //Serial.println("command1=" + PostCommand[i - 1]);
        String hexData = Str2Hex(Data);
        int lenHexData = hexData.length();
        PostCommand[i++] = String(lenHexData) + ",";
        //Serial.println("command2=" + PostCommand[i - 1]);
        int num = 30;
        for (int n = 0; n < lenHexData; n = n + num) {
          String DataSend = "";
          if (n + num < lenHexData) {
            //切割字串
            DataSend = hexData.substring(n, n + num);
          } else if (lenHexData % num > 0) {
            int remainder = lenHexData % num;
            //切割字串
            DataSend = hexData.substring(n, n + remainder);
          }
          PostCommand[i++] = DataSend;
          //Serial.println("command2=" + PostCommand[i - 1]);
        }
        //求出每條命令長度
        int totalLenHexData = 0;
        for (int j = 0; j <= i - 1; j++) {
          totalLenHexData = totalLenHexData + PostCommand[j].length();
          PostCommand[j] = String(PostCommand[j].length()) + "," + PostCommand[j];
        }
        //完成命令組合
        for (int j = 0; j <= i - 1; j++) {
          if (j == 1) PostCommand[j] = "AT+EHTTPSEND=1," + String(totalLenHexData) + "," + PostCommand[j];
          else if (j == i - 1) PostCommand[j] = "AT+EHTTPSEND=0," + String(totalLenHexData) + "," + PostCommand[j];
          else PostCommand[j] = "AT+EHTTPSEND=1," + String(totalLenHexData) + "," + PostCommand[j];
          result = AT2WNB303(PostCommand[j], "OK");
          //Serial.println("POST" + String(j) + + ":" + result);
        }
    
      }
      delay(1000);
      //關閉連線
      AT2WNB303("AT+EHTTPDISCON=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      AT2WNB303("AT+EHTTPDESTROY=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      return result;
    }
    
    //將訊息傳到WNB303,並讀取回傳訊息 0代表timeout
    String AT2WNB303(String ATdata, String StartWith) {
      Serial.println("你的命令是:" + ATdata);
      if (ATdata.length() > 0) { //送出AT命令
        ATdata.trim();
        String command = ATdata;
        command.toUpperCase();
    
        if (command == "RESET") {  //重置 WNB303
          digitalWrite(WNB303ResetPIN, HIGH);
          delay(10000);
          digitalWrite(WNB303ResetPIN, LOW);
          return "RESET OK";
        }
        else if (command == "POWERON") {  //開啟 WNB303 的電源
          digitalWrite(WNB303PowerPIN, HIGH);
          return "POWERON OK";
        }
        else if (command == "POWEROFF") {  //關閉 WNB303 的電源
          digitalWrite(WNB303PowerPIN, LOW);
          return "POWEROFF OK";
        }
        else  {  //送出AT命令
          Serial2.println(ATdata);
        }
      }
      else return "";
      String result = "";
      //等候回應資料
      long StartTime = millis();
      while (1) {
        result = "";
        while (Serial2.available()) { //WNB303有資料回傳
          char c = Serial2.read();    //從WNB303讀取一個位元組
          result += c;                //將讀到的字元 c 加進字串 Xfer
          if (c == '\n') break;
        }
        result.trim();
        if (result.startsWith(StartWith)) break; //結尾OK返回
        if ((millis() - StartTime) >= WNB303Timeout ) { //Timeout返回
          result = "0";
          break;
        }
      }
      return result;
    }
    
    //字串轉HEX
    String Str2Hex(String msg) {
      String a = "";
      for (int i = 0; i < msg.length(); i++)  {
        a = a + String(msg.charAt(i), HEX);
      }
      return a;
    }
    
    //HEX轉字串
    String Hex2Str(String msg) {
      char input[msg.length() + 1];
      msg.toCharArray(input, msg.length() + 1);
      char c[sizeof(input)];
      String a = "";
      for (int i = 0; i < sizeof(input) - 1; i += 2) {
        char temp[3];
        temp[0] = input[i];
        temp[1] = input[i + 1];
        int val = ASCIIHexToInt(temp[0]) * 16 + ASCIIHexToInt(temp[1]);
        c[i] = toascii(val);
        a = a + String(c[i]);
      }
      return a;
    }
    
    //ASC轉INT
    int ASCIIHexToInt(char c) {
      int ret = 0;
      if ((c >= '0') && (c <= '9')) ret = (ret << 4) + c - '0';
      else ret = (ret << 4) + toupper(c) - 'A' + 10;
      return ret;
    }
    
    //split拆解,範例:String a1=split(“aa,bb,cc”,’,’,0);
    String split(String data, char separator, int index) {
      int found = 0;
      int strIndex[] = { 0, -1 };
      int maxIndex = data.length() - 1;
      for (int i = 0; i <= maxIndex && found <= index; i++) {
        if (data.charAt(i) == separator || i == maxIndex) {
          found++;
          strIndex[0] = strIndex[1] + 1;
          strIndex[1] = (i == maxIndex) ? i + 1 : i;
        }
      }
      return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
    }
    
    
    土壤濕度感測器 nb-iot esp32 土壤濕度感測器

  • 土壤濕度感測器-MQTT
    adminA admin

    2.土壤溼度感測器-MQTT.pdf

    #include <WiFi.h>
    #include <PubSubClient.h> //請先安裝PubSubClient程式庫
    
    // ------ 以下修改成你自己的WiFi帳號密碼 ------
    char* ssid = "YourSSID";
    char* password = "YourPASSWORD";
    //------ 以下修改成你的土壤濕度感測器腳位 ------
    int soil_sensor = 36; //土壤濕度感測器AO信號腳 連接到ESP32 GPIO36
    
    // ------ 以下修改成你MQTT設定 ------
    char* MQTTServer = "broker.mqttgo.io";//免註冊MQTT伺服器
    int MQTTPort = 1883;//MQTT Port
    char* MQTTUser = "";//不須帳密
    char* MQTTPassword = "";//不須帳密
    //推播主題1:推播土壤濕度(記得改Topic)
    char* MQTTPubTopic1 = "YourTopic/class402/SoilWater";
    long MQTTLastPublishTime;//此變數用來記錄推播時間
    long MQTTPublishInterval = 3000;//每3秒推撥一次
    WiFiClient WifiClient;
    PubSubClient MQTTClient(WifiClient);
    
    void setup() {
      Serial.begin(115200); //Set console baud rate
      pinMode(soil_sensor,INPUT); //定義土壤濕度感測器接口為輸入接口。
    
    
      //開始WiFi連線
      WifiConnecte();
    
      //開始MQTT連線
      MQTTConnecte();
    }
    
    void loop() {
      //如果WiFi連線中斷,則重啟WiFi連線
      if (WiFi.status() != WL_CONNECTED) { WifiConnecte(); }
    
      //如果MQTT連線中斷,則重啟MQTT連線
      if (!MQTTClient.connected()) {  MQTTConnecte(); }
    
      //如果距離上次傳輸已經超過1秒,則Publish距離
      if ((millis() - MQTTLastPublishTime) >= MQTTPublishInterval ) {
       
      int val= analogRead(soil_sensor); //土壤濕度值給val
      Serial.print(val);
      Serial.println(" val");
        // ------ 將距離送到MQTT主題 ------
        MQTTClient.publish(MQTTPubTopic1, String((int)val).c_str());
        Serial.println("土壤濕度已推播到MQTT Broker");
        MQTTLastPublishTime = millis(); //更新最後傳輸時間
      }
      MQTTClient.loop();//更新訂閱狀態
      delay(50);
    
      }
    
    
    
    //開始WiFi連線
    void WifiConnecte() {
      //開始WiFi連線
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("WiFi連線成功");
      Serial.print("IP Address:");
      Serial.println(WiFi.localIP());
    }
    
    //開始MQTT連線
    void MQTTConnecte() {
      MQTTClient.setServer(MQTTServer, MQTTPort);
      while (!MQTTClient.connected()) {
        //以亂數為ClietID
        String  MQTTClientid = "esp32-" + String(random(1000000, 9999999));
        if (MQTTClient.connect(MQTTClientid.c_str(), MQTTUser, MQTTPassword)) {
          //連結成功,顯示「已連線」。
          Serial.println("MQTT已連線");
    
        } else {
          //若連線不成功,則顯示錯誤訊息,並重新連線
          Serial.print("MQTT連線失敗,狀態碼=");
          Serial.println(MQTTClient.state());
          Serial.println("五秒後重新連線");
          delay(5000);
        }
      }
    }
    
    
    土壤濕度感測器 土壤濕度感測器 mqtt esp32

  • 土壤濕度感測器-序列埠視窗監控
    adminA admin

    1.土壤溼度感測器-序列埠視窗監控.pdf

    int soil_sensor = 36; //土壤濕度感測器AO信號腳 連接到ESP32 GPIO36
    
    void setup() {
      Serial.begin(115200); //Set console baud rate
      pinMode(soil_sensor,INPUT); //定義土壤濕度感測器接口為輸入接口。
    }
    
    void loop() {
      int val= analogRead(soil_sensor); //土壤濕度值給val
      Serial.print(val);
      Serial.println(" val");
    
      delay(1000);
    }
    
    土壤濕度感測器 土壤濕度感測器 序列埠視窗監控 esp32

  • 水位感測器-NB-IoT
    adminA admin

    4.水位感測器-NB-IoT.pdf

    #include <WiFi.h>
    #include <Wire.h>
    #include "MatrixInt.h" //安裝方式:https://www.nmking.io/index.php/2022/12/15/701/
    
    long WNB303Timeout = 10000; //返回0=Timeout
    int water_sensor=36; // 水位感測器S信號腳 連接到ESP32的 GPIO36 
    //使用小霸王Matrix板
    int WNB303ResetPIN = 14;      //  設定 WNB303 重置腳位為輸出腳位
    int WNB303PowerPIN = 15;      //  設定 WNB303 電源控制腳位為輸出腳位
    int a;
    // ------ 以下修改成你MQTT設定 ------
    String MQTTServer = "mqttgo.io";//免註冊MQTT伺服器
    String MQTTPort = "1883";//MQTT Port
    String MQTTUser = "";//不須帳密
    String MQTTPassword = "";//不須帳密
    String MQTTPubTopic = "YourTopic/class402/WaterLevel";//推播主題:推播水位(記得改成你自己的Topic)
    long MQTTLastPublishTime = 0;//此變數用來記錄推播時間
    long MQTTPublishInterval = 5000;//每5秒推撥一次
    
    void setup() {
      Serial.begin(115200);       //  設定序列埠監控視窗的鮑率
      Serial2.begin(115200);      //  設定 WNB303 的鮑率
      Wire.begin(26, 27);         //  Matrix I2C
      for (int i = 0; i <= 7; ++i) MatrixInt(i, 0);//關閉所有燈號
      pinMode(water_sensor,INPUT); //設置water_sensor對應的腳GPIO36為輸入
      pinMode(WNB303ResetPIN, OUTPUT);        //  設定 WNB303 電源控制腳位為輸出腳位
      pinMode(WNB303PowerPIN, OUTPUT);        //  設定 WNB303 重置腳位為輸出腳位
      delay(1000);
    
      Serial.println("\r\n\r\n======================\r\nSystem Starting....");
      String result = "";
      //  開啟 Modem 的電源,開啟關閉之間須間隔10秒(延時電路)
      WNB303Restart(10);
      //檢查網路註冊狀態,5分鐘內無法註冊,則重新啟動WNB303
      int tryCount = 0;
      while (1) {
        boolean resultb = WNB303CheckReg();
        Serial.print("WNB303CheckNetReg result="); Serial.println(resultb);
        if (resultb == false) {
          Serial.println("時間內無法註冊網路(" + String(tryCount) + ")");
          delay(10000);
        }
        else break;
        if (tryCount++ >= 30) { //無法註冊已經超過5分鐘
          tryCount = 0;
          WNB303Restart(30);
        }
      }
      //檢查網路訊號品質
      result = WNB303CheckRSSI();
      Serial.print("WNB303CheckRSSI result="); Serial.println(result);
      delay(10000);
    }
    
    void loop() {
    
      //檢查時間,傳輸步驟:檢查網路、讀取距離、MQTT連線、推播、關閉
      if ((millis() - MQTTLastPublishTime) >= MQTTPublishInterval ) {
        MatrixInt(7, 1);
        //沒有網路,則重新啟動WNB303
        String result = "";
        //檢查網路狀態
        if (!(WNB303CheckReg())) {
          WNB303Restart(60); //60秒後重新檢測網路
          return;
        }else result = WNB303CheckRSSI();
         
        //連線mqtt
        result = mqttConnect(MQTTServer, MQTTPort, MQTTUser, MQTTPassword);
        if (result == "OK") Serial.println("MQTT Connected");
      int val=analogRead(water_sensor); //從水位感測器讀出類比數值
      a=map(val,0,4095,0,100);          //將val轉換成百分比顯示
      Serial.print("水位狀態:");
      Serial.print(val);
      Serial.println(" val");
      Serial.print("水位百分比:");
      Serial.print(a);
      Serial.println(" %");
         String payload = String((int)a);
        //推播訊息
        result = mqttPublish(MQTTPubTopic, "0", "0", "0", payload);
        if (result == "OK") Serial.println("Data:\"" + payload + "\" Published to " + MQTTPubTopic);
        //關閉mqtt
        result = mqttDisconnect();
        if (result == "OK") Serial.println("MQTT Disconnected");
        MQTTLastPublishTime = millis(); //更新最後傳輸時間
        MatrixInt(7, 0);
      }
      delay(1000);
    }
    
    //連線mqtt
    String mqttConnect(String Host, String Port, String MQTTUser, String MQTTPassword) {
      //1.取得IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      result = AT2WNB303("AT+EMQNEW=\"" + IP + "\",\"" + Port + "\"" + "," + 60000  + "," + 1024, "+EMQNEW:");
      String mqttid = split( result, ':', 1);
      //Serial.print("MQTTCreate result="); Serial.println(mqttid);
      //以亂數為ClientID
      String  MQTTClientid = "NBIoT-" + String(random(1000000, 9999999));
      result = AT2WNB303("AT+EMQCON=" + mqttid + ",3,\"" + MQTTClientid + "\"" + "," + 60000  + ",0,0,\"" + MQTTUser + "\",\"" + MQTTPassword + "\"", "OK");
      //Serial.print("MQTTConnect result="); Serial.println(result);
      return result;
    }
    
    //推播訊息
    String mqttPublish(String Topic, String QoS, String retained, String dup , String Payload) {
      String result = "" ;
      String hexPayload = Str2Hex(Payload);
      String lenHexPayload = String(hexPayload.length());
      result = AT2WNB303("AT+EMQPUB=0," + Topic + "," + QoS + "," + retained + "," + dup + "," + lenHexPayload + "," + hexPayload, "OK");
      return result;
    }
    
    //關閉mqtt連線
    String mqttDisconnect() {
      String result = "" ;
      result = AT2WNB303("AT+EMQDISCON=0", "OK");
      return result;
    }
    
    //檢查網路註冊狀態 return true or false
    boolean WNB303CheckReg() {
      String result = "";
      boolean CEREG = false;
      result = AT2WNB303("AT+CEREG?", "+CEREG:");
      if (result.indexOf("0,1") >= 0 || result.indexOf("1,1") >= 0) { //註冊成功
        MatrixInt(5, 0);//亮紅燈
        MatrixInt(6, 1);//亮綠燈
        CEREG = true;
      }
      else {
        MatrixInt(5, 1);//亮紅燈
        MatrixInt(6, 0);//亮綠燈
        CEREG = false;
      }
      return CEREG;
    }
    
    //檢查網路訊號品質 return RSSI,當RSSI=0或99代表沒訊號
    int WNB303CheckRSSI() {
      String result = "";
      int RSSI = 0;
      result = AT2WNB303("AT+CESQ", "+CESQ:");
      //處理+CESQ:
      if (!(result == "-1")) {
        int CESQ = split(split(result, ':', 1), ',', 0).toInt();
        RSSI = CESQ - 111;
      }
      if (RSSI == -111 || RSSI == 210) RSSI = 0;
      MatrixLEDrssi(RSSI);
      return RSSI;
    }
    
    //重新啟動WNB303(單位為秒)
    void WNB303Restart(int dalayTime) {
      AT2WNB303("POWEROFF", "");
      delay(5000);
      AT2WNB303("POWERON", "");
      delay(dalayTime * 1000) ;
    }
    
    
    
    //HTTP GET
    String HTTPGET(String Protocol, String Host, String port, String Url) {
      //例如 http://x.x.x.x/update?api_key=xxxxx&field1=60
      //拆解成Protocol="http" host="x.x.x.x" port="80" Url="/update?api_key=CxxxxxxJ&field1=60"
      //1.轉換網址IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      String PIP = Protocol + "://" + IP + ":" + port + "/";
      int PIPlen = PIP.length();
      //Serial.println("PIP=" + PIP + ",len=" + String(PIPlen));
      result = AT2WNB303("AT+EHTTPCREATE=0," + String(PIPlen) + "," + String(PIPlen) + ",\"" + PIP + "\"", "+EHTTPCREAT");
      result.trim(); String clientid = split(result, ':', 1);
      if (result == "") return "Error: Can't Create Connection";
      else {
        //3.開啟連線
        result = AT2WNB303("AT+EHTTPCON=" + clientid, "OK");
        result.trim();
        if (!(result == "OK")) result = "Error: Can't Connect to Server";
        //4.組成網址並傳送
        int LenUrl = Url.length();
        Url = clientid + ",0," + String(LenUrl) + "," + Url + ",0,,0,,0,";
        Url = "0," + String(Url.length()) + "," + String(Url.length()) + "," + Url;
        result = AT2WNB303("AT+EHTTPSEND=" + Url, "OK");
        if (!(result == "OK")) result = "Error: Can't Send to Server";
      }
      delay(1000);
      //關閉連線
      AT2WNB303("AT+EHTTPDISCON=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      AT2WNB303("AT+EHTTPDESTROY=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      return result;
    }
    
    //HTTP POST
    String HTTPPOST(String Protocol, String Host, String port, String Url , String contType , String Data) {
      //1.轉換網址IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      String PIP = Protocol + "://" + IP + ":" + port + "/";
      int PIPlen = PIP.length();
      //Serial.println("PIP=" + PIP + ",len=" + String(PIPlen));
      result = AT2WNB303("AT+EHTTPCREATE=0," + String(PIPlen) + "," + String(PIPlen) + ",\"" + PIP + "\"", "+EHTTPCREAT");
      result.trim(); String clientid = split(result, ':', 1);
      if (result == "") return "Error: Can't Create Connection";
      else {
        //3.開啟連線
        result = AT2WNB303("AT+EHTTPCON=" + clientid, "OK");
        result.trim();
        if (!(result == "OK")) result = "Error: Can't Connect to Server";
        //4.組成網址並傳送
        int i = 0;
        String PostCommand[10];
        PostCommand[i++] = clientid + ",1," + Url.length() + "," + Url + ",0,," + contType.length() + "," + contType + ",";
        //Serial.println("command1=" + PostCommand[i - 1]);
        String hexData = Str2Hex(Data);
        int lenHexData = hexData.length();
        PostCommand[i++] = String(lenHexData) + ",";
        //Serial.println("command2=" + PostCommand[i - 1]);
        int num = 30;
        for (int n = 0; n < lenHexData; n = n + num) {
          String DataSend = "";
          if (n + num < lenHexData) {
            //切割字串
            DataSend = hexData.substring(n, n + num);
          } else if (lenHexData % num > 0) {
            int remainder = lenHexData % num;
            //切割字串
            DataSend = hexData.substring(n, n + remainder);
          }
          PostCommand[i++] = DataSend;
          //Serial.println("command2=" + PostCommand[i - 1]);
        }
        //求出每條命令長度
        int totalLenHexData = 0;
        for (int j = 0; j <= i - 1; j++) {
          totalLenHexData = totalLenHexData + PostCommand[j].length();
          PostCommand[j] = String(PostCommand[j].length()) + "," + PostCommand[j];
        }
        //完成命令組合
        for (int j = 0; j <= i - 1; j++) {
          if (j == 1) PostCommand[j] = "AT+EHTTPSEND=1," + String(totalLenHexData) + "," + PostCommand[j];
          else if (j == i - 1) PostCommand[j] = "AT+EHTTPSEND=0," + String(totalLenHexData) + "," + PostCommand[j];
          else PostCommand[j] = "AT+EHTTPSEND=1," + String(totalLenHexData) + "," + PostCommand[j];
          result = AT2WNB303(PostCommand[j], "OK");
          //Serial.println("POST" + String(j) + + ":" + result);
        }
    
      }
      delay(1000);
      //關閉連線
      AT2WNB303("AT+EHTTPDISCON=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      AT2WNB303("AT+EHTTPDESTROY=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      return result;
    }
    
    //將訊息傳到WNB303,並讀取回傳訊息 0代表timeout
    String AT2WNB303(String ATdata, String StartWith) {
      Serial.println("你的命令是:" + ATdata);
      if (ATdata.length() > 0) { //送出AT命令
        ATdata.trim();
        String command = ATdata;
        command.toUpperCase();
    
        if (command == "RESET") {  //重置 WNB303
          digitalWrite(WNB303ResetPIN, HIGH);
          delay(10000);
          digitalWrite(WNB303ResetPIN, LOW);
          return "RESET OK";
        }
        else if (command == "POWERON") {  //開啟 WNB303 的電源
          digitalWrite(WNB303PowerPIN, HIGH);
          return "POWERON OK";
        }
        else if (command == "POWEROFF") {  //關閉 WNB303 的電源
          digitalWrite(WNB303PowerPIN, LOW);
          return "POWEROFF OK";
        }
        else  {  //送出AT命令
          Serial2.println(ATdata);
        }
      }
      else return "";
      String result = "";
      //等候回應資料
      long StartTime = millis();
      while (1) {
        result = "";
        while (Serial2.available()) { //WNB303有資料回傳
          char c = Serial2.read();    //從WNB303讀取一個位元組
          result += c;                //將讀到的字元 c 加進字串 Xfer
          if (c == '\n') break;
        }
        result.trim();
        if (result.startsWith(StartWith)) break; //結尾OK返回
        if ((millis() - StartTime) >= WNB303Timeout ) { //Timeout返回
          result = "0";
          break;
        }
      }
      return result;
    }
    
    //字串轉HEX
    String Str2Hex(String msg) {
      String a = "";
      for (int i = 0; i < msg.length(); i++)  {
        a = a + String(msg.charAt(i), HEX);
      }
      return a;
    }
    
    //HEX轉字串
    String Hex2Str(String msg) {
      char input[msg.length() + 1];
      msg.toCharArray(input, msg.length() + 1);
      char c[sizeof(input)];
      String a = "";
      for (int i = 0; i < sizeof(input) - 1; i += 2) {
        char temp[3];
        temp[0] = input[i];
        temp[1] = input[i + 1];
        int val = ASCIIHexToInt(temp[0]) * 16 + ASCIIHexToInt(temp[1]);
        c[i] = toascii(val);
        a = a + String(c[i]);
      }
      return a;
    }
    
    //ASC轉INT
    int ASCIIHexToInt(char c) {
      int ret = 0;
      if ((c >= '0') && (c <= '9')) ret = (ret << 4) + c - '0';
      else ret = (ret << 4) + toupper(c) - 'A' + 10;
      return ret;
    }
    
    //split拆解,範例:String a1=split(“aa,bb,cc”,’,’,0);
    String split(String data, char separator, int index) {
      int found = 0;
      int strIndex[] = { 0, -1 };
      int maxIndex = data.length() - 1;
      for (int i = 0; i <= maxIndex && found <= index; i++) {
        if (data.charAt(i) == separator || i == maxIndex) {
          found++;
          strIndex[0] = strIndex[1] + 1;
          strIndex[1] = (i == maxIndex) ? i + 1 : i;
        }
      }
      return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
    }
    
    
    水位感測器 esp32 nb-iot 水位感測器

  • 水位感測器-MQTT
    adminA admin

    2.水位感測器-MQTT.pdf

    #include <WiFi.h>
    #include <PubSubClient.h> //請先安裝PubSubClient程式庫
    
    // ------ 以下修改成你自己的WiFi帳號密碼 ------
    char* ssid = "YourSSID";
    char* password = "YourPASSWORD";
    //------ 以下修改成你的水位感測器腳位 ------
    int water_sensor=36; // 水位感測器S信號腳 連接到ESP32的 GPIO36 
    int a;
    // ------ 以下修改成你MQTT設定 ------
    char* MQTTServer = "broker.mqttgo.io";//免註冊MQTT伺服器
    int MQTTPort = 1883;//MQTT Port
    char* MQTTUser = "";//不須帳密
    char* MQTTPassword = "";//不須帳密
    //推播主題1:推播水位(記得改Topic)
    char* MQTTPubTopic1 = "YourTopic/class402/WaterLevel";
    long MQTTLastPublishTime;//此變數用來記錄推播時間
    long MQTTPublishInterval = 3000;//每3秒推撥一次
    WiFiClient WifiClient;
    PubSubClient MQTTClient(WifiClient);
    
    void setup() {
      Serial.begin(115200); //Set console baud rate
      pinMode(water_sensor,INPUT); //設置water_sensor對應的腳GPIO36為輸入
    
    
      //開始WiFi連線
      WifiConnecte();
    
      //開始MQTT連線
      MQTTConnecte();
    }
    
    void loop() {
      //如果WiFi連線中斷,則重啟WiFi連線
      if (WiFi.status() != WL_CONNECTED) { WifiConnecte(); }
    
      //如果MQTT連線中斷,則重啟MQTT連線
      if (!MQTTClient.connected()) {  MQTTConnecte(); }
    
      //如果距離上次傳輸已經超過1秒,則Publish距離
      if ((millis() - MQTTLastPublishTime) >= MQTTPublishInterval ) {
       
      int val=analogRead(water_sensor); //從水位感測器讀出類比數值
      a=map(val,0,4095,0,100);          //將val轉換成百分比顯示
      Serial.print("水位狀態:");
      Serial.print(val);
      Serial.println(" val");
      Serial.print("水位百分比:");
      Serial.print(a);
      Serial.println(" %");
        // ------ 將水位送到MQTT主題 ------
        MQTTClient.publish(MQTTPubTopic1, String((int)a).c_str());
        Serial.println("水位已推播到MQTT Broker");
        MQTTLastPublishTime = millis(); //更新最後傳輸時間
      }
      MQTTClient.loop();//更新訂閱狀態
      delay(50);
    
      }
    
    
    
    //開始WiFi連線
    void WifiConnecte() {
      //開始WiFi連線
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("WiFi連線成功");
      Serial.print("IP Address:");
      Serial.println(WiFi.localIP());
    }
    
    //開始MQTT連線
    void MQTTConnecte() {
      MQTTClient.setServer(MQTTServer, MQTTPort);
      while (!MQTTClient.connected()) {
        //以亂數為ClietID
        String  MQTTClientid = "esp32-" + String(random(1000000, 9999999));
        if (MQTTClient.connect(MQTTClientid.c_str(), MQTTUser, MQTTPassword)) {
          //連結成功,顯示「已連線」。
          Serial.println("MQTT已連線");
    
        } else {
          //若連線不成功,則顯示錯誤訊息,並重新連線
          Serial.print("MQTT連線失敗,狀態碼=");
          Serial.println(MQTTClient.state());
          Serial.println("五秒後重新連線");
          delay(5000);
        }
      }
    }
    
    
    水位感測器 esp32 mqtt 水位感測器

  • 水位感測器-序列埠視窗監控
    adminA admin

    1.水位感測器-序列埠視窗監控.pdf

    int water_sensor=36; // 水位感測器S信號腳 連接到ESP32的 GPIO36 
    int a;
    
    void setup()    
    {   
      Serial.begin(115200);
      pinMode(water_sensor,INPUT); //設置water_sensor對應的腳GPIO36為輸入
    }    
          
    void loop()  
    {
      int val=analogRead(water_sensor); //從水位感測器讀出類比數值
      a=map(val,0,4095,0,100);          //將val轉換成百分比顯示
      Serial.print("水位狀態:");
      Serial.print(val);
      Serial.println(" val");
      Serial.print("水位百分比:");
      Serial.print(a);
      Serial.println(" %");
     
      delay(1000);
    }
    
    水位感測器 esp32 水位感測器 序列埠視窗監控

  • 溶氧感測器-校正方法
    adminA admin

    1.溶氧感測器 校正方法.pdf

    #include <Arduino.h>
    
    #define VREF    5000//VREF(mv)
    #define ADC_RES 4096//ADC Resolution
    
    uint32_t raw;
    
    void setup()
    {
        Serial.begin(115200);
    }
    
    void loop()
    {
        raw=analogRead(36);
        Serial.println("raw:\t"+String(raw)+"\tVoltage(mv)"+String(raw*VREF/ADC_RES));
        delay(1000);
    }
    
    溶氧感測器

  • 溶氧感測器-NB-IoT
    adminA admin

    5.溶氧感測器 序列埠監控視窗 NB-IoT.pdf

    #define DO_PIN 36
    
    #define VREF 5000    //VREF (mv)
    #define ADC_RES 4096 //ADC Resolution
    
    //Single-point calibration Mode=0
    //Two-point calibration Mode=1
    #define TWO_POINT_CALIBRATION 0
    
    #define READ_TEMP (25) //Current water temperature ℃, Or temperature sensor function
    
    //Single point calibration needs to be filled CAL1_V and CAL1_T
    #define CAL1_V (1600) //mv
    #define CAL1_T (25)   //℃
    //Two-point calibration needs to be filled CAL2_V and CAL2_T
    //CAL1 High temperature point, CAL2 Low temperature point
    #define CAL2_V (1300) //mv
    #define CAL2_T (15)   //℃
    
    const uint16_t DO_Table[41] = {
        14460, 14220, 13820, 13440, 13090, 12740, 12420, 12110, 11810, 11530,
        11260, 11010, 10770, 10530, 10300, 10080, 9860, 9660, 9460, 9270,
        9080, 8900, 8730, 8570, 8410, 8250, 8110, 7960, 7820, 7690,
        7560, 7430, 7300, 7180, 7070, 6950, 6840, 6730, 6630, 6530, 6410};
    
    uint8_t Temperaturet;
    uint16_t ADC_Raw;
    uint16_t ADC_Voltage;
    uint16_t DO;
    
    int16_t readDO(uint32_t voltage_mv, uint8_t temperature_c)
    {
    #if TWO_POINT_CALIBRATION == 0
      uint16_t V_saturation = (uint32_t)CAL1_V + (uint32_t)35 * temperature_c - (uint32_t)CAL1_T * 35;
      return (voltage_mv * DO_Table[temperature_c] / V_saturation);
    #else
      uint16_t V_saturation = (int16_t)((int8_t)temperature_c - CAL2_T) * ((uint16_t)CAL1_V - CAL2_V) / ((uint8_t)CAL1_T - CAL2_T) + CAL2_V;
      return (voltage_mv * DO_Table[temperature_c] / V_saturation);
    #endif
    }
    double DOSensor;
    //-------
    #include <Wire.h>
    #include "MatrixInt.h" //安裝方式:https://www.nmking.io/index.php/2022/12/15/701/
    // ------ 以下修改成你MQTT設定 ------
    long WNB303Timeout = 10000; //返回0=Timeout
    //使用小霸王Matrix板
    int WNB303ResetPIN = 14;   //  設定 WNB303 重置腳位為輸出腳位
    int WNB303PowerPIN = 15;   //  設定 WNB303 電源控制腳位為輸出腳位
    
    // ------ 以下修改成你MQTT設定 ------
    String MQTTServer = "mqttgo.io";//免註冊MQTT伺服器
    String MQTTPort = "1883";//MQTT Port
    String MQTTUser = "";//不須帳密
    String MQTTPassword = "";//不須帳密
    String MQTTPubTopic = "YourTopic/class/WaterDO";
    long MQTTLastPublishTime = 0;//此變數用來記錄推播時間
    long MQTTPublishInterval = 10000;//每10秒推撥一次
    
    // ----------
    void ReadDO()
    {
      Temperaturet = (uint8_t)READ_TEMP;
      ADC_Raw = analogRead(DO_PIN);
      ADC_Voltage = uint32_t(VREF) * ADC_Raw / ADC_RES;
      DOSensor = ((double)(readDO(ADC_Voltage, Temperaturet))/1000);
      Serial.print("Temperature:\t" + String(Temperaturet) + "\t");
      Serial.print("ADC RAW:\t" + String(ADC_Raw) + "\t");
      Serial.print("ADC Voltage:\t" + String(ADC_Voltage) + "\t");
      Serial.println("DO:\t" + String(readDO(ADC_Voltage, Temperaturet)) + "\t");
      Serial.print("目前溶氧:");
      Serial.println( String(DOSensor) + " mg/L");  
    
      delay(1000);
    }
    
    void setup() {
      Serial.begin(115200);       //  設定序列埠監控視窗的鮑率
      Serial2.begin(115200);      //  設定 WNB303 的鮑率
      Wire.begin(26, 27);         //  Matrix I2C
      for (int i = 0; i <= 7; ++i) MatrixInt(i, 0);//關閉所有燈號
      pinMode(WNB303ResetPIN, OUTPUT);        //  設定 WNB303 電源控制腳位為輸出腳位
      pinMode(WNB303PowerPIN, OUTPUT);        //  設定 WNB303 重置腳位為輸出腳位
      delay(1000);
    
      Serial.println("\r\n\r\n======================\r\nSystem Starting....");
      String result = "";
      //  開啟 Modem 的電源,開啟關閉之間須間隔10秒(延時電路)
      WNB303Restart(10);
      //檢查網路註冊狀態,5分鐘內無法註冊,則重新啟動WNB303
      int tryCount = 0;
      while (1) {
        boolean resultb = WNB303CheckReg();
        Serial.print("WNB303CheckNetReg result="); Serial.println(resultb);
        if (resultb == false) {
          Serial.println("時間內無法註冊網路(" + String(tryCount) + ")");
          delay(10000);
        }
        else break;
        if (tryCount++ >= 30) { //無法註冊已經超過5分鐘
          tryCount = 0;
          WNB303Restart(30);
        }
      }
      //檢查網路訊號品質
      result = WNB303CheckRSSI();
      Serial.print("WNB303CheckRSSI result="); Serial.println(result);
      delay(10000);
    }
    
    void loop() {
    
      if ((millis() - MQTTLastPublishTime) >= MQTTPublishInterval ) {
        MatrixInt(7, 1);
        //沒有網路,則重新啟動WNB303
        String result = "";
        //檢查網路狀態
        if (!(WNB303CheckReg())) {
          WNB303Restart(60); //60秒後重新檢測網路
          return;
        }else result = WNB303CheckRSSI();
        //讀取溶氧量
        ReadDO();
    
        //連線mqtt
        result = mqttConnect(MQTTServer, MQTTPort, MQTTUser, MQTTPassword);
        if (result == "OK") Serial.println("MQTT Connected");
        String payload = String(DOSensor);
        //推播訊息
        result = mqttPublish(MQTTPubTopic, "0", "0", "0", payload);
        if (result == "OK") Serial.println("Data:\"" + payload + "\" Published to " + MQTTPubTopic);
        //關閉mqtt
        result = mqttDisconnect();
        if (result == "OK") Serial.println("MQTT Disconnected");
        MQTTLastPublishTime = millis(); //更新最後傳輸時間
        MatrixInt(7, 0);
      }
      delay(1000);
    }
    
    
    //連線mqtt
    String mqttConnect(String Host, String Port, String MQTTUser, String MQTTPassword) {
      //1.取得IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      result = AT2WNB303("AT+EMQNEW=\"" + IP + "\",\"" + Port + "\"" + "," + 60000  + "," + 1024, "+EMQNEW:");
      String mqttid = split( result, ':', 1);
      //Serial.print("MQTTCreate result="); Serial.println(mqttid);
      //以亂數為ClientID
      String  MQTTClientid = "NBIoT-" + String(random(1000000, 9999999));
      result = AT2WNB303("AT+EMQCON=" + mqttid + ",3,\"" + MQTTClientid + "\"" + "," + 60000  + ",0,0,\"" + MQTTUser + "\",\"" + MQTTPassword + "\"", "OK");
      //Serial.print("MQTTConnect result="); Serial.println(result);
      return result;
    }
    
    //推播訊息
    String mqttPublish(String Topic, String QoS, String retained, String dup , String Payload) {
      String result = "" ;
      String hexPayload = Str2Hex(Payload);
      String lenHexPayload = String(hexPayload.length());
      result = AT2WNB303("AT+EMQPUB=0," + Topic + "," + QoS + "," + retained + "," + dup + "," + lenHexPayload + "," + hexPayload, "OK");
      return result;
    }
    
    //關閉mqtt連線
    String mqttDisconnect() {
      String result = "" ;
      result = AT2WNB303("AT+EMQDISCON=0", "OK");
      return result;
    }
    
    //檢查網路註冊狀態 return true or false
    boolean WNB303CheckReg() {
      String result = "";
      boolean CEREG = false;
      result = AT2WNB303("AT+CEREG?", "+CEREG:");
      if (result.indexOf("0,1") >= 0 || result.indexOf("1,1") >= 0) { //註冊成功
        MatrixInt(5, 0);//亮紅燈
        MatrixInt(6, 1);//亮綠燈
        CEREG = true;
      }
      else {
        MatrixInt(5, 1);//亮紅燈
        MatrixInt(6, 0);//亮綠燈
        CEREG = false;
      }
      return CEREG;
    }
    
    //檢查網路訊號品質 return RSSI,當RSSI=0或99代表沒訊號
    int WNB303CheckRSSI() {
      String result = "";
      int RSSI = 0;
      result = AT2WNB303("AT+CESQ", "+CESQ:");
      //處理+CESQ:
      if (!(result == "-1")) {
        int CESQ = split(split(result, ':', 1), ',', 0).toInt();
        RSSI = CESQ - 111;
      }
      if (RSSI == -111 || RSSI == 210) RSSI = 0;
      MatrixLEDrssi(RSSI);
      return RSSI;
    }
    
    //重新啟動WNB303(單位為秒)
    void WNB303Restart(int dalayTime) {
      AT2WNB303("POWEROFF", "");
      delay(5000);
      AT2WNB303("POWERON", "");
      delay(dalayTime * 1000) ;
    }
    
    //HTTP GET
    String HTTPGET(String Protocol, String Host, String port, String Url) {
      //例如 http://x.x.x.x/update?api_key=xxxxx&field1=60
      //拆解成Protocol="http" host="x.x.x.x" port="80" Url="/update?api_key=CxxxxxxJ&field1=60"
      //1.轉換網址IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      String PIP = Protocol + "://" + IP + ":" + port + "/";
      int PIPlen = PIP.length();
      //Serial.println("PIP=" + PIP + ",len=" + String(PIPlen));
      result = AT2WNB303("AT+EHTTPCREATE=0," + String(PIPlen) + "," + String(PIPlen) + ",\"" + PIP + "\"", "+EHTTPCREAT");
      result.trim(); String clientid = split(result, ':', 1);
      if (result == "") return "Error: Can't Create Connection";
      else {
        //3.開啟連線
        result = AT2WNB303("AT+EHTTPCON=" + clientid, "OK");
        result.trim();
        if (!(result == "OK")) result = "Error: Can't Connect to Server";
        //4.組成網址並傳送
        int LenUrl = Url.length();
        Url = clientid + ",0," + String(LenUrl) + "," + Url + ",0,,0,,0,";
        Url = "0," + String(Url.length()) + "," + String(Url.length()) + "," + Url;
        result = AT2WNB303("AT+EHTTPSEND=" + Url, "OK");
        if (!(result == "OK")) result = "Error: Can't Send to Server";
      }
      delay(1000);
      //關閉連線
      AT2WNB303("AT+EHTTPDISCON=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      AT2WNB303("AT+EHTTPDESTROY=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      return result;
    }
    
    //HTTP POST
    String HTTPPOST(String Protocol, String Host, String port, String Url , String contType , String Data) {
      //1.轉換網址IP
      String result = "" ;
      String IP = AT2WNB303("AT+EDNS=\"" + Host + "\"", "+EDNS:");
      IP.trim(); IP = split( IP, ':', 1);
      if (IP.length() <= 7) return "Error: Can't Get IP";
      //2.建立連線
      String PIP = Protocol + "://" + IP + ":" + port + "/";
      int PIPlen = PIP.length();
      //Serial.println("PIP=" + PIP + ",len=" + String(PIPlen));
      result = AT2WNB303("AT+EHTTPCREATE=0," + String(PIPlen) + "," + String(PIPlen) + ",\"" + PIP + "\"", "+EHTTPCREAT");
      result.trim(); String clientid = split(result, ':', 1);
      if (result == "") return "Error: Can't Create Connection";
      else {
        //3.開啟連線
        result = AT2WNB303("AT+EHTTPCON=" + clientid, "OK");
        result.trim();
        if (!(result == "OK")) result = "Error: Can't Connect to Server";
        //4.組成網址並傳送
        int i = 0;
        String PostCommand[10];
        PostCommand[i++] = clientid + ",1," + Url.length() + "," + Url + ",0,," + contType.length() + "," + contType + ",";
        //Serial.println("command1=" + PostCommand[i - 1]);
        String hexData = Str2Hex(Data);
        int lenHexData = hexData.length();
        PostCommand[i++] = String(lenHexData) + ",";
        //Serial.println("command2=" + PostCommand[i - 1]);
        int num = 30;
        for (int n = 0; n < lenHexData; n = n + num) {
          String DataSend = "";
          if (n + num < lenHexData) {
            //切割字串
            DataSend = hexData.substring(n, n + num);
          } else if (lenHexData % num > 0) {
            int remainder = lenHexData % num;
            //切割字串
            DataSend = hexData.substring(n, n + remainder);
          }
          PostCommand[i++] = DataSend;
          //Serial.println("command2=" + PostCommand[i - 1]);
        }
        //求出每條命令長度
        int totalLenHexData = 0;
        for (int j = 0; j <= i - 1; j++) {
          totalLenHexData = totalLenHexData + PostCommand[j].length();
          PostCommand[j] = String(PostCommand[j].length()) + "," + PostCommand[j];
        }
        //完成命令組合
        for (int j = 0; j <= i - 1; j++) {
          if (j == 1) PostCommand[j] = "AT+EHTTPSEND=1," + String(totalLenHexData) + "," + PostCommand[j];
          else if (j == i - 1) PostCommand[j] = "AT+EHTTPSEND=0," + String(totalLenHexData) + "," + PostCommand[j];
          else PostCommand[j] = "AT+EHTTPSEND=1," + String(totalLenHexData) + "," + PostCommand[j];
          result = AT2WNB303(PostCommand[j], "OK");
          //Serial.println("POST" + String(j) + + ":" + result);
        }
    
      }
      delay(1000);
      //關閉連線
      AT2WNB303("AT+EHTTPDISCON=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      AT2WNB303("AT+EHTTPDESTROY=" + clientid, "OK");
      //Serial.println(result);
      delay(1000);
      return result;
    }
    
    //將訊息傳到WNB303,並讀取回傳訊息 0代表timeout
    String AT2WNB303(String ATdata, String StartWith) {
      Serial.println("你的命令是:" + ATdata);
      if (ATdata.length() > 0) { //送出AT命令
        ATdata.trim();
        String command = ATdata;
        command.toUpperCase();
    
        if (command == "RESET") {  //重置 WNB303
          digitalWrite(WNB303ResetPIN, HIGH);
          delay(10000);
          digitalWrite(WNB303ResetPIN, LOW);
          return "RESET OK";
        }
        else if (command == "POWERON") {  //開啟 WNB303 的電源
          digitalWrite(WNB303PowerPIN, HIGH);
          return "POWERON OK";
        }
        else if (command == "POWEROFF") {  //關閉 WNB303 的電源
          digitalWrite(WNB303PowerPIN, LOW);
          return "POWEROFF OK";
        }
        else  {  //送出AT命令
          Serial2.println(ATdata);
        }
      }
      else return "";
      String result = "";
      //等候回應資料
      long StartTime = millis();
      while (1) {
        result = "";
        while (Serial2.available()) { //WNB303有資料回傳
          char c = Serial2.read();    //從WNB303讀取一個位元組
          result += c;                //將讀到的字元 c 加進字串 Xfer
          if (c == '\n') break;
        }
        result.trim();
        if (result.startsWith(StartWith)) break; //結尾OK返回
        if ((millis() - StartTime) >= WNB303Timeout ) { //Timeout返回
          result = "0";
          break;
        }
      }
      return result;
    }
    
    //字串轉HEX
    String Str2Hex(String msg) {
      String a = "";
      for (int i = 0; i < msg.length(); i++)  {
        a = a + String(msg.charAt(i), HEX);
      }
      return a;
    }
    
    //HEX轉字串
    String Hex2Str(String msg) {
      char input[msg.length() + 1];
      msg.toCharArray(input, msg.length() + 1);
      char c[sizeof(input)];
      String a = "";
      for (int i = 0; i < sizeof(input) - 1; i += 2) {
        char temp[3];
        temp[0] = input[i];
        temp[1] = input[i + 1];
        int val = ASCIIHexToInt(temp[0]) * 16 + ASCIIHexToInt(temp[1]);
        c[i] = toascii(val);
        a = a + String(c[i]);
      }
      return a;
    }
    
    //ASC轉INT
    int ASCIIHexToInt(char c) {
      int ret = 0;
      if ((c >= '0') && (c <= '9')) ret = (ret << 4) + c - '0';
      else ret = (ret << 4) + toupper(c) - 'A' + 10;
      return ret;
    }
    
    //split拆解,範例:String a1=split(“aa,bb,cc”,’,’,0);
    String split(String data, char separator, int index) {
      int found = 0;
      int strIndex[] = { 0, -1 };
      int maxIndex = data.length() - 1;
      for (int i = 0; i <= maxIndex && found <= index; i++) {
        if (data.charAt(i) == separator || i == maxIndex) {
          found++;
          strIndex[0] = strIndex[1] + 1;
          strIndex[1] = (i == maxIndex) ? i + 1 : i;
        }
      }
      return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
    }```
    溶氧感測器 溶氧感測器 nb-iot esp32

  • 溶氧感測器-MQTT
    adminA admin

    3.溶氧感測器 序列埠監控視窗-MQTT.pdf

    #define DO_PIN 36
    
    #define VREF 5000    //VREF (mv)
    #define ADC_RES 4096 //ADC Resolution
    
    //Single-point calibration Mode=0
    //Two-point calibration Mode=1
    #define TWO_POINT_CALIBRATION 0
    
    #define READ_TEMP (25) //Current water temperature ℃, Or temperature sensor function
    
    //Single point calibration needs to be filled CAL1_V and CAL1_T
    #define CAL1_V (1600) //mv
    #define CAL1_T (25)   //℃
    //Two-point calibration needs to be filled CAL2_V and CAL2_T
    //CAL1 High temperature point, CAL2 Low temperature point
    #define CAL2_V (1300) //mv
    #define CAL2_T (15)   //℃
    
    const uint16_t DO_Table[41] = {
        14460, 14220, 13820, 13440, 13090, 12740, 12420, 12110, 11810, 11530,
        11260, 11010, 10770, 10530, 10300, 10080, 9860, 9660, 9460, 9270,
        9080, 8900, 8730, 8570, 8410, 8250, 8110, 7960, 7820, 7690,
        7560, 7430, 7300, 7180, 7070, 6950, 6840, 6730, 6630, 6530, 6410};
    
    uint8_t Temperaturet;
    uint16_t ADC_Raw;
    uint16_t ADC_Voltage;
    uint16_t DO;
    
    int16_t readDO(uint32_t voltage_mv, uint8_t temperature_c)
    {
    #if TWO_POINT_CALIBRATION == 0
      uint16_t V_saturation = (uint32_t)CAL1_V + (uint32_t)35 * temperature_c - (uint32_t)CAL1_T * 35;
      return (voltage_mv * DO_Table[temperature_c] / V_saturation);
    #else
      uint16_t V_saturation = (int16_t)((int8_t)temperature_c - CAL2_T) * ((uint16_t)CAL1_V - CAL2_V) / ((uint8_t)CAL1_T - CAL2_T) + CAL2_V;
      return (voltage_mv * DO_Table[temperature_c] / V_saturation);
    #endif
    }
    double DOSensor;
    // ---------
    #include <WiFi.h>
    #include <PubSubClient.h> //請先安裝PubSubClient程式庫
    
    // ------ 以下修改成你自己的WiFi帳號密碼 ------
    char* ssid = "YourSSID";
    char* password = "YourPassword";
    // ------ 以下修改成你MQTT設定 ------
    char* MQTTServer = "broker.mqttgo.io";//免註冊MQTT伺服器
    int MQTTPort = 1883;//MQTT Port
    char* MQTTUser = "";//不須帳密
    char* MQTTPassword = "";//不須帳密
    //推播主題1:推播溶氧量(記得改Topic)
    char* MQTTPubTopic1 = "YourTopic/class402/WaterDO";
    long MQTTLastPublishTime;//此變數用來記錄推播時間
    long MQTTPublishInterval = 10000;//每10秒推撥一次
    WiFiClient WifiClient;
    PubSubClient MQTTClient(WifiClient);
    
    void setup() {
      Serial.begin(115200);
    
      //開始WiFi連線
      WifiConnecte();
    
      //開始MQTT連線
      MQTTConnecte();
    }
    
    void loop() {
      //如果WiFi連線中斷,則重啟WiFi連線
      if (WiFi.status() != WL_CONNECTED) { WifiConnecte(); }
    
      //如果MQTT連線中斷,則重啟MQTT連線
      if (!MQTTClient.connected()) {  MQTTConnecte(); }
    
      //如果距離上次傳輸已經超過10秒,則Publish溶氧量
      if ((millis() - MQTTLastPublishTime) >= MQTTPublishInterval ) {
        //讀取溫濕度
      Temperaturet = (uint8_t)READ_TEMP;
      ADC_Raw = analogRead(DO_PIN);
      ADC_Voltage = uint32_t(VREF) * ADC_Raw / ADC_RES;
      DOSensor = ((double)(readDO(ADC_Voltage, Temperaturet))/1000);
      Serial.print("Temperature:\t" + String(Temperaturet) + "\t");
      Serial.print("ADC RAW:\t" + String(ADC_Raw) + "\t");
      Serial.print("ADC Voltage:\t" + String(ADC_Voltage) + "\t");
      Serial.println("DO:\t" + String(readDO(ADC_Voltage, Temperaturet)) + "\t");
      Serial.print("目前溶氧:");
      Serial.println( String(DOSensor) + " mg/L");  
        // ------ 將溶氧量送到MQTT主題 ------
        MQTTClient.publish(MQTTPubTopic1, String(DOSensor).c_str());
        Serial.println("溶氧量已推播到MQTT Broker");
        MQTTLastPublishTime = millis(); //更新最後傳輸時間
      }
      MQTTClient.loop();//更新訂閱狀態
      delay(50);
    }
    
    
    //開始WiFi連線
    void WifiConnecte() {
      //開始WiFi連線
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      Serial.println("WiFi連線成功");
      Serial.print("IP Address:");
      Serial.println(WiFi.localIP());
    }
    
    //開始MQTT連線
    void MQTTConnecte() {
      MQTTClient.setServer(MQTTServer, MQTTPort);
      while (!MQTTClient.connected()) {
        //以亂數為ClietID
        String  MQTTClientid = "esp32-" + String(random(1000000, 9999999));
        if (MQTTClient.connect(MQTTClientid.c_str(), MQTTUser, MQTTPassword)) {
          //連結成功,顯示「已連線」。
          Serial.println("MQTT已連線");
    
        } else {
          //若連線不成功,則顯示錯誤訊息,並重新連線
          Serial.print("MQTT連線失敗,狀態碼=");
          Serial.println(MQTTClient.state());
          Serial.println("五秒後重新連線");
          delay(5000);
        }
      }
    }
    
    溶氧感測器 溶氧感測器 mqtt esp32

  • 溶氧感測器-序列埠監控視窗
    adminA admin

    2.溶氧感測器 序列埠監控視窗.pdf

    #define DO_PIN 36
    
    #define VREF 5000    //VREF (mv)
    #define ADC_RES 4096 //ADC Resolution
    
    //Single-point calibration Mode=0
    //Two-point calibration Mode=1
    #define TWO_POINT_CALIBRATION 0
    
    #define READ_TEMP (25) //Current water temperature ℃, Or temperature sensor function
    
    //Single point calibration needs to be filled CAL1_V and CAL1_T
    #define CAL1_V (1600) //mv
    #define CAL1_T (25)   //℃
    //Two-point calibration needs to be filled CAL2_V and CAL2_T
    //CAL1 High temperature point, CAL2 Low temperature point
    #define CAL2_V (1300) //mv
    #define CAL2_T (15)   //℃
    
    const uint16_t DO_Table[41] = {
        14460, 14220, 13820, 13440, 13090, 12740, 12420, 12110, 11810, 11530,
        11260, 11010, 10770, 10530, 10300, 10080, 9860, 9660, 9460, 9270,
        9080, 8900, 8730, 8570, 8410, 8250, 8110, 7960, 7820, 7690,
        7560, 7430, 7300, 7180, 7070, 6950, 6840, 6730, 6630, 6530, 6410};
    
    uint8_t Temperaturet;
    uint16_t ADC_Raw;
    uint16_t ADC_Voltage;
    uint16_t DO;
    
    int16_t readDO(uint32_t voltage_mv, uint8_t temperature_c)
    {
    #if TWO_POINT_CALIBRATION == 0
      uint16_t V_saturation = (uint32_t)CAL1_V + (uint32_t)35 * temperature_c - (uint32_t)CAL1_T * 35;
      return (voltage_mv * DO_Table[temperature_c] / V_saturation);
    #else
      uint16_t V_saturation = (int16_t)((int8_t)temperature_c - CAL2_T) * ((uint16_t)CAL1_V - CAL2_V) / ((uint8_t)CAL1_T - CAL2_T) + CAL2_V;
      return (voltage_mv * DO_Table[temperature_c] / V_saturation);
    #endif
    }
    double DOSensor;
    
    void setup()
    {
      Serial.begin(115200);
    }
    
    void loop()
    {
      Temperaturet = (uint8_t)READ_TEMP;
      ADC_Raw = analogRead(DO_PIN);
      ADC_Voltage = uint32_t(VREF) * ADC_Raw / ADC_RES;
      DOSensor = ((double)(readDO(ADC_Voltage, Temperaturet))/1000);
      Serial.print("Temperature:\t" + String(Temperaturet) + "\t");
      Serial.print("ADC RAW:\t" + String(ADC_Raw) + "\t");
      Serial.print("ADC Voltage:\t" + String(ADC_Voltage) + "\t");
      Serial.println("DO:\t" + String(readDO(ADC_Voltage, Temperaturet)) + "\t");
      Serial.print("目前溶氧:");
      Serial.println( String(DOSensor) + " mg/L");  
    
      delay(1000);
    }```
    溶氧感測器 esp32 溶氧感測器 序列埠監控視窗

  • AHT15-數據回傳序列埠
    adminA admin

    AHT15溫濕度感測器數據回傳序列埠_教案.pdf

    #include <Wire.h>  // 匯入Wire函式庫,用於I2C通訊
    
    #define AHT15_ADDRESS 0x38  // 定義AHT15感測器的I2C地址
    #define AHT15_RESET 0xBA  // 定義重置命令的值
    #define AHT15_INIT 0xBE  // 定義初始化命令的值
    #define AHT15_START_MEASUREMENT 0xAC  // 定義開始測量命令的值
    
    void setup() {  // 設定函數,在程式開始時執行一次
      Wire.begin();  // 啟用Wire函式庫
      Serial.begin(115200);  // 啟動序列通訊鮑率115200
      
      // Reset sensor
      Wire.beginTransmission(AHT15_ADDRESS);  // 開始向AHT15_ADDRESS發送數據
      Wire.write(AHT15_RESET);  // 發送重置命令
      if (Wire.endTransmission() != 0) {  // 如果傳輸結束並返回錯誤
        Serial.println("重置錯誤");  // 顯示錯誤信息
        while(1);  // 進入無窮迴圈
      }
      delay(20);  // 等待20毫秒
      
      // Initialize sensor
      Wire.beginTransmission(AHT15_ADDRESS);  // 開始向AHT15_ADDRESS發送數據
      Wire.write(AHT15_INIT);  // 發送初始化命令
      Wire.write(0x08);  // 發送額外的初始化數據
      Wire.write(0x00);  // 發送額外的初始化數據
      if (Wire.endTransmission() != 0) {  // 如果傳輸結束並返回錯誤
        Serial.println("初始化錯誤");  // 顯示錯誤信息
        while(1);  // 進入無窮迴圈
      }
      delay(10);  // 等待10毫秒
    }
    
    void loop() {  // 主迴圈,會不斷重複執行
      // Start measurement
      Wire.beginTransmission(AHT15_ADDRESS);  // 開始向AHT15_ADDRESS發送數據
      Wire.write(AHT15_START_MEASUREMENT);  // 發送開始測量命令
      Wire.write(0x33);  // 發送額外的開始測量數據
      Wire.write(0x00);  // 發送額外的開始測量數據
      if (Wire.endTransmission() != 0) {  // 如果傳輸結束並返回錯誤
        Serial.println("測量失敗");  // 顯示錯誤信息
        delay(1000);  // 等待1000毫秒
        return;  // 返回,跳過此次迴圈的剩餘部分
      }
      delay(80);  // 等待80毫秒以完成測量
      
      // Read data
      Wire.requestFrom(AHT15_ADDRESS, 6);  // 從AHT15_ADDRESS請求6個字節的數據
      if (Wire.available() != 6) {  // 如果可用數據不是6個字節
        Serial.println("讀取錯誤");  // 顯示錯誤信息
        return;  // 返回,跳過此次迴圈的剩餘部分
      }
      uint8_t data[6];  // 創建一個用於存儲數據的陣列
      for (int i = 0; i < 6; i++) {  // 對於每個字節
        data[i] = Wire.read();  // 讀取並存儲數據
      }
      
      // Calculate humidity and temperature
      uint32_t rawHumidity = ((uint32_t)data[1] << 12) | ((uint32_t)data[2] << 4) | (data[3] >> 4);  // 計算原始濕度值
      float humidity = rawHumidity * 100.0 / (1 << 20);  // 轉換原始濕度值為百分比
      
      uint32_t rawTemperature = (((uint32_t)data[3] & 0xF) << 16) | ((uint32_t)data[4] << 8) | data[5];  // 計算原始溫度值
      float temperature = ((200.0 * rawTemperature) / (1 << 20)) - 50;  // 轉換原始溫度值為攝氏度
      
      // Print results
      Serial.print("Humidity: ");  // 顯示"濕度:"
      Serial.print(humidity);  // 顯示濕度值
      Serial.print("% , ");  // 顯示"% ,"
      Serial.print("Temperature: ");  // 顯示"溫度:"
      Serial.print(temperature);  // 顯示溫度值
      Serial.println("°C");  // 顯示"°C"
      
      delay(2000);  // 等待2000毫秒
    }
    
    AHT15溫濕度感測器 aht15 esp32 數據回傳序列埠

  • AHT15-簡易藍芽傳輸
    adminA admin

    ATH15溫濕度感測器_簡易藍牙傳輸_教案.pdf

    #include <Wire.h>
    #include <BluetoothSerial.h>  // 匯入藍牙序列通訊的函式庫
    
    #define AHT15_ADDRESS 0x38
    #define AHT15_RESET 0xBA
    #define AHT15_INIT 0xBE
    #define AHT15_START_MEASUREMENT 0xAC
    BluetoothSerial BT; // 宣告藍牙物件,名稱為BT
    
    void setup() {
      Wire.begin();
      Serial.begin(115200);
      BT.begin("Denny0628"); // 請改名例如英文+ 生日
      
      // Reset sensor
      Wire.beginTransmission(AHT15_ADDRESS);
      Wire.write(AHT15_RESET);
      Wire.endTransmission();
      delay(20);
      
      // Initialize sensor
      Wire.beginTransmission(AHT15_ADDRESS);
      Wire.write(AHT15_INIT);
      Wire.write(0x08);
      Wire.write(0x00);
      Wire.endTransmission();
      delay(10);
    }
    
    void loop() {
      // Start measurement
      Wire.beginTransmission(AHT15_ADDRESS);
      Wire.write(AHT15_START_MEASUREMENT);
      Wire.write(0x33);
      Wire.write(0x00);
      Wire.endTransmission();
      delay(80);
      
      // Read data
      Wire.requestFrom(AHT15_ADDRESS, 6);
      uint8_t data[6];
      for (int i = 0; i < 6; i++) {
        data[i] = Wire.read();
      }
      
      // Calculate humidity and temperature
      uint32_t rawHumidity = ((uint32_t)data[1] << 12) | ((uint32_t)data[2] << 4) | (data[3] >> 4);
      float humidity = rawHumidity * 100.0 / (1 << 20);
      
      uint32_t rawTemperature = (((uint32_t)data[3] & 0xF) << 16) | ((uint32_t)data[4] << 8) | data[5];
      float temperature = ((200.0 * rawTemperature) / (1 << 20)) - 50;
      
      // Print results in Serial Monitor
      Serial.print("Humidity: ");
      Serial.print(humidity);
      Serial.print("% , ");
      Serial.print("Temperature: ");
      Serial.print(temperature);
      Serial.println("°C");
    
      // 在藍牙上打印溫度和濕度
      BT.print(temperature); // 將溫度值透過藍牙傳輸
      BT.print("*C, "); 
      BT.print(humidity);  // 將濕度值透過藍牙傳輸
      BT.println(" H");
      delay(2500);
    }
    
    
    AHT15溫濕度感測器 esp32 aht15溫濕度感測器 藍芽傳輸
  • 登入

  • 沒有帳戶? 註冊

Powered by NodeBB Contributors
  • 第一個貼文
    最後的貼文
0
  • 版面
  • 最新
  • 標籤
  • 熱門
  • World
  • 使用者
  • 群組