Arduinoで気象観測データサーバを構築し、Raspberry Piでデータを取得、音声出力する。
Arduinoを無線LAN接続にちらりと気象観測データサーバのことを書いたきり、あっという間に3か月以上経ってしまった。サーバへの接続リクエストをトリガにして休止モードから復帰できたらいいな、などと考えていたのだが、勤め人には勉強する時間が乏しく、何よりその能力に欠けていることに気づいた。無念である。ともあれ、お盆休みで到達したところまでを公開するものである。
気象観測データサーバ
サーバは、汎用性を持たせるため、HTTPサーバとしてHTMLデータを出力することにした。下記のスケッチはArduino付属のスケッチ例WebServerをほぼそのまま流用している。MAC
とADDRESS
の値は適宜変更のこと。
/*
* Weather Data Server
* Based on the Example Scketch "WebServer", which was
* created 18 Dec 2009
* by David A. Mellis
* modified 9 Apr 2012
* by Tom Igoe,
* Copyright 2014 FireWheel <firewheel@m40.coreserver.jp>
* GNU General Public License V3
* see <http://www.gnu.org/licenses/>
*/
#include <SPI.h>
#include <Ethernet.h>
#include <RHT.h>
#include <MPL.h>
#include <Wire.h>
const unsigned int PORT = 80;
const char CR = 0x0D;
const char LF = 0x0A;
const char QQ = 0x22; // double quotation mark
const String CHARSET = "UTF-8";
byte MAC[] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX};
uint8_t ADDRESS[] = {192, 168, 0, 101};
IPAddress ip(ADDRESS);
EthernetServer server(PORT);
void setup() {
Ethernet.begin(MAC, ip);
MPL.begin();
}
void loop() {
EthernetClient client = server.available();
if (client) {
boolean current_line_is_blank = true;
while (client.connected()) {
if (!client.available())
continue;
char c = client.read();
if (c == LF && current_line_is_blank) {
send_response_message(client);
break;
}
current_line_is_blank
= (c == LF) ? true
: (c != CR) ? false
: current_line_is_blank
;
}
delay(1);
client.stop();
}
}
void send_response_message(EthernetClient client) {
String content_type = "Content-Type: text/html; charset=" + CHARSET;
String meta_charset = "<meta charset=" + quoted(CHARSET) + ">";
String dd_temperature
= "<dd id=" + quoted("temperature") + ">" + RHT.thermoString() + "</dd>";
String dd_humidity
= "<dd id=" + quoted("humidity") + ">" + RHT.hygroString() + "</dd>";
String dd_atmosphere
= "<dd id=" + quoted("atmosphere") + ">" + MPL.atmString() + "</dd>";
client.println("HTTP/1.1 200 OK");
client.println("Connection: close");
client.println(content_type);
client.println();
client.println("<!DOCTYPE html>");
client.println("<html>");
client.println("<head>");
client.println(meta_charset);
client.println("<title>Weather Data</title>");
client.println("</head>");
client.println("<body>");
client.println("<dl>");
client.println("<dt>temperature</dt>");
client.println(dd_temperature);
client.println("<dt>humidity</dt>");
client.println(dd_humidity);
client.println("<dt>atmosphere</dt>");
client.println(dd_atmosphere);
client.println("</dl>");
client.println("</body>");
client.println("</html>");
}
String quoted (String to_quote) {
return QQ + to_quote + QQ;
}
気象観測データクライアント
クライアントは使い慣れたPerlで作成した。まず、スクレイピングに必要なURI、Web::Scraper両モジュールをインストールする。Smart::Commentsはデバッグ用なので、お好みでどうぞ。
> sudo apt-get install liburi-perl > sudo apt-get install libweb-scraper-perl > sudo apt-get install libsmart-comments-perl
折角Raspberry Piでデータを受けるのだから、結果を音声出力させる。Raspberry Piの設定には明記していなかったが、ダウンロードしたパッケージはホームディレクトリ直下で展開している。
#!/usr/bin/env perl
# weather_data_client.pl - 気象データを取得して出力する
# Copyright 2014 FireWheel <firewheel@m40.coreserver.jp>
# GNU General Public License V3
# see <http://www.gnu.org/licenses/>
use 5.10.0;
use strict;
use warnings;
use utf8;
use URI;
use Web::Scraper;
#use Smart::Comments;
my $URI = q{http://192.168.0.101};
my $COMMAND_FORMAT = q{~/aquestalkpi/AquesTalkPi %s | aplay >/dev/null 2>&1};
my $TIME_TEXT_FORMAT = q{%d時%d分};
my $WEATHER_TEXT_FORMAT
= q{"気温 %.1f度、湿度 %.1fパーセント、気圧 %.1fヘクトパスカル"};
my $scraper = scraper {
process '#temperature', temperature => 'TEXT';
process '#humidity', humidity => 'TEXT';
process '#atmosphere', atmosphere => 'TEXT';
result 'temperature', 'humidity', 'atmosphere';
};
my $weather_data_ref = $scraper->scrape(URI->new($URI));
my ($hour, $minute) = (localtime)[2, 1];
### $weather_data_ref
my $time_text = sprintf $TIME_TEXT_FORMAT, $hour, $minute;
my $weather_text = sprintf $WEATHER_TEXT_FORMAT,
$weather_data_ref->{temperature},
$weather_data_ref->{humidity},
$weather_data_ref->{atmosphere};
my $time_command = sprintf $COMMAND_FORMAT, $time_text;
my $weather_command = sprintf $COMMAND_FORMAT, $weather_text;
qx{$time_command};
qx{$weather_command};
__END__
cron(8)で15分毎に出力させる、などという使い方も面白いかもしれない。
コメント