---
# System prepended metadata

title: 110專題 智慧長照助手

---

# 110專題-結合靜電纖維之智慧醫療輔助系統

:desert_island: [暑假規劃](/O_Dlh_EJTeC-sR1vjF5V9Q)

## 硬體-設備、纖維
:::spoiler 9 個纖維判斷
```javascript=
// the number of the pushbutton pin
const int buttonPin1 = 15; 
const int buttonPin2 = 2;  
const int buttonPin3 = 4; 
const int buttonPin4 = 5; 
const int buttonPin5 = 18; 
const int buttonPin6 = 19; 
const int buttonPin7 = 21; 
const int buttonPin8 = 22; 
const int buttonPin9 = 23; 

// variable for reading the pushbutton status
int buttonState1 = 0;  
int buttonState2 = 0;
int buttonState3 = 0;
int buttonState4 = 0;
int buttonState5 = 0;
int buttonState6 = 0;
int buttonState7 = 0;
int buttonState8 = 0;
int buttonState9 = 0;

void setup() {
    // 監控視窗(Serial Monitor)設定為 115200
    Serial.begin(115200);
    // initialize the pushbutton pin as an input:
    pinMode(buttonPin1, INPUT);
    pinMode(buttonPin2, INPUT);
    pinMode(buttonPin3, INPUT);
    pinMode(buttonPin4, INPUT);
    pinMode(buttonPin5, INPUT);
    pinMode(buttonPin6, INPUT);
    pinMode(buttonPin7, INPUT);
    pinMode(buttonPin8, INPUT);
    pinMode(buttonPin9, INPUT);
}

void loop() {
    buttonState1 = digitalRead(buttonPin1);
    buttonState2 = digitalRead(buttonPin2);
    buttonState3 = digitalRead(buttonPin3);
    buttonState4 = digitalRead(buttonPin4);
    buttonState5 = digitalRead(buttonPin5);
    buttonState6 = digitalRead(buttonPin6);
    buttonState7 = digitalRead(buttonPin7);
    buttonState8 = digitalRead(buttonPin8);
    buttonState9 = digitalRead(buttonPin9);

    // 判斷哪一個纖維被按壓
    if (buttonState1 == HIGH) {
    Serial.print("a\n");
    } 
    else if(buttonState2 == HIGH){
    Serial.print("b\n");
    }
    else if(buttonState3 == HIGH){
    Serial.print("c\n");
    }
    else if(buttonState4 == HIGH){
    Serial.print("d\n");
    }
    else if(buttonState5 == HIGH){
    Serial.print("e\n");
    }
    else if(buttonState6 == HIGH){
    Serial.print("f\n");
    }
    else if(buttonState7 == HIGH){
    Serial.print("g\n");
    }
    else if(buttonState8 == HIGH){
    Serial.print("h\n");
    }
    else if(buttonState9 == HIGH){
    Serial.print("i\n");
    }
    else {
    Serial.print("No Touch\n");
    }
    delay(200);
}
```
![9個纖維](https://hackmd.io/_uploads/ByPisqK7A.jpg)
:::

:::spoiler ESP32 接收纖維訊號並修改文字檔內容

Arduino端-傳送:
```javascript=
#include <WiFi.h>

// Wi-Fi 相關設定
const char* ssid = "yy"; // 更改為你的Wi-Fi網路名稱
const char* password = "0975742550"; // 更改為你的Wi-Fi密碼
WiFiServer server(80);

// 按鈕設定
const int buttonPin1 = 15; 
const int buttonPin2 = 2;  
const int buttonPin3 = 4; 
const int buttonPin4 = 5; 
const int buttonPin5 = 18; 
const int buttonPin6 = 19; 
const int buttonPin7 = 21; 
const int buttonPin8 = 22; 
const int buttonPin9 = 23; 

int buttonPins[] = {buttonPin1, buttonPin2, buttonPin3, buttonPin4, buttonPin5, buttonPin6, buttonPin7, buttonPin8, buttonPin9};
char buttonMessages[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'};
const int numButtons = 9;

WiFiClient client;

void setup() {
    // initialize the pushbutton pin as an input:
    for (int i = 0; i < numButtons; i++) {
        pinMode(buttonPins[i], INPUT);
    }

    // 連接到Wi-Fi網路
    Serial.begin(115200);
    delay(10);
    Serial.println("\nConnecting to " + String(ssid));
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("\nWiFi connected.");

    // 開啟伺服器
    server.begin();
    Serial.println("Server started");

    // 顯示ESP32的IP位址
    Serial.println(WiFi.localIP());
}

void loop() {
    // 等待客戶端連接
    client = server.available();
    if (!client) {
        return;
    }

    // 檢查每個按鈕的狀態
    for (int i = 0; i < numButtons; i++) {
        if (digitalRead(buttonPins[i]) == HIGH) {
            // 發送對應按鈕的訊息給客戶端
            client.println(buttonMessages[i]);
            Serial.println(buttonMessages[i]);
            delay(1000); // 延遲一段時間以避免重複發送
        }
    }
}

```
python端-接收:
```javascript=
import socket

# ESP32 的 IP 位址和端口
ESP32_IP = "172.20.10.2"  # 更改為 ESP32 的 IP 位址
ESP32_PORT = 80

# 連接到 ESP32
esp32_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
esp32_socket.connect((ESP32_IP, ESP32_PORT))

print("trytxt.py已就緒")

# 接收來自 ESP32 的訊息並修改文件
while True:
    message = esp32_socket.recv(1024).decode("utf-8")
    if message == "a":
        with open("dec.txt", "w") as file:
            file.write("a")
        print("dec.txt updated with 'a'")
    elif message == "b":
        with open("dec.txt", "w") as file:
            file.write("b")
        print("dec.txt updated with 'b'")
    elif message == "c":
        with open("dec.txt", "w") as file:
            file.write("c")
        print("dec.txt updated with 'c'")
    elif message == "d":
        with open("dec.txt", "w") as file:
            file.write("d")
        print("dec.txt updated with 'd'")
    elif message == "e":
        with open("dec.txt", "w") as file:
            file.write("e")
        print("dec.txt updated with 'e'")
    elif message == "f":
        with open("dec.txt", "w") as file:
            file.write("f")
        print("dec.txt updated with 'f'")
    elif message == "g":
        with open("dec.txt", "w") as file:
            file.write("g")
        print("dec.txt updated with 'g'")
    elif message == "h":
        with open("dec.txt", "w") as file:
            file.write("h")
        print("dec.txt updated with 'h'")
    elif message == "i":
        with open("dec.txt", "w") as file:
            file.write("i")
        print("dec.txt updated with 'i'")
```

![ESP32判斷按鈕並修改文檔內容](https://hackmd.io/_uploads/r1tfwat7R.png)

::: danger
:warning: 遇到問題：每次都要按一下 python 端那邊的執行才會顯示目前觸碰到哪個按鈕。
:::

:::spoiler Heart Rate
```javascript=
#define USE_ARDUINO_INTERRUPTS true
#include <PulseSensorPlayground.h> // 包含 PulseSensorPlayground.h 庫
#include <WiFi.h>

// WiFi 設置
const char* ssid = "啊婷的iPhone";             // WiFi 網絡名稱
const char* password = "Bbbbb12252";     // WiFi 密碼

// TCP 伺服器設置
WiFiServer server(80);

const int PulseWire = 34;                   // 感測器訊號線連接 ESP32 的模擬輸入引腳
int Threshold = 550;                        // 設置門檻值

PulseSensorPlayground pulseSensor;          // 創建 PulseSensorPlayground 對象

int count = 1;                              // 用於計數有效的心跳數據
int sumBPM = 0;                             // 用於累加心跳數據

void setup() {
  Serial.begin(115200);                     // 初始化串列通訊
  delay(1000);                              // 延遲以確保串列監視器有時間打開
  Serial.println("Initializing Pulse Sensor...");

  // 連接 WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");
  Serial.println(WiFi.localIP());

  // 啟動 TCP 伺服器
  server.begin();

  pulseSensor.analogInput(PulseWire);       // 設置感測器的模擬輸入引腳
  pulseSensor.setThreshold(Threshold);      // 設置門檻值

  if (pulseSensor.begin()) {                // 啟動感測器
    Serial.println("PulseSensor object created successfully!");
  } else {
    Serial.println("Failed to initialize PulseSensor.");
  }
}

void loop() {
  WiFiClient client = server.available();   // 檢查是否有客戶端連接

  int myBPM = pulseSensor.getBeatsPerMinute(); // 讀取每分鐘心跳數據
  if (pulseSensor.sawStartOfBeat()) {          // 如果檢測到心跳
    Serial.println("♥ A HeartBeat Happened!"); // 打印心跳訊息
    Serial.print("BPM: ");                     // 打印 BPM 值
    Serial.println(myBPM); 
    Serial.print("count: ");                     // 打印 count 值
    Serial.println(count);

    if (myBPM > 45 && myBPM < 135) {                           // 如果心跳數據大於 0
      sumBPM += myBPM;                         // 累加心跳數據
      count++;                                 // 計數增加

      if (count == 11) {                        // 當計數達到 5
        int averageBPM = sumBPM / 10;       // 計算平均值
        Serial.println("averageBPM : ");
        Serial.println(averageBPM);
        Serial.println("finish");              // 打印完成訊息
        if (client) {
          client.print(averageBPM);            // 將平均 BPM 數據發送給連接的客戶端
          //client.print("\n");
          client.stop();                       // 關閉客戶端連接
        }
        sumBPM = 0;                            // 重置累加器
        count = 1;                             // 重置計數
      }
    }
  }
  delay(20);                                   // 短暫延遲
}
```
:::

:::spoiler 整合按鈕(&燈條)及心率
Arduino端-傳送:
```javascript=
#include <WiFi.h>
#include <PulseSensorPlayground.h>
#include <FastLED.h>

// WiFi 設置
const char* ssid = "啊婷的iPhone";
const char* password = "Bbbbb12252";

// TCP 伺服器設置
WiFiServer server(80);

// 按鈕設定
const int buttonPins[] = {15, 2, 4, 32, 18, 19, 21, 22, 23};
const char buttonMessages[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'};
const int numButtons = 9;

// 心率設定
const int PulseWire = 34;
int Threshold = 550;
PulseSensorPlayground pulseSensor;

int count = 1;
int sumBPM = 0;

WiFiClient client;

// WS2812 LED設定
#define LED_PIN 13
#define NUM_LEDS 60
CRGB leds[NUM_LEDS];

bool lightOn = false; // 追蹤燈的狀態

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Initializing...");

  // 連接 WiFi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi connected");
  Serial.println(WiFi.localIP());

  // 啟動 TCP 伺服器
  server.begin();

  // 設置按鈕引腳為輸入
  for (int i = 0; i < numButtons; i++) {
    pinMode(buttonPins[i], INPUT);
  }

  // 設置心率感測器
  pulseSensor.analogInput(PulseWire);
  pulseSensor.setThreshold(Threshold);

  if (pulseSensor.begin()) {
    Serial.println("PulseSensor object created successfully!");
  } else {
    Serial.println("Failed to initialize PulseSensor.");
  }

  // 初始化 FastLED
  FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
  FastLED.clear();
  FastLED.show();
}

void loop() {
  client = server.available();

  if (client) {
    // 檢查每個按鈕的狀態
    for (int i = 0; i < numButtons; i++) {
      if (digitalRead(buttonPins[i]) == HIGH) {
        if (buttonMessages[i] == 'b') {
          // 按下 'b' 時，切換燈的狀態
          lightOn = !lightOn;
          if (lightOn) {
            turnOnLED();
          } else {
            turnOffLED();
          }
          Serial.println(lightOn ? "Light ON" : "Light OFF");
        } else {
          client.println(buttonMessages[i]);
          Serial.println(buttonMessages[i]);
        }
        delay(500); // 避免重複觸發
      }
    }

    // 讀取心率數據
    int myBPM = pulseSensor.getBeatsPerMinute();
    if (pulseSensor.sawStartOfBeat()) {
      Serial.println("♥ A HeartBeat Happened!");
      Serial.print("BPM: ");
      Serial.println(myBPM);
      Serial.print("count: ");
      Serial.println(count);

      if (myBPM > 40 && myBPM < 180) {
        sumBPM += myBPM;
        count++;

        if (count == 11) {
          int averageBPM = sumBPM / 10;
          Serial.println("averageBPM : ");
          Serial.println(averageBPM);
          Serial.println("finish");
          client.print(averageBPM);
          client.stop();
          sumBPM = 0;
          count = 1;
        }
      }
    }
    delay(20);
  }
}

void turnOnLED() {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB(255, 255, 255); // 設定為白色
  }
  FastLED.show();
}

void turnOffLED() {
  FastLED.clear();
  FastLED.show();
}


```

python端-接收:
```javascript=
def dec_need(self):
    # ESP32 的 IP 位址和端口
    self.ESP32_IP = "172.20.10.14"  # 更改為 ESP32 的 IP 位址
    self.ESP32_PORT = 80
    # 連接到 ESP32
    self.esp32_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    self.esp32_socket.connect((self.ESP32_IP, self.ESP32_PORT))
    while True:
        message = self.esp32_socket.recv(1024).decode("utf-8").strip()
        #print(f"接收到的消息: {message}")
        current_datetime = datetime.datetime.now().strftime("%Y.%m.%d")
        current_time = datetime.datetime.now().strftime("%H:%M")

        if message == "a":
            with open("txtall/dec.txt", "w") as file:
                file.write("a")
            print("dec.txt updated with 'a'")
        elif message == "c":
            with open("txtall/dec.txt", "w") as file:
                file.write("c")
            print("dec.txt updated with 'c'")
        elif message == "d":
            with open("txtall/dec.txt", "w") as file:
                file.write("d")
            print("dec.txt updated with 'd'")
        elif message == "e":
            with open("txtall/dec.txt", "w") as file:
                file.write("e")
            print("dec.txt updated with 'e'")
        elif message == "f":
            with open("txtall/dec.txt", "w") as file:
                file.write("f")
            print("dec.txt updated with 'f'")
        elif message == "g":
            with open("txtall/dec.txt", "w") as file:
                file.write("g")
            print("dec.txt updated with 'g'")
        elif message == "h":
            with open("txtall/dec.txt", "w") as file:
                file.write("h")
            print("dec.txt updated with 'h'")
        elif message == "i":
            with open("txtall/dec.txt", "w") as file:
                file.write("i")
            print("dec.txt updated with 'i'")
        else:
            try:
                heart_rate = int(message)
                if 40 < heart_rate < 180:
                    with open("txtall/heart_rate.txt", "a", encoding='utf-8') as file:
                        file.write(f"日期 : {current_datetime}  時間 : {current_time}  心率 : {message}\n")
                    print(f"Heart rate recorded: {message}")
            except ValueError:
                return
                
```
:::


:::success
調節 LED 亮度：
https://micro.rohm.com/tw/deviceplus/how-tos/arduino-guide/the-basics-of-arduino-adjusting-led-brightness/
:::


---
## 軟體-介面
:::success 
介面資料雲端資料夾：https://drive.google.com/drive/folders/1MMlxr_NQQ7bYJF94IRtl19EimyHDoQfm
:::




### 介面登入帳密：

#### 病患
編號：999    (目前雲端所放的新資料)
密碼：45678  (目前雲端所放的新資料，家屬手機號碼後五碼)

###### 注意:
1. 有關病患資料的帳號密碼都可以透過下圖所示的資料位子來更動數字。
2. 心率偵測結果標註值班人員，依據當前使用者而改變。
3. 看診日曆與吃藥行程皆只會顯示近60日之資料，心率資料保留至當前之五天前所有資料。
4. 看診日曆與吃藥行程的部分目前已匯入至專題展當天的時間資料。
![image](https://hackmd.io/_uploads/SyTaF183A.png)
![image](https://hackmd.io/_uploads/BkL-ak8n0.png)
![image](https://hackmd.io/_uploads/HJPMJeI2R.png)



#### 醫護
編號：學號  (每位皆已匯入)
密碼：0000 (預設，可自行更改)
##### 注意:
1. 登入後會記錄當前人員，也會依據此，在心率顯示系統標注目前使用者。
2. 每個人員的資料都可以被更改。
3. 登入時資料輸入錯誤會顯示該帳號為ER，達到三次錯誤，該帳號便會刪除。
4. 皆已有防呆措施或備註

![image](https://hackmd.io/_uploads/S11eq1L2C.png)
![image](https://hackmd.io/_uploads/Hk-Xp2LR0.png)
![image](https://hackmd.io/_uploads/rJM2T2L0A.png)
![image](https://hackmd.io/_uploads/rJiEBEFRR.png)
![image](https://hackmd.io/_uploads/H1Bj4EKRR.png)
![image](https://hackmd.io/_uploads/H1KB6n8AC.png)







---
## 專題文檔資料
:::warning
專題成果報告書 :
https://1drv.ms/w/c/3698df63b124f8aa/EVp1mgiIbelNo4gkVi1g7p0BSA1WptEyehmuDeoMNzisSA?e=Tm5oih

專題PPT :
https://1drv.ms/p/c/3698df63b124f8aa/ETqrBLL6jnJPgRl1UAhPhu0BlmqcSKhhJcvH5LKzRmPmMA?e=Pqhmbp

專題海報 :
https://1drv.ms/p/c/3698df63b124f8aa/EfuuT03lyiFFikSJ94f_jXQBTr7Pn23VjZhvSyzxrFhOnA?e=yFnM6J

:::

---
## 參考網站
:::info
Random Nerd Tutorials (ESP32相關資料)：https://randomnerdtutorials.com/
:::

:::spoiler ESP32 WROOM32 的 INPUT 腳位
1. GPIO 0
2. GPIO 2
3. GPIO 4
4. GPIO 5
5. GPIO 12
6. GPIO 13
7. GPIO 14
8. GPIO 15
9. GPIO 16
10. GPIO 17
11. GPIO 18
12. GPIO 19
13. GPIO 21
14. GPIO 22
15. GPIO 23
16. GPIO 25
17. GPIO 26
18. GPIO 27
19. GPIO 32
20. GPIO 33
21. GPIO 34
22. GPIO 35
23. GPIO 36
24. GPIO 39
:::


:::success
https://www.rakuten.com.tw/shop/baoleduo/product/yg92mdkko/?adp_id=21249296291_34d9aab0-3747-11ee-a245-0242ac110004_x&gclid=EAIaIQobChMIsMGUhaeyhgMV6f5MAh0fYQDGEAQYBCABEgJtxfD_BwE&scid=GSA_PMAXadp_21249296291_34d9aab0-3747-11ee-a245-0242ac110004&utm_source=google&utm_medium=cpc&utm_campaign=pmax_adp_baoleduo&utm_content=34d9aab0-3747-11ee-a245-0242ac110004&gad_source=1
:::

---

## 連線問題
:::danger
* 手機Wi-Fi開啟了最大相容性，若電腦依然連不上，則將手機的**所有連線功能關閉**，再重開即可。
* 若遇到電腦執行時，下方顯示為"**未連上設備**"，請嘗試按下病患介面，若病患介面按下後開始無反應，則為設備連接問題；若依然有反應，則嘗試第一點。
* 若為**設備連接問題**，則將設備電源拔除，手機網路重開，即可連線成功。
:::

