2025年11月14日 星期五

8 Port Telegram 告警機

  8 Port Telegram 告警機



  • Wokwi Wi-Fi 設置 (Wokwi-GUEST / "")。

  • 硬編碼 的 8 組警報訊息內容。

  • 使用 HTTPClient 庫手動發送 Telegram 訊息。

  • 8 個輸入腳位 (INPUT_PULLUPLOW 觸發)。


#include <Arduino.h>
#include <WiFi.h>
#include <HTTPClient.h> // 使用 HTTPClient 庫手動發送 Telegram API 請求

// --- Wokwi Wi-Fi 設置 (硬編碼) ---
const char* ssid = "Wokwi-GUEST";
const char* password = "";

// --- 內定 Telegram 配置 (已替換為您的有效值) ---
const String DEFAULT_TELEGRAM_TOKEN = "8022700986:AAGymymK9_d1HcTGJWl3mtqHmilxB64_5Zw";
const String DEFAULT_CHAT_ID = "7965218469"; // Chat ID 建議使用 long 類型
// --- 硬體定義 ---
struct InputPin {
  int id;      // 警報訊息組編號 (1 to 8)
  int pin;     // 實際連接的 ESP32 GPIO
};

// 您的硬體連接定義
InputPin inputMap[] = {
  {1, 34}, {2, 35}, {3, 32}, {4, 33},
  {5, 25}, {6, 26}, {7, 27}, {8, 14}
};
const int NUM_INPUTS = sizeof(inputMap) / sizeof(inputMap[0]);

// --- 配置變數 ---
String telegramToken = DEFAULT_TELEGRAM_TOKEN;
String chatID = DEFAULT_CHAT_ID;
// 警報解除與持續旗標 (這裡預設關閉)
bool sendOnRelease = false;
bool sendOnPersist = false;

// 硬編碼 8 組警報訊息內容
String alarmMessages[NUM_INPUTS];

// --- 狀態變數 ---
int lastPinState[NUM_INPUTS];
unsigned long lastTriggerTime[NUM_INPUTS] = {0};
const unsigned long PERSIST_INTERVAL = 60000; // 警報持續發送間隔 (60 秒)

// ----------------------------------------------------
//                函式宣告
// ----------------------------------------------------
void initializeAlarmMessages();
void initializeInputs();
void connectWifi();
void checkAndSendAlarm(int index);
void sendTelegramMessage(const String& msg);


// ----------------------------------------------------
//                SETUP
// ----------------------------------------------------
void setup() {
  Serial.begin(115200);
  // 增加延遲,確保 Wokwi 核心啟動穩定
  delay(500);
  Serial.println("\n--- Wokwi ESP32 Alarm System Booting ---");
 
  // 1. 初始化 8 組警報訊息
  initializeAlarmMessages();
 
  // 2. 初始化輸入腳位 (設置為上拉輸入)
  initializeInputs();

  // 3. 連接 Wi-Fi
  connectWifi();

  Serial.println("System Ready.");
}


// ----------------------------------------------------
//                LOOP
// ----------------------------------------------------
void loop() {
  // 1. 確保 Wi-Fi 連線
  if (WiFi.status() != WL_CONNECTED) {
    connectWifi();
    delay(1000);
    return;
  }

  // 2. 監控硬體輸入
  for (int i = 0; i < NUM_INPUTS; i++) {
    checkAndSendAlarm(i);
  }

  delay(10);
}


// ----------------------------------------------------
//                配置與初始化
// ----------------------------------------------------

void initializeAlarmMessages() {
  // 設置 8 組警報訊息內容
  for (int i = 0; i < NUM_INPUTS; i++) {
    // 修正字串串接錯誤
    alarmMessages[i] = String("警報觸發測試第") +
                       (i + 1 < 10 ? "0" : "") +
                       String(i + 1) +
                       "組";
                       
    Serial.print("Alarm Message "); Serial.print(i + 1); Serial.print(": "); Serial.println(alarmMessages[i]);
  }
}

