2014年8月21日 星期四

使用 Arduino 製作 溫控灑水系統 (1.草案)

最近有個計畫,就是使用 Arduino 來製作一個溫控灑水系統(系統需求還在腦袋中...)。
想說可以用來替頂樓的屋頂,加上一個灑水系統來降溫,也或許可以拿來做一些溫控的用途,也當作第一個實作。

但對於 Arduino 只屬於網路上看過模擬的階段,還沒有實作過,所以現在先開始蒐集一些網路上的資源。

除了 Arduino 官網一定要看看外,目前也加入了 Arduino.Taipei  Arduino.Taiwan的粉絲團。

網誌目前有前輩們:柯博文老師,葉難,Cooper Ma, Open Knowledge(知識開源共享), 大兵萊恩 一路直前, 請繼續推薦...

一個創意的分享網站 Instructables,

工具的資源目前有: Fritzing , 123D Curcuit ,

還有 曹永忠 老師製作的免費 Arduino 電子書,

看到前輩們很多都是用 Frizing 來製作線路圖,所以也已經下載並安裝完成,不過才剛開始測試,有問題再請教大家。

123D Circuit 好像是 AutoDesk 公司的產品,註冊了免費帳號,測試了一下,發現這個工具還不錯,可以直接模擬運行電路的結果,而且還可以模擬執行 Arduino 程式,很好玩!! 只是不知道是免費帳號的原因,可以使用的電子元件好像不多,就...再研究囉!!
我在 123D 製作的幾個測試 線路一,線路二 , 線路三 ...

目前大概整理這些資源,如果還有大家推薦,會再補上。

對於 Arduino 還有電學的設計規劃上,希望大家的建議及指導,也希望可以用實作方式來完成這個系統。線路及程式會同步分享在網誌上。


2014年8月12日 星期二

Generate QR Code by using Google Chart API

API Reference 基本上就是參考這裡:
https://google-developers.appspot.com/chart/infographics/docs/qr_codes

API Root URL 網址:
https://chart.googleapis.com/chart?

會用到的參數大致就這四個:
cht=qr //這是固定一定要的chs=<width>x<height> //產生QR Code圖的寬高
choe=UTF-8 //編碼預設定UTF-8,所以也可以不設定
chl=Hello%20world //QR Code的內容
chld=<error_correction_level>|<margin> //容錯率 預設是L(7%)也可以設定 M/Q/H
margin 是留邊,單位是QR Code的內格區塊寬度數,預設是4



比較重要的地方是:因為是以URL傳送,所以QR Code內容需要先做 URI 編碼動作,
把一些如空白或一些特殊字元轉成%XX的16進位碥碼,以避免出現錯誤的內容。
若是在 JavaScripte 中可以用 encodeURIComponent(uri); 先把內容編碼。
PHP 中則可用 string urlencode ( string $str ); 函數來編碼。

所以直接以API網址來產生QR Code的例如下(Sample URL):
https://chart.googleapis.com/chart?cht=qr&chs=200x200&chld=L|0&chl=Hello%20world


或是以 JavaScripte 來動態產生(generate by JavaScript dynamically):



補上一個網路分享的QR Code(還有Bar Code等的)解碼器(Chart Decode Tool)
http://zxing.org/w/decode.jspx

2013年12月26日 星期四

Javascript 如何檢查日期的合法性? How to check the DATE is valid in Javascript?


其實如果是用 DateTime Picker 就應該不會有這樣的需求,
但規劃是用 年 / 月 / 日 各別的下拉選單,就有可能出現像是 2月30 or 31這樣的日期。
而且如果還要自行判斷是否為閏年或是大小月就更麻煩了。

利用 Javescript 中的 Date Object 來幫忙做處理是最方便不過的。
但是 Date Object 中卻沒有 method 可以用來做日期的合法檢查。

.valueOf() 和 .getTime() 是會回傳 NaN 沒錯,但那只有在日期是超過處理範圍時才會發生。

new Date( '2005-02-31' ) 並不會被認為非法,但最後會被轉換為 '2005-03-03'

所以也正好利用這個點去檢查,是否輸入的日期是合法的。

// 傳入 年月日 檢查是否為合法日期
function validDate( _year, _month, _day )
{
  var Day = new Date( _year+ '-' + _month+ '-' + _day);
  var chk = new Date( Day.valueOf() );
  return (chk.getFullYear()==_year && (chk.getMonth()+1)==_month && chk.getDate()==_day);
}
以上

Use Javascript Date() Object to convert date-time info. But JS Date Object didn't have a method to check if the DATE is valid.

.valueOf() and .getTime() can get NaN. But it is only returned when out of DATE-TIME rang.

Date( '2005-02-31' ) will be accepted, but will be converted into '2005-03-03'.

So I can check the _year,_month &_day if the same after Date() converted.

2013年9月26日 星期四

MySQL 如何用 SELECT 查詢 產生一個自動遞增的序號欄位

因為要跑活動績分排行,而這個排行又是以某項欄位總和做排序 給績分,所以希望撈出的資料 在 SUM, GROUP 及 ORDER 後,還可以再依序給一個排行績分的欄位。

因為是持續三週的活動,且每天都有每日的績分排行(前20名的績分依序就是20,19,18...到1分),每週還有週排行,週排行就是將每個Player該週的績分加總排序即可。

所以用了一個活動資料表,來記錄每個玩家每日的績分:

