PlayLoud!!

Since1997

arduinoで気温をツイート

arduinoイーサネットシールドと温度センサLM35を接続してみました。

こんな感じで室温をツイートします。
https://twitter.com/#!/keigox68000/status/166234898166849537
スケッチ(プログラム)はいろんなところから借りてきたコードを切り貼りしてます。(この記事の最後に掲載)
Twitter関連は、NeoCatさんのArduinoからTwitterにPOSTするライブラリ OAuth版を参考にしてます。
温度センサ関連は、書籍を参考にしてます。

たのしい電子工作 Arduinoで電子工作をはじめよう!

たのしい電子工作 Arduinoで電子工作をはじめよう!

で、温度を実数でツイートすると桁数が大きくてうるさいので、小数点第一位まで表示するようにしたらsprintfで大ハマりしました。
arduinoのsprintfは固定小数点が「?」に化けるバグ(?)があるらしく、いろいろ検索してそれに気づくまでに何時間もかかってしまいました。くっそー
http://dereenigne.org/electronics/arduino/arduino-float-to-string
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1164927646

国内で同じような情報が見つけられませんでした……やっぱり海外のサイトも積極的に見ないとダメだなぁ。
結局、LM35から取得した数値を温度に変換したものを10倍してから整数部分だけを文字列に格納(小数点第一位まで求めて)、その文字列に小数点を挿入するという回りくどい方法で小数点第一までの温度を表示することにしました。

そんなわけでarduinoと便利なライブラリのおかげで定期的に室温をツイートするところまでは行けたのですが、室温が変わらない場合はTwitterの制限で連続ポストできないため、温度に時刻を付加してポストするようにしてみました。

ntpサーバから時刻を取得するのですが、こちらはarduino IDEのサンプルと、なんでも作っちゃう、かも。さんの「Arduinoで遊ぼう - NTPを使ってインターネット経由で時刻をあわせる」の記事がとても参考になりました。
 
とりあえず、arduinoを使ってデータを取得してツイートするところまではできたので、これから本番に移ります。室温なんかポストしてもTL汚すだけなのでもっと別なことで遊んでみます(笑)
 
気温を計測してポストする(必要ないコードなど残っていますが参考まで)

#include <SPI.h> // needed in Arduino 0019 or later
#include <Ethernet.h>
#include <Twitter.h>
#include <EthernetUdp.h>
#include <Time.h>

// The includion of EthernetDNS is not needed in Arduino IDE 1.0 or later.
// Please uncomment below in Arduino IDE 0022 or earlier.
//#include <EthernetDNS.h>

// Ethernet Shield Settings
byte mac[] = { 0x**, 0x**, 0x**, 0x**, 0x**, 0x** };

// UDPローカルポート番号
unsigned int localPort = 8888;

// NTPタイムサーバIPアドレス(ntp.nict.jp NTP server)
IPAddress timeServer(133, 243, 238, 164);

// NTPパケットバッファサイズ
const int NTP_PACKET_SIZE= 48;

// NTP送受信用パケットバッファ
byte packetBuffer[NTP_PACKET_SIZE];

// Udpクラス
EthernetUDP Udp;

// 最後にパケットを送信した時間(ミリ秒)
unsigned long lastSendPacketTime = 0;

// If you don't specify the IP address, DHCP is used(only in Arduino 1.0 or later).
byte ip[] = { イーサネットシールドのIPアドレスをカンマ区切りで };

// Your Token to Tweet (get it from http://arduino-tweet.appspot.com/)
Twitter twitter("〜あなたの取得したトークン〜");

// Message to post
char msg[256];

#define  LM35_IN  0

void  setup()
{
 delay(1000);
 Ethernet.begin(mac, ip);
 Serial.begin(9600);

 Udp.begin(localPort);

 // 最初の時刻リクエストを送信
 sendNTPpacket(timeServer);
 lastSendPacketTime = millis();
}

