上一篇我們已經做出一個基本的網頁聊天室,這篇要來做兩件事情,第一件事情「和燈泡聊天」,第二件事情則是「美化聊天室」。
首先來和燈泡聊天,在這邊我們剛剛做的那個頁面可以完全不用更動,如果忘記剛剛的頁面怎麼做的請參考:實戰智慧插座 17 - 打造網頁聊天室和燈泡聊天 ( 原理篇 ),重點在要設計另外一個頁面給燈泡使用 ( 其實就是你用頁面 A,燈泡用頁面 B 和你聊天,這樣才有聊天室的感覺 )。
因為對於燈泡來說,對話的內容不需要顯示出來,只需要在程式內容撰寫對應的邏輯,所以這邊就純粹用 console
印出內容,不過因為我們要透過 Webduino 控制智慧插座,所以一開始在 HTML 的部分要先引入對應的 JavaScript。
<script src="https://www.gstatic.com/firebasejs/3.6.2/firebase.js"></script>
<script src="https://webduino.io/components/webduino-js/dist/webduino-all.min.js"></script>
<script src="https://blockly.webduino.io/webduino-blockly.js"></script>
JavaScript 一開始先對變數做宣告,主要就是初始化 Firebase 資料庫。( 記得要用自己的資料庫呀! )
var firebase;
var led;
var config = {
databaseURL: "你的資料庫網址"
};
firebase.initializeApp(config);
var database = firebase.database().ref();
然後寫一個獲取時間並且可以自動判斷「如果是個位數就補零」的流程,待會會用到。
function getTime() {
var date = new Date();
var h = date.getHours();
var m = date.getMinutes();
var s = date.getSeconds();
if (h < 10) {
h = '0' + h;
}
if (m < 10) {
m = '0' + m;
}
if (s < 10) {
s = '0' + s;
}
var now = h + ':' + m + ':' + s;
return now;
}
再來就是裝置開發板的程式,這邊先宣告智慧插座是接在板子的 10 號腳上,一開始會出現連線中的提示,然後「當裝置上線之後」,就會觸發 database.push
這一段程式,也就是會發一段「我上線了」的訊息進資料庫,也因為資料庫有變動,有連接資料庫的聊天室就會收到燈泡上線的訊息。
boardReady('evkG', function(board) {
board.systemReset();
board.samplingInterval = 250;
led = getLed(board, 10);
console.log('裝置連線中...');
database.push({
name: '智慧燈泡',
content: '我上線囉!',
time: getTime()
});
//主程式...
});
在還沒有寫主程式的狀況下,我們讓裝置上線,這時候就會在聊天室裡頭收到智慧燈泡說「我上線囉!」的訊息。
最後就是主程式,一開始先設定一個 event
的陣列物件,裡面放入收到指定的訊息 ( text ) 後,智慧插座要做的對應行為 ( fn ),還有燈泡要回覆的訊息 ( msg ),接著使用 Firebase 的 .limitToLast(1)
,來獲取最後一筆訊息,然後內容作出對應的判斷,當然這邊寫的判斷非常簡單 ( 單純判斷有沒有包含文字 ),如果有興趣也可以寫得複雜些。
var event = [
{
text:'開燈',
msg:'燈泡已經打開!',
fn:function(){led.on();}
},
{
text:'關燈',
msg:'燈泡已經關起來了!',
fn:function(){led.off();}
},
{
text:'閃爍',
msg:'一閃一閃亮晶晶~',
fn:function(){led.blink(500);}
}
];
database.limitToLast(1).on('value', function(snapshot) {
var s = {};
for(var i in snapshot.val()){
s = snapshot.val()[i];
console.log('('+s.time+') '+s.name+' 說:'+s.content);
for(var j in event){
if(s.content.indexOf(event[j].text)!=-1){
event[j].fn();
database.push({
name: '智慧燈泡',
content:event[j].msg,
time: getTime()
});
}
}
}
});
完成之後我們讓裝置上線,在聊天室打「開燈」、「關燈」或「閃爍」,就可以看到燈泡作出對應的變化,而且燈泡也會把當前的狀態回報在聊天室裡面。
( 程式:http://bin.webduino.io/budiw/2/edit?html,js,output )
剛剛我們看到的是網頁前端的做法,雖然很方便但某種程度上也會受限於瀏覽器,如果你會使用 Node.js 的話,我們就可以讓燈泡聊天的程式跑在後端運作,要使用 Node.js 首先必須安裝 Node.js ( https://nodejs.org/en/download/ )。
基本上現在安裝完成之後就會連同 npm ( node package manager ) 一起安裝,透過 npm 我們就可以安裝對應的 package,打開指令輸入工具,進入開發的目錄,安裝 webduino-js
、webduino-blockly
和 firebase
。( Mac 可能要用 sudo 開頭 )
npm install webduino-js webduino-blockly firebase
安裝好了之後應該會看到你的目錄下多一個 node_modules 的資料夾,裡面包含了所需要的程式內容。
接著建立一個名為 index.js 的檔案,一開始先 require 對應的 package,後面的程式基本上就把剛剛寫得完全複製貼上就可以了。
require("webduino-js");
require("webduino-blockly");
var firebase = require('firebase');
編輯完成存檔之後,在指令輸入 node index
,就可以透過 Node.js 操控智慧插座上頭的燈泡,我們在前端網頁的聊天室,也就會看到出現燈泡上線的訊息。
然後我們就可以開始聊天控制燈泡,不論在燈泡、前端、後端或是資料庫,都可以看到即時的變化。
到這邊為止基本上我們已經幾乎完成所有的工作,最後一步就是美化一下我們的聊天室,而美化的工作幾乎全部都在 CSS 身上,為了讓設計的結構更完整,我這邊稍微調整了一下 HTML,目的是「讓輸入框在最底下,而訊息顯示在上方」。
<div id="im">
<div id="input">
<div>
<span>姓名:</span><input id="name"><br/>
<span>內容:</span><input id="content">
</div>
<button id="btn">送出訊息</button>
</div>
<div id="show"></div>
</div>
CSS 的部分先看到最外層,設定背景色,以及把對話區域的背景色設為半透明的黑色,同時指定最大的寬度與置中, box-sizing
的目的在於不要讓 padding
影響了實際的寬度。
body,html{
width:100%;
height:100%;
margin:0;
padding:0;
background:url(http://www.oxxostudio.tw/firebase-webduino-im/bg2.jpg);
background-size:cover;
}
#im{
position:relative;
margin:0 auto;
width:100%;
max-width:600px;
height:100%;
box-sizing:border-box;
background:rgba(0,0,0,.4);
}
接下來這幾段則是輸入框的部分,首先把位置設為 absolute
這樣我們才可以將其固定在最下方 ( 不要用 fixed
因為 fixed
是針對最外層視窗 ),z-index
設為 2 讓輸入框可以在比較高層的位置,接下來的幾個屬性是在編排輸入框的內容位置。
#input{
position:absolute;
z-index:2;
height:90px;
width:100%;
left:0;
bottom:0;
margin:0;
padding:15px;
box-sizing:border-box;
background:#222;
color:#fff;
}
#input input, #input span{
display:inline-block;
margin:5px 0;
}
#input input{
width:75%;
border:none;
padding:5px;
}
#input span{
width:10%;
min-width:50px;
}
#input div{
width:80%;
float:left;
}
#input button{
float:right;
height:90%;
width:20%;
margin:5px 0;
border:none;
padding:0;
background:#369;
font-size:16px;
color:#fff;
}
再來看到訊息顯示區域,同樣位置設定為 position
,高度直接用 CSS 的計算功能,記得減去最下方輸入框的高度,然後透過 overflow-y
讓 y 軸出現捲軸而不會超過版面,其他的屬性大概都是在設定對話區域的樣式、時間的樣式...等。
#show{
position:absolute;
top:0;
left:0;
z-index:1;
width:100%;
height:calc(100% - 90px);
overflow-y:scroll;
padding:20px;
box-sizing:border-box;
}
#show>div{
position:relative;
margin:0 0 20px 0;
clear:both;
height:40px;
}
#show>div>div{
display:inline-block;
}
#show .time{
position:absolute;
top:-2px;
font-size:10px;
color:#777;
}
#show .name{
color:#fff;
vertical-align:middle;
}
#show .content{
background:rgba(255,255,255,.8);
padding:10px;
margin-top:15px;
margin-left:10px;
border-radius:5px;
vertical-align:middle;
}
最後這段的目的在設定捲軸樣式,不過基本上只有支援 webkit
的瀏覽器才支援就是了。
#show::-webkit-scrollbar {
width:5px;
}
#show::-webkit-scrollbar-track {
background:rgba(255,255,255,.1);
border-radius: 5px;
}
#show::-webkit-scrollbar-thumb {
background:rgba(255,255,255,.2);
border-radius: 2px;
}
不過只有 CSS 還不夠,因為我們的對話內容是動態產生,而且我還想要讓「自己」發出的對話會有點不同 ( 例如說位置在右邊 ),所以 JavaScript 裡面就動態產生一些 style 套進去,當中 $show.scrollTop($show[0].scrollHeight);
這段比較特別,因為我們之前是用 prepend
把新訊息放在最上面,而這邊適用 append
把新的訊息放在最下面,間接導致輸入完訊息會看不到最新的內容,所以就透過網頁捲軸的操控,讓每次捲軸都能保持在最下方的位置。
database.limitToLast(1).on('value', function(snapshot) {
for(var i in snapshot.val()){
$show.append('<div class="'+snapshot.val()[i].id+'"><div class="time">'+snapshot.val()[i].time+'</div><div class="name">'+snapshot.val()[i].name+' 說</div><div class="content">'+snapshot.val()[i].content+'</div>');
}
$show.scrollTop($show[0].scrollHeight);
$show.find('.id'+ms+' .name').css({
'float':'right',
'padding-top':'12px',
'color':'#fc0'
});
$show.find('.id'+ms+' .content').css({
'float':'right',
'margin-right':'10px'
});
$show.find('.id'+ms+' .time').css({
'right':'0',
'color':'#777'
});
});
完成後來實際測試看一下長相,總算是比較有聊天室的樣子了,這時候如果我們打開前端的燈泡網頁,或是剛剛後端的 Node.js 程式,就可以在這個聊天室裡面真正和燈泡聊天囉!
( 聊天室:http://bin.webduino.io/luxe/1/edit?html,css,js,output )
其實透過 FireBase 來實做一個聊天室非常的簡單,我真正花時間的地方反而是在美化聊天室,當然如果背後邏輯能再多花一點時間優化,就可以做出更多種的變化與應用,不然以現在的例子,你輸入「不要開燈」,燈泡還是會打開喔!XD 畢竟沒有做更複雜的判斷,只是判斷有沒有包含字詞而已。
然後我自己比較喜歡把「燈泡」部分的程式運作在後端,畢竟瀏覽器的程式只要瀏覽器關起來就沒作用了,運行在後端至少就可以 24 不間斷的運作。
最後,我們其實也可以透過 Webduino Blockly 編輯工具 ( https://blockly.webduino.io ) 做出燈泡的聊天主程式,因為線上工具真的是做得非常強大呀!
( 解答:https://blockly.webduino.io/#-K_PVGorhJTD6vbECkiw )