# 高二下自主學習計畫---遠端寵物飼料餵食器
## 目錄
[TOC]
## 動機
在高一探究與實作的課程中,我們有研究可以藍芽控制的寵物飼料餵食器,不過由於藍芽接收範圍有限之原因,因此不能夠完全實現能夠在美國遠端台灣的餵食器的想法。因此這次的自主學習,我們決定要實現此想法,並且改善裝置的設計。
## 預計功能
* 能夠在國外也能用手機定時餵食家中寵物
## 實踐想法
**這次計畫預計的想法是:前端網頁送出選擇時間後經由後端去計算多久之後執行,最後透過Arduino的HTTPCLIENT程式庫去讀取最後計算出來所需的時間讓馬達在時間到後運作。**
為了達成遠端的功能,勢必不能只依靠無線WI-FI和藍芽,因此我想到可以上傳project到IoT雲平台上,因此我使用了Heroku這個支持多種程式語言的雲平台當作這次架設網頁的Server端。這也是我第一次接觸到要設計後端程式運作,由於之前有學過一點點python,所以這次是使用Flask去架設後端程式網頁。
## 程式架構
**以下先附上這次的程式碼:**
**HTML網頁程式碼如下:**
```htmlembedded=
<!DOCTYPE html>
<head>
<h1>遠端控制飼育機器</h1>
<!--for python flask-->
<script type="text/javascript" src="{{ url_for('static' , filename='js/jquery.js')}}"></script>
<script type="text/javascript" src="{{ url_for('static' , filename='js/jquery-ui.js')}}"></script>
<script type="text/javascript" src="{{ url_for('static' , filename='js/jquery-ui-sliderAccess.js')}}"></script>
<script type="text/javascript" src="{{ url_for('static' , filename='js/jquery-ui-timepicker-addon.js')}}"></script>
</head>
<body>
<!--Form-->
<div id='modes'>
<form id='myform' method="POST" action='' autocomplete="off">
<div id='FeedTime'>
<label for='select-FeedTime'>FeedTime</label>
<input type='text' name='select-FeedTime' id='select-FeedTime'>
</div>
<div id='WaterTime'>
<label for='select-WaterTime'>WaterTime</label>
<input type='text' name='select-WaterTime' id='select-WaterTime'>
</div>
</div>
<input type="submit" id="submit" value="Send">
</form>
</div>
<!--for HTML-->
<script type="text/javascript" src="/static/js/jquery.js"></script>
<script type="text/javascript" src="/static/js/jquery-ui.js"></script>
<script type="text/javascript" src="/static/js/jquery-ui-sliderAccess.js"></script>
<script type="text/javascript" src="/static/js/jquery-ui-timepicker-addon.js"></script>
<link rel="stylesheet" href="/static/css/jquery-ui.min.css">
<link rel="stylesheet" href="/static/css/jquery-ui-timepicker-addon.css">
<!--datetimepickerLaunch-->
<script>
jQuery('#select-FeedTime').datetimepicker({dateFormat:'yy.mm.dd', timeFormat:'HH:mm', defaultDate:''});
</script>
<script>
jQuery('#select-WaterTime').datetimepicker({dateFormat:'yy.mm.dd', timeFormat:'HH:mm', defaultDate:''});
</script>
</body>
```
**PYTHON程式碼如下:**
```python=
from flask import Flask,request,url_for,render_template,redirect
from datetime import datetime,timezone,timedelta
import time
app = Flask(__name__)
@app.route("/timetest")
def Time_cmp():
ty = timezone(timedelta(hours =+8))
datetimeNow = datetime.now(ty).strftime('%Y.%m.%d %H:%M')
return datetimeNow
@app.route("/")
def home():
global work
work="FALSE"
return "Hello Heroku."
@app.route("/htmltest", methods=["POST","GET"])
def htmltest():
if request.method == "POST":
WaterTime = request.form['select-WaterTime']
FeedTime =request.form['select-FeedTime']
print("Feed",FeedTime,"Water",WaterTime)
if FeedTime != '':
global A
A = Feed(FeedTime)
work = "TRUE"
return redirect(url_for("FEEDING"))
else:
global B
B = WATER(WaterTime)
work = "TRUE"
return redirect(url_for("WATERING"))
else:
return render_template("index.html")
@app.route("/FEEDING")
def FEEDING():
return A
@app.route("/WATERING")
def FEEDING():
return B
@app.route("/WORK")
def WORK():
reset()
return work
def reset():
time.sleep(1)
work= "FALSE"
return work
def Feed(selectFeedTime):
ty = timezone(timedelta(hours =+8))
datetimeNow = datetime.now(ty).strftime('%Y.%m.%d %H:%M:%S')
datetimeNow = datetime.now().strptime(datetimeNow , '%Y.%m.%d %H:%M:%S')
selectFeedTime = datetime.strptime(selectFeedTime , '%Y.%m.%d %H:%M')
timeGapFeed = selectFeedTime - datetimeNow
timeGapFeedSecond = str(timeGapFeed.total_seconds())
return timeGapFeedSecond
def Feed(selectWaterTime):
ty = timezone(timedelta(hours =+8))
datetimeNow = datetime.now(ty).strftime('%Y.%m.%d %H:%M:%S')
datetimeNow = datetime.now().strptime(datetimeNow , '%Y.%m.%d %H:%M:%S')
selectFeedTime = datetime.strptime(selectFeedTime , '%Y.%m.%d %H:%M')
timeGapWater = selectWaterTime - datetimeNow
timeGapWaterSecond = str(timeGapWater.total_seconds())
return timeGapWaterSecond
if __name__ == "__main__":
app.run(debug=True)
```
**Arduino程式碼如下:**
```Arduino=
#include <WiFi.h>
#include <HTTPClient.h>
#include <Servo.h>
char severName[] = "feed-your-pet-anywhere-omg.herokuapp.com";
const char* ssid = "******";
const char* pass = "******";
const char* headerKeys[] = {"Referer","Cookie"};
Servo myservo;
int pos=0;
#define USE_SERIAL Serial
void setup() {
myservo.attach(9);
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid,pass);
Serial.println("");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Wi-Fi ready...");
}
void loop(){
if((WiFi.status()== WL_CONNECTED)){
httpclient();
}
}
void httpclient(){
HTTPClient feedcheck;
feedcheck.begin("http://feed-your-pet-anywhere-omg.herokuapp.com/FEEDING");
int httpCode = feedcheck.GET();
USE_SERIAL.print(httpCode);
USE_SERIAL.print("\n");
if(httpCode == HTTP_CODE_OK) {
String payload1 = feedcheck.getString();
int FEED=payload1.toInt();
for(int t=FEED;t<0;t=t-1){
if(t==0){
Serial.print("ENDFEED");
for(pos = 0; pos < 180; pos += 1)
{
myservo.write(pos);
delay(15);
}
for(pos = 180; pos>=1; pos-=1)
{
myservo.write(pos);
delay(15);
}
}
}
Serial.print("Sever response playload:");
Serial.print(payload1);
Serial.print("\n");
}
else {
USE_SERIAL.print("Error Response Code:" );
USE_SERIAL.print(httpCode);
}
feedcheck.end();
}
```
## 運行截圖



