owned this note
owned this note
Published
Linked with GitHub
---
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]

今天分享使用LilyGo T-Call連上我們手機使用的網路來製作物聯網的裝置
最後搭配MQTT & Node-Red & Telegram 製作遠端pH監測器
首先看一下今天的主角LilyGo T-Call
保留了許多腳位在後續使用上不用擔心不夠用




[🌟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

使用簡單的JS計算pH值

輸出結果


🌟全文可以至下方連結觀看或是補充
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)
