Nginx+Mariadb+PHP+Python
Last updated
Was this helpful?
Last updated
Was this helpful?
雖然透過ThingSpeak呈現溫濕度圖表非常的方便,只要註冊申請帳號,透過api傳送資料到ThingSpeak,就會自動把圖畫出來,但在一些特殊狀況下,如沒有對外的網路,那就沒有辦法把資料上傳到ThingSpeak,所以此篇在Raspberry Pi上建立Nginx+Mariadb,透過Python讀取DHT22溫濕度後把資料寫到Mariadb資料庫,然後讀取資料庫中的歷史資料,用python + bokeh + pandas產生圖表網頁,讓使用者可以連到本機的網站觀看目前Raspberry Pi的溫濕度狀況,如下圖…
目前把整個溫濕度所需要安裝的套件,設定的內容及程式原始碼,透過Ansible去處理,使用方式和moodlebox一樣,使用moodlebox的原始程式,修改成go38box,整個ansible的資料夾架構及設定方式與moodlebox相同,安裝方式請參考
溫濕度網站的架構非常的簡單,就只是一般的網頁,此網頁樣版來自於https://templated.co/azure,只做小部分修改,在溫濕度圖的地方使用兩個iFrame把溫度與濕度的html嵌入到首頁中,然後固定時間會重新載入溫濕度的html檔,所以在整個網站顯示的部分沒什麼特別的程式,也沒有使用到php,會安裝php主要是因為使用phpmyadmin去管理設定資料庫
溫濕度網址:http://go38box.local
PhpMyAdmin網址:http://go38box.local/phpmyadmin
網站路徑:/var/www/html/temperature
首頁:index.html
溫度:db_temp.html
濕度:db_humidity.html
這邊要注意的部分為db_temp.html及db_humidity.html兩個檔案,此兩個檔案為link,來源為/home/go38box/DHT22/db_temp.html
及/home/go38box/DHT22/db_humidity.html
,另外phpmyadmin也是用link的方式建立,來源為/usr/share/phpmyadmin
,檔案清單如下:
go38box@go38box:/var/www/html/temperature $ ls -al
total 52
drwxrwxr-x 6 www-data www-data 4096 Apr 26 00:33 .
drwxr-xr-x 3 root root 4096 Apr 26 00:33 ..
drwxrwxr-x 3 www-data www-data 4096 Apr 26 00:33 css
lrwxrwxrwx 1 root root 36 Apr 26 00:33 db_humidity.html -> /home/go38box/DHT22/db_humidity.html
lrwxrwxrwx 1 root root 32 Apr 26 00:33 db_temp.html -> /home/go38box/DHT22/db_temp.html
drwxrwxr-x 8 www-data www-data 4096 Apr 26 00:33 .git
drwxrwxr-x 2 www-data www-data 4096 Apr 26 00:33 images
-rw-rw-r-- 1 www-data www-data 2199 Apr 26 00:33 index.html
drwxrwxr-x 2 www-data www-data 4096 Apr 26 00:33 js
-rw-rw-r-- 1 www-data www-data 17128 Apr 26 00:33 LICENSE.txt
lrwxrwxrwx 1 root root 21 Apr 26 00:33 phpmyadmin -> /usr/share/phpmyadmin
-rw-rw-r-- 1 www-data www-data 12 Apr 26 00:33 README.md
go38box@go38box:/var/www/html/temperature $
下方內容放在<head>
內,主要功能為固定時間讓iframe重新載入來更新溫濕度,setInterval為設定多久執行一次,設定方式為(秒*1000),如下(60秒*1000),就是每分鐘重新載入一次
<script language="javascript">
one=function(){
iftemp.location.reload()
ifhumidity.location.reload()
}
setInterval("one()",60000)
</script>
下方內容放在<body>內,主要顯示溫濕度的html檔,有兩個<iframe>,name分別為iftemp及ifhumidity,這個名稱需要和<head>的設定相同
<section class="content">
<h2>溫濕度計</h2>
<iframe name="iftemp" src="../db_temp.html" width="550px" height="260px" frameborder="0" scrolling="no"></iframe>
<iframe name="ifhumidity" src="../db_humidity.html" width="550px" height="260px" frameborder="0" scrolling="no"></iframe>
</section>
設定檔「/etc/nginx/sites-available/default
」,內容如下,主要修改了root,預設的網站根目錄為「/var/www/html」目前修改成「/var/www/html/temperature
」,用ansible安裝是不需要再手動設定
#
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html/temperature;
index index.php index.html index.htm index.nginx-debian.html;
server_name go38box;
location / {
try_files $uri $uri/ =404;
}
location ~ [^/]\.php(/|$) {
include fastcgi_params;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_read_timeout 300;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PHP_VALUE "max_execution_time=300\n upload_max_filesize=50M\n post_max_size=50M";
client_max_body_size 50M;
}
}
DHT22所讀取的溫濕度會寫到Raspberry PI本機中建立的mariadb資料庫中,可以透過下方的網址及帳號密碼登入觀看及設定
帳號:go38box
密碼:Go38box4$
資料庫:temperature
目前建立一個名稱為temperature的資料庫,裡面有3張資料表,欄位說明及結構如下
temp儲存溫濕度的記錄,欄位說明如下:
datetime:資料的日期時間
temp:溫度,取到小數點第一位
humidity 濕度,取到小數點第一位
資料結構如下圖:
smtp資料表,存放有關寄送溫濕度異常E-MAIL的設定,此表中只會有一筆設定資料,如果要修改參數可以直接修改欄位內容即可
id:此id為key值,因為此資料表為設定用,所以只需要一筆資料,程式會讀取id=0的該筆資料當做設定值
hostname:網站網址,目前預設為 go38box.local
from_addr:寄件者E-MAIL,目前使用gmail當作smtp來寄送mail
to_addr:收件者E-MAIL
smtp_addr:gmail的smtp網址為 smtp.gmail.com
smtp_port:gmail的smtp port為 587
smtp_password:smtp的密碼,使用gmail當作smtp寄送mail,所以此密碼為from_addr
的E-MAIL密碼,目前此欄位有加密
send_time:最後一次寄送E-Mail的時間(程式會自動更新此欄位)
send_status:目前溫濕度狀態,1為異常、0為正常,此欄位請不要修改(程式會自動更新此欄位)
send_wait_time:每執行一次都會檢查是否異常,此欄位儲存單位是秒數,主要在溫濕度一直在異常狀態下不會重復的寄送,例如此欄位目前預設值為3600秒,也就是1小時,當送出一封異常E-MAIL後,會自動更新欄位中的send_time最後送出異常E-Mail的時間,每次執行會用目前的時間和send_time
相減,看是否超過此欄位所設定的時間(1小時),如果超過則會再寄送一次異常E-MAIL
send_check_time:每執行一次都會檢查是否正常,此欄位儲存單位是秒數,如果上一次寄送異常E-MAIL的時間和目前時間相比是否大於所設定的send_check_time
,大於的話才會切換為正常,必免溫濕度剛好在設定的邊界值跳動會一直送出異常與正常的E-MAIL,例如目前設定660,代表11分鐘內,不會寄送恢復正常的E-MAIL,如果超過,則會更新send_time
及send_status
設為0
id:此id為key值,因為此資料表為設定用,所以只需要一筆資料,程式會讀取id=0的該筆資料當做設定值
send_mail:此欄位主要設定是否要寄送E-MAIL,0(不寄送),1(寄送)
temp_max:設定溫度正常範圍的最高溫度,目前預設為30度
temp_min:設定溫度正常範圍的最低溫度,目前預設為10度
humidity_max:設定濕度正常範圍的最高濕度,目前預設為70%
humidity_min:設定濕度正常範圍的最低濕度,目前預設為40%
time_offset:當程式取得新的溫濕度後,會先抓資料庫中最後一筆資料回來做參考比對,檢查與最後一筆資料的時間是否超過time_offset
的設定值,目前預設為100秒,如果與上一筆資料時間相差超過100秒,則會直接寫入資料庫,如果沒有超過,則會再比對目前溫濕度是否和最後一筆的溫濕度相差超過difference
的設定值,如果超過也是不寫入資料庫中,主要就是去DHT22元件的異常值
difference:溫濕度的正負差,目前設定為5
thingspeak_key:如果有申請thingspeak,也想把資料上傳到thingspeak的話,註冊後會取得一組thingspeak_key
,要上傳的話把key填入此欄位,如果不想上傳的話就清空此欄位,請參考文內的ThingSpeak 說明
在開始前,請先閱讀開發環境及設備 及 取得溫濕度 這兩個章節,確認溫濕度元件已接上RaspberryPi並且可以讀取到溫濕度
#!/usr/bin/python
# coding:utf-8
import sys, os, logging
import Adafruit_DHT
import httplib, urllib
import time,datetime
import MySQLdb
import base64
import smtplib
import pandas as pd
from bokeh.models import BoxAnnotation
from bokeh.plotting import figure, output_file, show
from bokeh.models import HoverTool
from Crypto.Cipher import DES
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
# 程式檔案路徑
fPath = "/home/go38box/DHT22/"
# log 參數設定
FORMAT = '%(asctime)s - %(message)s'
logpath = fPath + "tempLogs"
logging.basicConfig(format = FORMAT, filename = logpath)
logger = logging.getLogger('tcpserver')
"""
console = logging.StreamHandler()
aformat = logging.Formatter('%(asctime)s - %(message)s')
console.setFormatter(aformat)
logger.addHandler(console)
"""
def main():
writeToDb = False
errId = -1
# 連接資料庫
db = db_connect()
# 取得最後一筆資料
lastRecord = get_last_record(db)
# 取得config資料表中的設定
[dbSendMail,dbTempMax,dbTempMin,dbHumidityMax,dbHumidityMin,dbTimeOffset,dbDifference,dbThingSpeakApiKey] = get_config(db)
#取得目前時間
dtnow = datetime.datetime.now()
#取得溫濕度
[temp,humidity] = dht22()
# 目前時間和最後一筆資料的時間相差幾秒
timeoffset = (dtnow - lastRecord[0]).seconds
# 送溫濕度到ThingSpeak,如果設定值為空的話,就不傳送
if dbThingSpeakApiKey!='':
params = urllib.urlencode({'field1': '{0:0.1f}'.format(temp), 'field2': '{0:0.1f}'.format(humidity), 'key': dbThingSpeakApiKey})
post_to_thingspeak2(params)
#溫濕度在0~100間才處理
if (humidity >0 and humidity <= 100) and (temp >0 and temp<=100):
if timeoffset > dbTimeOffset:
#目前時間和資料庫中最後一筆資料的時間超過X秒就直接寫入資料庫
logger.warning('Msg =>last(%s Temp:%s Humidity:%s) New(%s Temp:%6.2f Humidity:%6.2f) event:%s', lastRecord[0],lastRecord[1],lastRecord[2],dtnow,temp,humidity,'timeoffset > 60')
writeToDb = True
errId=2
else:
#目前時間和資料庫在X秒內,就檢查和上一筆的溫濕度不可超過所設定的範圍
#超過則不寫入資料庫
#溫度+-5度 ,濕度+-5度
#正負值由資料庫中設定
if (temp > lastRecord[1]+dbDifference) or (temp < lastRecord[1]-dbDifference):
logger.warning('Msg =>last(%s Temp:%s Humidity:%s) New(%s Temp:%6.2f Humidity:%6.2f) event:%s', lastRecord[0],lastRecord[1],lastRecord[2],dtnow,temp,humidity,'(temp > lastRecord[1]+'+str(dbDifference)+') or (temp < lastRecord[1]-'+str(dbDifference)+')')
writeToDb = False
errId=3
elif (humidity > lastRecord[2]+dbDifference) or (humidity < lastRecord[2]-dbDifference):
logger.warning('Msg =>last(%s Temp:%s Humidity:%s) New(%s Temp:%6.2f Humidity:%6.2f) event:%s', lastRecord[0],lastRecord[1],lastRecord[2],dtnow,temp,humidity,'(humidity > lastRecord[2]+'+str(dbDifference)+') or (humidity < lastRecord[2]-'+str(dbDifference)+')')
writeToDb = False
errId=4
else:
writeToDb = True
else:
# 溫濕度不在0~100間
logger.warning('Msg =>last(%s Temp:%s Humidity:%s) New(%s Temp:%6.2f Humidity:%6.2f) event:%s', lastRecord[0],lastRecord[1],lastRecord[2],dtnow,temp,humidity,'(humidity >0 and humidity <= 100) and (temp >0 and temp<=100)')
writeToDb = False
errId=1
# 依上方的判斷(writeToDb),決定是否要寫入資料庫
if writeToDb:
#logger.warning('Msg =>last(%s Temp:%s Humidity:%s) New(%s Temp:%6.2f Humidity:%6.2f) event:%s', lastRecord[0],lastRecord[1],lastRecord[2],dtnow,temp,humidity,'OK')
# 將目前的溫濕度寫入資料庫
insert_to_mysql(db,dtnow,temp,humidity);
# 取得目前時間
dataframe = select_data(db,1)
lastRecordNew = get_last_record(db)
build_temp(dataframe[0],lastRecordNew,dbTempMax,dbTempMin)
build_humidity(dataframe[1],lastRecordNew,dbHumidityMax,dbHumidityMin)
# 依資料表config中欄位「send_mail」的設定,判斷是否要寄送E-Mail
if dbSendMail==1 :
if writeToDb == True and (lastRecordNew[1]>=dbTempMin and lastRecordNew[1]<=dbTempMax and lastRecordNew[2]>=dbHumidityMin and lastRecordNew[2]<=dbHumidityMax):
send_email(db,lastRecord[0],lastRecord[1],lastRecord[2],lastRecordNew[0],lastRecordNew[1],lastRecordNew[2],dbTempMax,dbTempMin,dbHumidityMax,dbHumidityMin,dbTimeOffset,dbDifference,timeoffset,0)
elif writeToDb == False:
# print 'writeToDb=false'
send_email(db,lastRecord[0],lastRecord[1],lastRecord[2],dtnow,temp,humidity,dbTempMax,dbTempMin,dbHumidityMax,dbHumidityMin,dbTimeOffset,dbDifference,timeoffset,errId)
elif lastRecordNew[1]<dbTempMin or lastRecordNew[1]>dbTempMax or lastRecordNew[2]<dbHumidityMin or lastRecordNew[2]>dbHumidityMax :
# print 'maxmine'
errId=5
logger.warning('Msg =>last(%s Temp:%s Humidity:%s) New(%s Temp:%6.2f Humidity:%6.2f) event:%s', lastRecord[0],lastRecord[1],lastRecord[2],dtnow,temp,humidity,'溫濕度異常,不在所設定的範圍內!')
send_email(db,lastRecord[0],lastRecord[1],lastRecord[2],lastRecordNew[0],lastRecordNew[1],lastRecordNew[2],dbTempMax,dbTempMin,dbHumidityMax,dbHumidityMin,dbTimeOffset,dbDifference,timeoffset,errId)
db.close()
# 遲接資料庫
def db_connect():
db = MySQLdb.connect(host="localhost",user="go38box", passwd="Go38box4$",db="temperature", charset="utf8")
return db
# 取得溫濕度
def dht22():
humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.AM2302,4)
if humidity is not None and temperature is not None:
print('Temp={0:0.1f}* Humidity={1:0.1f}%'.format(temperature,humidity))
return(temperature,humidity)
else:
print('Failed to get reading. Try again!')
return(0,0)
# 將溫濕度送到ThingSpeak上
def post_to_thingspeak2(payload):
headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "text/plain"}
not_connected = 1
while (not_connected):
try:
conn = httplib.HTTPConnection("api.thingspeak.com",80,True,10)
conn.connect()
not_connected = 0
except (httplib.HTTPException, socket.error) as ex:
# logger.warning('Error: %s',ex)
print "Error: %s" % ex
conn.request("POST", "/update", payload, headers)
response = conn.getresponse()
print( response.status, response.reason, payload, time.strftime("%c"))
if response.status!=200 and response.reason!='OK':
logger.warning('ThingSpeak Error: status:%s reason:%s. payload:%s time:%s' ,response.status, response.reason, payload, time.strftime("%c"))
data = response.read()
conn.close()
# 將溫濕度寫入資料庫中
def insert_to_mysql(db,dtnow,temp,humidity):
cursor = db.cursor()
strnow = dtnow
strtemp = "%.1f" %(temp)
strhumidity = "%.1f" %(humidity)
insert = ("INSERT INTO temp (datetime, temp, humidity) VALUES (%s, %s, %s)")
data = (strnow,strtemp,strhumidity)
cursor.execute(insert,data)
db.commit()
# 從資料庫中取得最後一筆溫濕度記錄
def get_last_record(db):
cursor = db.cursor()
cursor.execute("select * from temp order by datetime desc limit 1")
record = cursor.fetchone()
lastTime = record[0]
lastTemp = record[1]
lastHumidity = record[2]
# print "Last Datetime = %s Temp = %s Humidity = %s" %(lastTime,lastTemp,lastHumidity)
return (lastTime,lastTemp,lastHumidity)
# 從資料庫查詢從目前時間往前x天的溫濕度資料,畫圖用
def select_data(db,sDay):
cursor = db.cursor()
cursor.execute("select * from temp where datetime BETWEEN DATE_SUB(NOW(),INTERVAL " + str(sDay) +" DAY) AND NOW()")
rows = cursor.fetchall()
#for record in rows:
# print "%s %s %s" % (record[0],record[1],record[2])
df = pd.DataFrame([[ij for ij in i] for i in rows])
df.rename(columns={0: 'DateTime', 1: 'Temp', 2: 'Humidity'}, inplace=True);
df_temp = df.sort_values(['DateTime'], ascending=[1]);
df_humidity = df.sort_values(['DateTime'], ascending=[2]);
return (df_temp,df_humidity)
# 產生溫度的html檔
def build_temp(df,lastRecord,dbTempMax,dbTempMin):
hover = HoverTool(tooltips=[
("時間", "@x{%F %H:%M:%S}"),
("溫度", "@y{%0.2f} (°C)"),
],
formatters={
'x' : 'datetime',
'y' : 'printf',
},)
TOOLS = ["pan,wheel_zoom,box_zoom,reset,save",hover]
p = figure(plot_width=540,plot_height=250,x_axis_type="datetime",y_range=(0, 40), tools=TOOLS,toolbar_location = "above", title="溫度 ("+str(lastRecord[0])+" "+str(lastRecord[1])+"°C)")
p.xgrid.grid_line_color=None
p.ygrid.grid_line_alpha=0.5
p.xaxis.axis_label = '時間'
p.yaxis.axis_label = '攝氏(°C)'
p.line(df['DateTime'], df['Temp'], color='navy', alpha=0.5)
#p.line(df['DateTime'], df['Temp'], line_dash="4 4", line_width = 1,color='navy', alpha=0.5)
#p.circle(df['DateTime'],df['Temp'], size=10, color="navy", alpha=0.5)
p.add_layout(BoxAnnotation(top=dbTempMin, fill_alpha=0.1, fill_color='red'))
p.add_layout(BoxAnnotation(bottom=dbTempMin, top=dbTempMax, fill_alpha=0.1, line_color='olive', fill_color='olive'))
p.add_layout(BoxAnnotation(bottom=dbTempMax, fill_alpha=0.1, fill_color='red'))
output_file(fPath+"db_temp.html")
show(p)
# 產生濕度的html檔
def build_humidity(df,lastRecord,dbHumidityMax,dbHumidityMin):
hover = HoverTool(tooltips=[
("時間", "@x{%F %H:%M:%S}"),
("濕度", "@y{%0.2f} (%)"),
],
formatters={
'x' : 'datetime',
'y' : 'printf',
},)
TOOLS = ["pan,wheel_zoom,box_zoom,reset,save",hover]
p = figure(plot_width=540,plot_height=250,x_axis_type="datetime",y_range=(20,105), tools=TOOLS,toolbar_location = "above", title="濕度 ("+str(lastRecord[0])+" "+str(lastRecord[2])+"%)")
p.xgrid.grid_line_color=None
p.ygrid.grid_line_alpha=0.5
p.xaxis.axis_label = '時間'
p.yaxis.axis_label = '百分比(%)'
p.line(df['DateTime'], df['Humidity'], color='navy', alpha=0.5)
p.add_layout(BoxAnnotation(top=dbHumidityMin, fill_alpha=0.1, fill_color='red'))
p.add_layout(BoxAnnotation(bottom=dbHumidityMin, top=dbHumidityMax, fill_alpha=0.1, line_color='olive', fill_color='olive'))
p.add_layout(BoxAnnotation(bottom=dbHumidityMax, fill_alpha=0.1, fill_color='red'))
output_file(fPath+"db_humidity.html")
show(p)
# 讀取資料庫中config資料表中的設定,id=0
def get_config(db):
cursor = db.cursor()
cursor.execute("select * from config where id=0")
record = cursor.fetchone()
return(record[1],record[2],record[3],record[4],record[5],record[6],record[7],record[8])
# 傳送email
def send_email(db,lastDatetime,lastTemp,lastHuminidy,newDatetime,newTemp,newHuminidy,dbTempMax,dbTempMin,dbHumidityMax,dbHumidityMin,dbTimeOffset,dbDifference,timeoffset,errId):
cursor = db.cursor()
cursor.execute("select * from smtp where id=0")
record = cursor.fetchone()
fromaddr = record[2]
toaddr = record[3]
pwd = decrypt_des(record[6])
sendTime = record[7]
sendStatus = record[8]
sendWaitTime = record[9]
sendCheckTime = record[10]
sendTimeOffset = (newDatetime - sendTime).seconds
goSendMail = False
print 'errId=' +str(errId)
print 'sendTimeOffset=' +str(sendTimeOffset)
if errId==0:
#errId=0代表溫濕度正常,但還要加入檢查,如果上一次寄送異常mail的時間和目前時間相比是否大於所設定的sendCheckTime,大於的話才切換為正常
if sendStatus==1 and (sendTimeOffset > sendCheckTime):
update_smtp_send_status(db,newDatetime,0)
#傳送回復正常的mail
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "Go38 溫濕度正常"
bodytable = """<font color="#00A800">溫濕度正常!</font><br>"""
bodytable += """
<br><font color="blue">*溫度正常範圍:""" + str(dbTempMin) + """ ~ """ + str(dbTempMax) + """ (°C)</font><br>
<font color="blue">*濕度正常範圍:""" + str(dbHumidityMin) + """ ~ """ + str(dbHumidityMax) + """ (%)</font><br>
"""
bodytable += """
<table align="left" border="1" cellpadding="1" cellspacing="1" style="width:500px">
<tbody>
<tr>
<td style="text-align:center"><a href="http://"""+str(record[1])+""" " target="_blank">"""+str(record[1])+"""</a></td>
<td style="text-align:center">日期</td>
<td style="text-align:center">溫度(°C)</td>
<td style="text-align:center">濕度(%)</td>
</tr>
<tr>
<td style="text-align:center">上一筆資料</td>
<td style="text-align:center">"""+ str(lastDatetime) +"""</td>
<td style="text-align:center">"""+ str(lastTemp) +"""</td>
<td style="text-align:center">"""+ str(lastHuminidy) +"""</td>
</tr>
<tr>
<td style="text-align:center">最新資料</td>
<td style="text-align:center">"""+ str(newDatetime) +"""</td>
<td style="text-align:center">"""+ str(newTemp) +"""</td>
<td style="text-align:center">"""+ str(newHuminidy) +"""</td>
</tr>
</tbody>
</table>
"""
msg.attach(MIMEText(bodytable, 'html', 'utf-8') )
server = smtplib.SMTP(record[4], record[5])
server.starttls()
server.login(fromaddr, pwd)
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
else:
#最後傳送狀態,0:傳送正常,1:傳送異常
if sendStatus == 0:
goSendMail = True
elif sendStatus == 1:
#最後一次送mail的時間和目前時間相減,相差的秒數大於所設定的sendWaitTime,則再傳送一次異常mail
if sendTimeOffset > sendWaitTime:
goSendMail = True
##傳送溫濕度異常的mail
if goSendMail==True:
update_smtp_send_status(db,newDatetime,1)
msg = MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = toaddr
msg['Subject'] = "Go38 溫濕度異常"
#body = str(record[1]) + "MAIL測試"
if errId==1:
bodytable = """<font color="red">偵測器回傳的溫濕度不在 0~100 之間,未寫入資料庫!</font><br>"""
elif errId==2:
bodytable = """<font color="red">目前時間和資料庫中最後一筆資料的時間超過"""+str(dbTimeOffset)+"""秒就直接寫入資料庫,不比對正負值!</font><br>"""
elif errId==3:
bodytable = """<font color="red">目前溫度與最後一筆資料相比,在"""+str(timeoffset)+"""秒內超過所設定的正負值"""+str(dbDifference)+"""!</font><br>"""
elif errId==4:
bodytable = """<font color="red">目前濕度與最後一筆資料相比,在"""+str(timeoffset)+"""秒內超過所設定的正負值"""+str(dbDifference)+"""!</font><br>"""
elif errId==5:
bodytable = """<font color="red">目前溫度或濕度不在所設定的正常範圍內!</font><br>"""
else:
bodytable = """<font color="red">沒有此errId<br>"""
bodytable += """
<br><font color="blue">*溫度正常範圍:""" + str(dbTempMin) + """ ~ """ + str(dbTempMax) + """ (°C)</font><br>
<font color="blue">*濕度正常範圍:""" + str(dbHumidityMin) + """ ~ """ + str(dbHumidityMax) + """ (%)</font><br>
"""
bodytable += """
<table align="left" border="1" cellpadding="1" cellspacing="1" style="width:500px">
<tbody>
<tr>
<td style="text-align:center"><a href="http://"""+str(record[1])+""" " target="_blank">"""+str(record[1])+"""</a></td>
<td style="text-align:center">日期</td>
<td style="text-align:center">溫度(°C)</td>
<td style="text-align:center">濕度(%)</td>
</tr>
<tr>
<td style="text-align:center">上一筆資料</td>
<td style="text-align:center">"""+ str(lastDatetime) +"""</td>
<td style="text-align:center">"""+ str(lastTemp) +"""</td>
<td style="text-align:center">"""+ str(lastHuminidy) +"""</td>
</tr>
<tr>
<td style="text-align:center">最新資料</td>
<td style="text-align:center">"""+ str(newDatetime) +"""</td>
<td style="text-align:center">"""+ str(newTemp) +"""</td>
<td style="text-align:center">"""+ str(newHuminidy) +"""</td>
</tr>
</tbody>
</table>
"""
# msg.attach(MIMEText(body, 'plain'))
msg.attach(MIMEText(bodytable, 'html', 'utf-8') )
# msg = MIMEText(mail_msg, 'html', 'utf-8')
server = smtplib.SMTP(record[4], record[5])
server.starttls()
server.login(fromaddr, pwd)
text = msg.as_string()
server.sendmail(fromaddr, toaddr, text)
server.quit()
# 更新資料表smtp中的SendTime與SendStatus
def update_smtp_send_status(db,dSendTime,dSendStatus):
cursor = db.cursor()
cursor.execute("update smtp set send_time='"+ str(dSendTime) +"' , send_status='"+str(dSendStatus)+"' where id=0")
db.commit()
# 解密,主要用於資料表中smtp的smtp_password欄位,加密過程還加了一組key,目前設定為"@Go38Box"
def decrypt_des(encrypted):
if encrypted is None:
return ""
try:
key = '@Go38Box'
# ECB方式
generator = DES.new(key, DES.MODE_ECB)
# 解碼
crypted_str = base64.b64decode(encrypted)
# 解密
result = generator.decrypt(crypted_str)
# 替換非空白字元
result = result.strip("")
#print "encrypted : "+str(encrypted)+" cipher :"+result
return result
except Exception, e:
print Exception, ":", e
return ""
# end main
if __name__ == "__main__":
sys.exit(main())
以下的程式主要是用在smtp資料表欄位「smtp_password」,注意裡面有一個變數key,下方測試是使用「1234A#CD」,而溫濕度程式在使用的是「@Go38Box」
#!/usr/bin/python
# coding:utf-8
from Crypto.Cipher import DES
import base64
def encrypt_des(cipher):
if cipher is None:
return ""
try:
key = '1234A#CD'
# ECB方式
generator = DES.new(key, DES.MODE_ECB)
# 未滿8位數補空白
pad = 8 - len(cipher) % 8
pad_str = ""
for i in range(pad):
pad_str = pad_str + chr(pad)
# 加密
encrypted = generator.encrypt(cipher + pad_str)
# 編碼
result = base64.b64encode(encrypted)
print "cipher : "+str(cipher)+" encrypted : "+result
# decrypt_des(result)
return result
except Exception, e:
print Exception, ":", e
return ""
def decrypt_des(encrypted):
if encrypted is None:
return ""
try:
key = '1234A#CD'
# ECB方式
generator = DES.new(key, DES.MODE_ECB)
# 解碼
crypted_str = base64.b64decode(encrypted)
# 解密
result = generator.decrypt(crypted_str)
# 替換非空白字元
result = result.strip("")
print "encrypted : "+str(encrypted)+" cipher :"+result
return result
except Exception, e:
print Exception, ":", e
return ""
encrypt_des('123345678')
decrypt_des('y6xH9zUHiHXjh8Y5CxVMjg==')
以上程式執行結果
cipher : 123345678 encrypted : y6xH9zUHiHXjh8Y5CxVMjg==
encrypted : y6xH9zUHiHXjh8Y5CxVMjg== cipher :123345678
>>>