void  loop()
{
 if ( millis() - lastSendPacketTime > 13000 ){
   // NTPサーバへ時刻リクエストを送信
   sendNTPpacket(timeServer);
   // 時間を更新
   lastSendPacketTime = millis();
 }  

   // NTPサーバからのパケット受信
 if ( Udp.parsePacket() ) {
   // バッファに受信データを読み込む
   Udp.read(packetBuffer, NTP_PACKET_SIZE);

   // 時刻情報はパケットの40バイト目からはじまる4バイトのデータ
   unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
   unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);

   // NTPタイムスタンプは64ビットの符号無し固定小数点数(整数部32ビット、小数部32ビット)
   // 1900年1月1日0時との相対的な差を秒単位で表している
   // 小数部は切り捨てて、秒を求めている
   unsigned long secsSince1900 = highWord << 16 | lowWord;
//    Serial.print("Seconds since Jan 1 1900 = " );
//    Serial.println(secsSince1900);

   // NTPタイムスタンプをUNIXタイムに変換する
   // UNITタイムは1970年1月1日0時からはじまる
   // 1900年から1970年の70年を秒で表すと2208988800秒になる
   const unsigned long seventyYears = 2208988800UL;
   // NTPタイムスタンプから70年分の秒を引くとUNIXタイムが得られる
   unsigned long epoch = secsSince1900 - seventyYears;  
   Serial.print("Unix time = ");
   Serial.println(epoch);

   // Timeライブラリに時間を設定(UNIXタイム)
   // 日本標準時にあわせるために+9時間しておく
   setTime(epoch + (9 * 60 * 60));

 int  temp_in,ht,mt,st,i;
 float  temp;
 char  disp[20]="";
 char  disp1[20]="";
 char  h[20],m[20],s[20];

 ht = ((epoch + 32400) % 86400L) / 3600;
 mt = ((epoch + 32400) % 3600) / 60;
 st = (epoch + 32400) % 60;
 sprintf(h,"%02d:",ht);
 sprintf(m,"%02d:",mt);
 sprintf(s,"%02d",st);

 temp_in = analogRead(LM35_IN);
 temp = (float)(temp_in) * (float)(0.0048) * (float)1000;
 itoa(temp,disp,10);
 strncpy(disp1,disp,strlen(disp)-1);
 strcat(disp1,".\0");
 strcat(disp1,&disp[strlen(disp)-1]);

 strcpy(msg,"現在の室温 ");
 strcat(msg,disp1);
 strcat(msg," ℃ (");
 strcat(msg,h);
 strcat(msg,m);
 strcat(msg,s);
 strcat(msg,") #Arduino");

 Serial.println(msg);

Serial.println("connecting ...");
 if (twitter.post(msg)) {
   int status = twitter.wait(&Serial);
   if (status == 200) {
     Serial.println("OK.");
   } else {
     Serial.print("failed :code ");
     Serial.println(status);
   }
 } else {
   Serial.println("connection failed.");
 }

 Serial.print(temp, 1);
 Serial.print("\n");
 }

 Serial.print("wait...");
 Serial.print("\n");
 // wait
 unsigned long waitTime = 60000UL*58UL;
 delay(waitTime);

}

// send an NTP request to the time server at the given address 
unsigned long sendNTPpacket(IPAddress & address)
{
 // set all bytes in the buffer to 0
 memset(packetBuffer, 0, NTP_PACKET_SIZE); 
 // Initialize values needed to form NTP request
 // (see URL above for details on the packets)
 packetBuffer[0] = 0b11100011;   // LI, Version, Mode
 packetBuffer[1] = 0;     // Stratum, or type of clock
 packetBuffer[2] = 6;     // Polling Interval
 packetBuffer[3] = 0xEC;  // Peer Clock Precision
 // 8 bytes of zero for Root Delay & Root Dispersion
 packetBuffer[12]  = 49; 
 packetBuffer[13]  = 0x4E;
 packetBuffer[14]  = 49;
 packetBuffer[15]  = 52;
 // all NTP fields have been given values, now
 // you can send a packet requesting a timestamp:
 // NTP requests are to port 123
 Udp.beginPacket(address, 123);
 Udp.write(packetBuffer, NTP_PACKET_SIZE);
 Udp.endPacket();
}