今天下午弄完滷冬瓜後, 花了一整個下午研究樹莓派上執行的 reportip2.py 為何近兩周以來都沒有回報外網 IP 變更訊息, 原先以為問題可能是 myip.com.tw 已經從 http 改成 https 協定, 導致呼叫 visit() 函數時無法取得 IP 資料所致. 但後來發覺 reportip2.py 的檔案模式竟然不是可執行模式, 奇怪, 難道有駭客入侵改了嗎? 總之, 兩個都改了之後就 OK 了 :
pi@raspberrypi:~ $
ls reportip2.py -al
-rw-r--r-- 1 pi pi 2960 Dec 10 2017 reportip2.py
pi@raspberrypi:~ $
sudo chmod +x /home/pi/reportip2.py
pi@raspberrypi:~ $
ls reportip2.py -al
-rwxr-xr-x 1 pi pi 2960 Dec 10 2017 reportip2.py
pi@raspberrypi:~ $
python2 reportip2.py
Network is Ready!
IP information from http://myip.com.tw
IP not change. 111.254.54.xx 192.168.2.192
reportip2.py 會將目前最新外網 IP 紀錄於文字檔中, 每次比對時會讀取現在的外網 IP 與檔案所記錄之 IP 比較, 若不一樣才以郵件通報. 這次我一直到兩周後連線失敗才發現這問題似乎太晚, 應該改為 HEART BEAT 模式, 例如每小時通報一次, 不需要去比對有無變異, 這樣只要沒有收到 email 就表示樹莓派有問題了, 而且從郵件中找尋最新 IP 也很快.
關於回報 IP 以便能從遠端存取樹莓派的方法參考之前的測試紀錄 :
#
從外網以 SSH 存取樹莓派的方法
#
Python 學習筆記 : 網頁擷取 (一) 使用 urllib 與 HTMLParser
#
Python 學習筆記 : 以 Gmail 寄送郵件的方法 (一)
#
樹莓派自動偵測網路斷線時重開機的方法
目前的 reportip2.py 是用 Python 2 改寫的 (利用我的 Hinet 信箱寄送郵件), 當時也嚐試改成 Python 3 版但沒成功, reportip3.py 就晾在那邊, 前陣子測試了用 Gmail 傳送郵件的方法, 因此這次就改為用 Gmail 來寄送 IP 訊息, 且改用 Python 3 來寫, 原始碼 reportip3.py 如下 :
#
reportip3.py : send mail by Gmail with TLS
import smtplib
from urllib import request
import re
import socket
import time
class Getmyip:
def getip(self):
try:
myip=self.visit("https://myip.com.tw")
except:
try:
myip=self.visit("http://cmp.nkuht.edu.tw/info/ip.asp")
except:
try:
myip=self.visit("http://dir.twseo.org/ip-check.php")
except:
print("Fail to get the Network ip.")
print("Get the LAN ip.")
myip=get_lan_ip()
return myip
def visit(self, url):
opener=request.urlopen(url,timeout=20)
#print(opener.headers.get_content_charset())
if url==opener.geturl():
str=opener.read().decode(opener.headers.get_content_charset())
print("IP information from", url)
return re.search('\d+\.\d+\.\d+\.\d+',str).group(0)
def get_network_ip():
getmyip=Getmyip()
localip=getmyip.getip()
return localip
def get_lan_ip():
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("1.1.1.1",80))
ipaddr=s.getsockname()[0]
s.close()
return ipaddr
#check_network()
ipaddr=get_network_ip()
lanip=get_lan_ip()
emailip=str(ipaddr)+" "+str(lanip)
print("current ip: {}".format(emailip))
smtp=smtplib.SMTP("smtp.gmail.com", 587)
smtp.ehlo()
smtp.starttls()
smtp.login("mygmail@gmail.com", "yguxhsurqwpseksw")
from_addr="mygmail@gmail.com"
to_addr=["myhinetmail@msa.hinet.net"]
msg="Subject:My IP\n\
From:Raspberry Pi 3\n\
To:My IP\n\
Cc:mycompanymail@mycompany.com.tw\n\
{}".format(emailip)
status=smtp.sendmail(from_addr, to_addr, msg)
if status=={}:
print("郵件傳送成功!")
else:
print("郵件傳送失敗!")
smtp.quit()
檔案存成 reportip3.py, 然後用 chmod 指令變更為可執行 :
pi@raspberrypi:~ $ ls reportip3.py -ls
4 -rw-r--r-- 1 pi pi 1800 Nov 11 17:03 reportip3.py
pi@raspberrypi:~ $ sudo chmod +x /home/pi/reportip3.py
pi@raspberrypi:~ $ ls reportip3.py -ls
4 -rwxr-xr-x 1 pi pi 1800 Nov 11 17:03 reportip3.py
用 python3 指令執行成功 :
pi@raspberrypi:~ $ python3 reportip3.py
IP information from https://myip.com.tw
current ip: 111.254.54.xx 192.168.2.192
Send mail successfully!
最後修改 crontab, 加入於整點執行 reportip3.py 的定時器 :
pi@raspberrypi:~ $ crontab -e
pi@raspberrypi:~ $ crontab -l
*/10 * * * * /usr/bin/python2 /home/pi/reportip2.py
0 * * * * sudo /usr/local/checkwifi.sh
0 * * * * /usr/bin/python3/home/pi/reportip3.py
這是整點執行的 crontab.
如果是想每個小時執行一次, 但不是整點, 而是 crontab 更新的那時開始每隔一小時的話要這麼寫 :
pi@raspberrypi:~ $ crontab -l
*/10 * * * * /usr/bin/python2 /home/pi/reportip2.py
0 * * * * sudo /usr/local/checkwifi.sh
* */1 * * * /usr/bin/python3 /home/pi/reportip3.py
查看 crontab 日誌 :
pi@raspberrypi:~ $
sudo cat /var/log/cron.log
參考 :
#
定時任務之crontab命令
#
第十五章、例行性工作排程(crontab)
#
crontab 表达式每小时执行一次(整点整分)
2018-11-12 補充 :
今早收信確認每小時 (30 分) 都會收到樹莓派發出的外網 IP 通知信 :
只要漏掉一封信就表示有問題, 要嘛是網路斷線, 要嘛是樹莓派系統出問題.
2019-07-27 補充:
今天發現手機收到的 email 中, 鄉下 Pi 3 傳回來的 IP 為 192.168.2.192, 這表示查詢外網 IP 有問題, 檢查 reportip3.py 應該是每一個 try 都失敗, 原因可能出在 visit(), 它原先是用 urllib.request, 乾脆改成 requests 好了 :
#reportip3.1.py
#Send mail by Gmail with TLS
import smtplib
import request3
import re
import socket
import time
class Getmyip:
def getip(self):
try:
myip=self.visit("https://myip.com.tw") #utf-8
except:
try:
myip=self.visit("http://cmp.nkuht.edu.tw/info/ip.asp") #big-5
except:
try:
myip=self.visit("http://dir.twseo.org/ip-check.php")
except:
print("Fail to get the Network ip.")
print("Get the LAN ip.")
myip=get_lan_ip()
return myip
def visit(self, url):
r=requests.get(url)
#print(r.encoding)
return re.search('\d+\.\d+\.\d+\.\d+',r.text).group(0)
def get_network_ip():
getmyip=Getmyip()
localip=getmyip.getip()
return localip
def get_lan_ip():
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("1.1.1.1",80))
ipaddr=s.getsockname()[0]
s.close()
return ipaddr
#check_network()
ipaddr=get_network_ip()
lanip=get_lan_ip()
emailip=str(ipaddr)+" "+str(lanip)
print("current ip: {}".format(emailip))
smtp=smtplib.SMTP("smtp.gmail.com", 587)
smtp.ehlo()
smtp.starttls()
smtp.login("yhhuang1966@gmail.com", "
yguxhsurqwpseksw")
from_addr="yhhuang1966@gmail.com"
to_addr=["tony1966@ms5.hinet.net"]
msg="Subject:Meinung IP\n\
From:Raspberry Pi 3\n\
To:MyIP\n\
Cc:yhhuang@cht.com.tw\n\
{}".format(emailip)
status=smtp.sendmail(from_addr, to_addr, msg)
if status=={}:
print("Send mail successfully!")
else:
print("Send mail in failure!")
smtp.quit()