CREATE TABLE `tbl_event_A` (
  `sn` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'SN',
  `playerid` int(11) unsigned NOT NULL COMMENT 'PlayerID',
  `logday` int(11) unsigned NOT NULL COMMENT '記錄日期',
  `winpoint` int(11) NOT NULL COMMENT '日總贏點數',
  `score` int(11) NOT NULL COMMENT '日績分',
  `week` tinyint(3) NOT NULL COMMENT '週次',
  PRIMARY KEY (`sn`),
  KEY `logdate` (`logday`)
) ENGINE=MyISAM;

希望從原始資料表撈出的排序資料及績分,可以在一個 Query 動作中完成,所以會需要在 Select 動作中,帶出一個有遞增績分欄位。

上網做相關的搜尋,一開始連要搜尋怎麼的關鍵詞都摸不著頭序,就一直試,後來發現搜尋 "select 查詢 自動 序號" 這樣的結果最多相關的結果。
有不少回應是 MS SQL 本身才支援的語法,像是 RANK() OVER() ROW_NUMBER() 語法,可參考 這裡

反而 MySQL 的討論不多,後來後搜尋英文 mysql select auto increment number ,才有較多的
討論。

原來是利用 MySQL 中臨時(暫時)變數的方式來做遞增,簡單範例如下:
SELECT @s:=@s+1 serial_number, student_id, student_name, student_avg
FROM students, (SELECT @s:= 0) AS s
WHERE student_avg > 4;

於是馬上就把它套用到我的查詢裡面:
SELECT @SN:=@SN+1 as Score, PlayerID, SUM(winpoint) as WinPoint 
FROM tbl_dailyplayerpoint,(SELECT @SN:=0) as Dummy 
WHERE logday='$Yesterday' 
GROUP BY PlayerID 
ORDER BY WinPoint DESC 
LIMIT 20;
試了發現的確可以產生一個遞增的欄位,但放在我的 query 中,經過 SUM, GROUP 及 ORDER BY 後,帶出的數值很奇怪,是一些很大的數字,且沒有規律。
+-------+----------+----------+
| Score | PlayerID | WinPoint |
+-------+----------+----------+
|    31 |        4 | 20441389 |
|    60 |       31 | 12158264 |
|    35 |       10 | 11551464 |
|    41 |       23 |  8594067 |
|    46 |       34 |  7555544 |
|    29 |        1 |  7475172 |
|    42 |       24 |  6409297 |
|    62 |       11 |  6393142 |
|    78 |       54 |  5791644 |
|    45 |       33 |  5757180 |
|    47 |       35 |  5689378 |
|    70 |       44 |  5649346 |
|    34 |        8 |  5590604 |
|    86 |       56 |  5470747 |
|    44 |       32 |  5289877 |
|    40 |       22 |  5080401 |
|    81 |       22 |  4591810 |
|     2 |       25 |  4446734 |
|    75 |       93 |  4431110 |
|    63 |       68 |  4430356 |
+-------+----------+----------+
於是在想,是不是因為這個臨時的變數在經過 GROUP 後,因為不同的資料量而被加總了不同次而不同,不是想像中的由小到大。

最後,經過不同的常試修改,試出了這個方式,也就是把 @SN:=@SN+1 移出原始query,把原查詢變成一個子查詢,@SN:=@SN+1放到外層,這樣 @SN 就不會受到 GROUP 的影響而產生不定數的值。
SELECT 21-(@SN:=@SN+1) as Score, PlayerID, WinPoint 
FROM (SELECT PlayerID, SUM(winpoint) as WinPoint 
      FROM tbl_dailyplayerpoint 
      WHERE logday='$Yesterday' 
      GROUP BY PlayerID 
      ORDER BY WinPoint DESC 
      LIMIT 20) as Dummy1, 
(SELECT @SN:=0) as Dummy2;
撈出的結果看來就是我想要的!!
+-------+----------+----------+
| Score | PlayerID | WinPoint |
+-------+----------+----------+
|    20 |        4 | 20441389 |
|    19 |       31 | 12158264 |
|    18 |       10 | 11551464 |
|    17 |       23 |  8594067 |
|    16 |       34 |  7555544 |
|    15 |        1 |  7475172 |
|    14 |       24 |  6409297 |
|    13 |       11 |  6393142 |
|    12 |       54 |  5791644 |
|    11 |       33 |  5757180 |
|    10 |       35 |  5689378 |
|     9 |       44 |  5649346 |
|     8 |        8 |  5590604 |
|     7 |       56 |  5470747 |
|     6 |       32 |  5289877 |
|     5 |       22 |  5080401 |
|     4 |       22 |  4591810 |
|     3 |       25 |  4446734 |
|     2 |       93 |  4431110 |
|     1 |       68 |  4430356 |
+-------+----------+----------+

於是我就可以在一個 query 中,直接撈出並新增到所建立的活動資料表中了!!
 
INSERT INTO tbl_event_A (score,playerid,winpoint,logday,week) 
SELECT 21-(@SN:=@SN+1), PlayerID, WinPoint,'$Yesterday','$week' 
FROM (SELECT PlayerID, SUM(winpoint) as WinPoint 
      FROM tbl_dailyplayerpoint 
      WHERE logday='$Yesterday' 
      GROUP BY PlayerID 
      ORDER BY WinPoint DESC 
      LIMIT 20) as Dummy1,
(SELECT @SN:=0) as Dummy2;
寫好的 PHP 用 cron table 設定每日早上跑,去產生昨天的排行!!
以上經驗,分享給大家!!