void initializeInputs() {
  for (int i = 0; i < NUM_INPUTS; i++) {
    // 設置為 INPUT_PULLUP,連接 LOW 時觸發
    pinMode(inputMap[i].pin, INPUT_PULLUP);
    lastPinState[i] = digitalRead(inputMap[i].pin);
  }
}

void connectWifi() {
  if (WiFi.status() == WL_CONNECTED) {
    return;
  }

  Serial.print("Connecting to Wokwi Wi-Fi SSID: ");
  Serial.println(ssid);
 
  WiFi.begin(ssid, password);

  int attempts = 0;
  while (WiFi.status() != WL_CONNECTED && attempts < 30) {
    delay(500);
    Serial.print(".");
    attempts++;
  }

  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\nWiFi Connected!");
    Serial.print("IP Address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("\nWiFi Connection Failed! Will retry in loop.");
  }
}

// ----------------------------------------------------
//                硬體與警報處理
// ----------------------------------------------------

void checkAndSendAlarm(int index) {
  int currentState = digitalRead(inputMap[index].pin);
  String message = alarmMessages[index];
  unsigned long currentTime = millis();
 
  // 警報觸發 (狀態從 HIGH 變為 LOW)
  if (lastPinState[index] == HIGH && currentState == LOW) {
    String triggerMsg = "[🚨 警報觸發] " + message + " (Port " + String(inputMap[index].id) + ")";
    sendTelegramMessage(triggerMsg);
    lastTriggerTime[index] = currentTime;

  // 警報解除 (狀態從 LOW 變為 HIGH)
  } else if (lastPinState[index] == LOW && currentState == HIGH) {
    if (sendOnRelease) {
      String releaseMsg = "[✅ 警報解除] " + message + " (Port " + String(inputMap[index].id) + ")";
      sendTelegramMessage(releaseMsg);
    }
    lastTriggerTime[index] = 0; // 重置計時器

  // 警報持續 (狀態持續為 LOW)
  } else if (lastPinState[index] == LOW && currentState == LOW) {
    if (sendOnPersist && (currentTime - lastTriggerTime[index] >= PERSIST_INTERVAL)) {
      String persistMsg = "[⚠️ 持續警告] " + message + " (Port " + String(inputMap[index].id) + ")";
      sendTelegramMessage(persistMsg);
      lastTriggerTime[index] = currentTime; // 更新發送時間
    }
  }

  // 更新狀態
  lastPinState[index] = currentState;
}

// ----------------------------------------------------
//                Telegram 函式 (使用 HTTPClient)
// ----------------------------------------------------

void sendTelegramMessage(const String& msg) {
  // 移除強制阻擋檢查,因為用戶已提供真實值

  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("Error: WiFi is not connected. Cannot send Telegram message.");
    return;
  }

  HTTPClient http;
 
  // URL 編碼訊息內容
  String encodedMsg = "";
  for (char c : msg) {
      if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
          encodedMsg += c;
      } else {
          encodedMsg += '%';
          if ((byte)c < 16) encodedMsg += '0';
          encodedMsg += String((byte)c, HEX);
      }
  }

  // 構建 Telegram API URL
  String telegramApiUrl = "https://api.telegram.org/bot" + telegramToken +
                          "/sendMessage?chat_id=" + chatID +
                          "&text=" + encodedMsg;

  http.begin(telegramApiUrl);
 
  Serial.print("Sending Telegram message...");
  int httpCode = http.GET(); // 發送 HTTP GET 請求

  if (httpCode > 0) {
    Serial.printf(" [HTTP Code: %d]\n", httpCode);
    if (httpCode == HTTP_CODE_OK) {
      Serial.println("Telegram API Success. Message sent.");
    } else {
      Serial.print("Telegram API Error. Response: ");
      Serial.println(http.getString());
    }
  } else {
    Serial.printf(" [HTTP Error: %s]\n", http.errorToString(httpCode).c_str());
  }

  http.end();
}


沒有留言:

張貼留言

ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite

 ESP32 (ESP-IDF in VS Code) MFRC522 + MQTT + PYTHON TKinter +SQLite  ESP32 VS Code 程式 ; PlatformIO Project Configuration File ; ;   Build op...