## 遭遇困難 & 解決辦法
### HTML內部的Input time 無法選擇日期
HTML中的`input type="time"`只能選擇幾點幾分而不能選擇哪一天,為了能更精確選擇日期,查詢網路過後,發現可以使用額外的Javascript套件Datetimepicker,就能夠選擇日期了。
### Arduino判斷運作條件的方法
一開始的時候計畫要讓Arduino偵測網址,在python上面計時,時間到即跳轉頁面,Arduino偵測到後即運作。結果因為頁面是預先寫好的Arduino在偵測時就會直接偵測到計時完成的頁面而不停運作。
為了能實踐時間到才運作的想法,因此改成讓Arduino偵測要過多久才運作,並且將計時移動到Arduino端來進行,如此一來就能正常運行。
## 未來可改進之處
### 能夠餵飼料和倒水同時進行
當初在寫Arudino端偵測網頁時,一直找不到原因可以讓Arduino同時偵測飼料和倒水的頁面成功,導致一次只能選擇兩者之一進行,只能夠分開選兩次時間,如果能一次選擇兩個的時間能讓使用效果更好。
### 網頁介面
之後可以學習CSS的寫法,讓網頁介面整個看起來更美觀一些。
## 心得
這次自主學習整個程式都是由我來負責,其他人則負責製作裝置,因此我也感覺自己身負重任,畢竟缺少了程式整個都不能運作。不過很可惜的是當時因為疫情爆發而被迫線上教學,當時程式並還沒debug完,後來回學校後發現裝置被誤丟掉了,也因此沒有搭配過裝置運作。
不過這次的自主學習對我來說還是很好的一次學習經驗,這也是我第一次接觸到網頁的程式設計,我覺得非常有趣而javacript對html的擴˙充性也讓我再次讚嘆程式真的是無極限,甚麼都能做的互相搭配做出來。
## 參考資料
[發布網站到Heroku - iT 邦幫忙](https://ithelp.ithome.com.tw/articles/10196129)
[HttpClient - Arduino Reference](https://www.arduino.cc/reference/en/libraries/httpclient/)
[Arduino库教程-Bridge-HTTP Client - 创客智造](https://www.ncnynl.com/archives/201608/539.html)
[Python Flask 入門指南: 輕量級網頁框架教學](https://devs.tw/post/448)
[W3School-HTML Element Reference](https://www.w3schools.com/tags/default.asp)