--- disqus: ahb0222 GA : G-VF9ZT413CG --- # LilyGo T-Call SIM 連接 MQTT & Node-Red & Telegram 製作遠端pH監測器(ESP32 SIM800L)_分享 > [color=#40f1ef][name=LHB阿好伯, 2021/07/16][:earth_africa:](https://www.facebook.com/LHB0222/) ###### tags: `MQTT` `Arduino` [TOC] ![](https://i.imgur.com/T5usIXC.jpg) 今天分享使用LilyGo T-Call連上我們手機使用的網路來製作物聯網的裝置 最後搭配MQTT & Node-Red & Telegram 製作遠端pH監測器 首先看一下今天的主角LilyGo T-Call 保留了許多腳位在後續使用上不用擔心不夠用 ![](https://i.imgur.com/4kQBVcA.jpg) ![](https://i.imgur.com/g7VWaVa.png) ![](https://i.imgur.com/q34hAzq.png) ![](https://i.imgur.com/WGYaUKP.png) [🌟LilyGo T-Call SIM800 系列🌟](https://github.com/Xinyuan-LilyGO/LilyGo-T-Call-SIM800) 後續我查了一下幾乎所有的IoT門號都要以公司的方式購買 最後選擇使用亞太最低的方案一個月只要49元來測試 後續程式碼中的APN應使用 **==gtnet==** 而非 Internet 後續相關程式碼參考[Connect ESP32 to Cloud MQTT Broker (TTGO T-Call ESP32 SIM800L)](https://randomnerdtutorials.com/esp32-cloud-mqtt-broker-sim800l/) 選擇適當的公用Cloud MQTT Broker 修改MQTT topic即可傳輸資料 [補充-MQTT 入門](/1UJl7NNvT6GdDq8KnnLQAQ) 🌟 ```cpp= #define pHSensorPin 35 //pH meter模擬輸入腳位 String msgStr = ""; String pHval2 = ""; char json[25]; // 選擇數據機: #define TINY_GSM_MODEM_SIM800 // Set serial for debug console (to the Serial Monitor, default speed 115200) #define SerialMon Serial // Set serial for AT commands #define SerialAT Serial1 // Define the serial console for debug prints, if needed #define TINY_GSM_DEBUG SerialMon // set GSM PIN, if any #define GSM_PIN "" int pHval; // Your GPRS credentials, if any const char apn[] = "gtnet"; // APN (example: internet.vodafone.pt) use https://wiki.apnchanger.org const char gprsUser[] = ""; const char gprsPass[] = ""; // SIM card PIN (leave empty, if not defined) const char simPIN[] = ""; // MQTT details const char* broker = "mqtt.eclipseprojects.io"; // Public IP address or domain name const char* mqttUsername = "REPLACE_WITH_YOUR_MQTT_USER"; // MQTT username const char* mqttPassword = "REPLACE_WITH_YOUR_MQTT_PASS"; // MQTT password //設定MQTT topic const char* topicpH = "topic/topic2"; // Define the serial console for debug prints, if needed //#define DUMP_AT_COMMANDS #include <Wire.h> #include <TinyGsmClient.h> #ifdef DUMP_AT_COMMANDS #include <StreamDebugger.h> StreamDebugger debugger(SerialAT, SerialMon); TinyGsm modem(debugger); #else TinyGsm modem(SerialAT); #endif #include <PubSubClient.h> //#include <Adafruit_Sensor.h> //#include <Adafruit_BME280.h> TinyGsmClient client(modem); PubSubClient mqtt(client); // TTGO T-Call pins #define MODEM_RST 5 #define MODEM_PWKEY 4 #define MODEM_POWER_ON 23 #define MODEM_TX 27 #define MODEM_RX 26 #define I2C_SDA 21 #define I2C_SCL 22 // BME280 pins //#define I2C_SDA_2 18 //#define I2C_SCL_2 19 #define OUTPUT_1 2 #define OUTPUT_2 15 uint32_t lastReconnectAttempt = 0; // I2C for SIM800 (to keep it running when powered from battery) TwoWire I2CPower = TwoWire(0); //TwoWire I2CBME = TwoWire(1); //Adafruit_BME280 bme; #define IP5306_ADDR 0x75 #define IP5306_REG_SYS_CTL0 0x00 float temperature = 0; float humidity = 0; long lastMsg = 0; bool setPowerBoostKeepOn(int en){ I2CPower.beginTransmission(IP5306_ADDR); I2CPower.write(IP5306_REG_SYS_CTL0); if (en) { I2CPower.write(0x37); // Set bit1: 1 enable 0 disable boost keep on } else { I2CPower.write(0x35); // 0x37 is default reg value } return I2CPower.endTransmission() == 0; } void mqttCallback(char* topic, byte* message, unsigned int len) { Serial.print("Message arrived on topic: "); Serial.print(topic); Serial.print(". Message: "); String messageTemp; for (int i = 0; i < len; i++) { Serial.print((char)message[i]); messageTemp += (char)message[i]; } Serial.println(); // Feel free to add more if statements to control more GPIOs with MQTT // If a message is received on the topic esp/output1, you check if the message is either "true" or "false". // Changes the output state according to the message if (String(topic) == topicOutput1) { Serial.print("Changing output to "); if(messageTemp == "true"){ Serial.println("true"); digitalWrite(OUTPUT_1, HIGH); } else if(messageTemp == "false"){ Serial.println("false"); digitalWrite(OUTPUT_1, LOW); } } else if (String(topic) == topicOutput2) { Serial.print("Changing output to "); if(messageTemp == "true"){ Serial.println("true"); digitalWrite(OUTPUT_2, HIGH); } else if(messageTemp == "false"){ Serial.println("false"); digitalWrite(OUTPUT_2, LOW); } } } boolean mqttConnect() { SerialMon.print("Connecting to "); SerialMon.print(broker); // Connect to MQTT Broker without username and password //boolean status = mqtt.connect("GsmClientN"); // Or, if you want to authenticate MQTT: boolean status = mqtt.connect("GsmClientN", mqttUsername, mqttPassword); if (status == false) { SerialMon.println(" fail"); ESP.restart(); return false; } SerialMon.println(" success"); mqtt.subscribe(topicOutput1); mqtt.subscribe(topicOutput2); return mqtt.connected(); } void setup() { // Set console baud rate SerialMon.begin(115200); delay(10); // Start I2C communication //I2CPower.begin(I2C_SDA, I2C_SCL, 400000); //I2CBME.begin(I2C_SDA_2, I2C_SCL_2, 400000); // Keep power when running from battery bool isOk = setPowerBoostKeepOn(1); SerialMon.println(String("IP5306 KeepOn ") + (isOk ? "OK" : "FAIL")); // Set modem reset, enable, power pins pinMode(MODEM_PWKEY, OUTPUT); pinMode(MODEM_RST, OUTPUT); pinMode(MODEM_POWER_ON, OUTPUT); digitalWrite(MODEM_PWKEY, LOW); digitalWrite(MODEM_RST, HIGH); digitalWrite(MODEM_POWER_ON, HIGH); pinMode(OUTPUT_1, OUTPUT); pinMode(OUTPUT_2, OUTPUT); SerialMon.println("Wait..."); // Set GSM module baud rate and UART pins SerialAT.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX); delay(6000); // Restart takes quite some time // To skip it, call init() instead of restart() SerialMon.println("Initializing modem..."); modem.restart(); // modem.init(); String modemInfo = modem.getModemInfo(); SerialMon.print("Modem Info: "); SerialMon.println(modemInfo); // Unlock your SIM card with a PIN if needed if ( GSM_PIN && modem.getSimStatus() != 3 ) { modem.simUnlock(GSM_PIN); } // You might need to change the BME280 I2C address, in our case it's 0x76 // if (!bme.begin(0x76, &I2CBME)) { // Serial.println("Could not find a valid BME280 sensor, check wiring!"); // while (1); // } SerialMon.print("Connecting to APN: "); SerialMon.print(apn); if (!modem.gprsConnect(apn, gprsUser, gprsPass)) { SerialMon.println(" fail"); ESP.restart(); } else { SerialMon.println(" OK"); } if (modem.isGprsConnected()) { SerialMon.println("GPRS connected"); } // MQTT Broker setup mqtt.setServer(broker, 1883); mqtt.setCallback(mqttCallback); } void loop() { if (!mqtt.connected()) { SerialMon.println("=== MQTT NOT CONNECTED ==="); // Reconnect every 10 seconds uint32_t t = millis(); if (t - lastReconnectAttempt > 10000L) { lastReconnectAttempt = t; if (mqttConnect()) { lastReconnectAttempt = 0; } } delay(100); return; } long now = millis(); if (now - lastMsg > 10000) { lastMsg = now; //讀取pH 模組腳位的電壓大小 pHval2 = analogRead(pHSensorPin); SerialMon.println(pHval2); // 把String字串轉換成字元陣列格式 pHval2.toCharArray(json, 25); // 發布MQTT主題與訊息 mqtt.publish(topicpH, json); // 清空MQTT訊息內容 pHval2 = ""; } mqtt.loop(); } ``` > [pH meter介紹](http://2018.igem.org/Team:NCKU_Tainan/pH_meter) 多數的教學範例都是將pH換算的公式放在程式碼中 但這這次使用到MQTT將原始數據傳到Node-Red後在處理我覺得更方便 而且後續的數據也可以更方便的傳送到Telegram、Line或是 google sheet [Node-RED 連結MQTT 資料上傳至 Google Sheet服務](/IZ2k09W8TSumVdrA-NBLsw) 這邊使用到了[node-red-contrib-telegrambot](https://flows.nodered.org/node/node-red-contrib-telegrambot)&[node-red-contrib-line-notify ](https://flows.nodered.org/node/node-red-contrib-line-notify)節點用於傳送訊息給Telegram和Line ![](https://i.imgur.com/SW8SOX1.png) 使用簡單的JS計算pH值 ![](https://i.imgur.com/S0xahe9.png) 輸出結果 ![](https://i.imgur.com/RPpEY4Y.png) ![](https://i.imgur.com/ATUxK6f.png) 🌟全文可以至下方連結觀看或是補充 https://hackmd.io/@LHB-0222/LilyGo_T-Call_1 全文分享至 https://www.facebook.com/LHB0222/ https://www.instagram.com/ahb0222/ 有疑問想討論的都歡迎於下方留言 喜歡的幫我分享給所有的朋友 \o/ 有所錯誤歡迎指教 # [:page_with_curl: 全部文章列表](https://hackmd.io/@LHB-0222/AllWritings) ![](https://i.imgur.com/nHEcVmm.jpg)