
九保すこひです(フリーランスのITコンサルタント、エンジニア)
さてさて、私は夏生まれなのですが、年を追うごとに少しずつ苦手になってきているものがあります。
それが・・・・・・
夏の暑さ
です。
おそらく気候変動の影響もあって夏の気温が高くなっていることもあって、さすがに最近はエグいことになってますよね。
なお、そんな「暑いな…」という曖昧なことは分かるんですけど、なぜか、
どれぐらいのレベルで暑いか?
が直感で分からないんです。(うーん、子供の頃に外で遊び過ぎて温度感覚が麻痺しちゃったのかもです)
そこで
今回はLaravel
を使って、28℃
を超えたら「熱中症アラーム」メールを送信できる機能を実装してみることにしました。
何かの参考になりましたら嬉しいです。
「近くに『ガツンとみかん』
が売ってない…」
目次 [非表示]
やりたいこと
今回やりたいことは、以下のとおりです。
- 気温が 28℃ を超えたら「熱中症アラーム」メールを送信
- 何回も通知が来たらうっとおしいのでメール送信後3時間はメールしない
- 寝てる時にメールが来たらうっとおしいのでメール送信しない
では、実際に作業を進めていきましょう
OpenWeatherMap API を使えるようにする
今回、天気情報は OpenWeatherMap API を使いますので、以下のページを参考にして「API キー」を取得しておいてください。
参考ページ: OpenWeatherMapに登録する
そして、API キーを取得したら.env
へセットしておいてください。
.env
OPEN_WEATHER_MAP_API=*******************
メール送信する部分をつくる
では、コマンドよりも先に「熱中症、要注意」メールが送信できるようにしていきましょう。
Mailable をつくる
まずは、Laravel
でメール送信する際に便利なMailable
をつくります。
以下のコマンドを実行してください。
php artisan make:mail TemperatureExceeded
すると、ファイルが作成されるので中身を次のようにします。
app/Mail/TemperatureExceeded.php
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class TemperatureExceeded extends Mailable
{
use Queueable, SerializesModels;
private $threshold_temperature;
private $current_temperature;
public function __construct($threshold_temperature, $current_temperature)
{
$this->threshold_temperature = $threshold_temperature;
$this->current_temperature = $current_temperature;
}
public function build()
{
$subject = '【熱中症アラート】';
$from = 'from@example.com';
return $this
->from($from, config('app.name'))
->subject($subject)
->view('emails.temperature_exceeded', [
'threshold_temperature' => $this->threshold_temperature,
'current_temperature' => $this->current_temperature,
]);
}
}
メールのテンプレート(ビュー)をつくる
次に、先ほどのTemperatureExceeded
で設定したテンプレート(ビュー)を作成します。(つまりメールの文面ですね)
resources/views/emails/temperature_exceeded.blade.php
<h3>気温が {{ $threshold_temperature }} ℃ を超えました。(現在: {{ $current_temperature }}℃)</h3>
電気代は気にせずクーラーつけよう!<br>
熱中症になったらもっとお金かかるよ 😭
これでメール送信部分は完了です
温度を監視する独自 Artisan コマンドをつくる
では、ここからが本題です。
今回は1時間ごとに温度をチェックしたいので、タイマー実行しやすい独自Artisan
コマンドをつくっていきます。
以下のコマンドを実行してください。
php artisan make:command CheckTemperatureCommand
するとファイルが作成されるので、中身を以下のように変更します。
app/Console/Commands/CheckTemperatureCommand.php
<?php
namespace App\Console\Commands;
use App\Mail\TemperatureExceeded;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Mail;
class CheckTemperatureCommand extends Command
{
// 天気情報を取得する場所(東京スカイツリー)
const LATITUDE = '35.710079006659114';
const LONGITUDE = '139.8106985886275';
const TO_EMAIL_ADDRESS = 'to@example.com';
protected $signature = 'check:temperature
{--threshold=28 : The temperature threshold}
{--start=7:00 : The start time}
{--end=23:00 : The end time}
{--ignore=3 : The number of hours to ignore}';
protected $description = 'Check temperature';
public function handle()
{
$threshold_temperature = intval($this->option('threshold'));
$ignore_hours = intval($this->option('ignore'));
$start_dt = new Carbon($this->option('start'));
$end_dt = new Carbon($this->option('end'));
$now = now();
// 時間チェック
if(! $now->between($start_dt, $end_dt)) {
$this->info('有効時間外です');
return Command::SUCCESS;
}
// 温度を取得
$current_temperature = $this->getTemperature();
if(is_null($current_temperature)) {
$this->error('気温の取得に失敗しました');
return Command::FAILURE;
}
// 条件が合えばメール送信
$last_email_date_time = cache('last_email_date_time');
if(is_null($last_email_date_time) || $now->diffInHours($last_email_date_time) > $ignore_hours) { // 基準時間以上経過している場合はメール送信可
if($current_temperature > $threshold_temperature) { // 温度が基準を超えたかどうかチェック
$this->info('気温が基準を超えました');
$this->sendEmail($current_temperature);
cache(['last_email_date_time' => $now]);
} else {
$this->info('気温は基準内です');
}
} else {
$this->info('メール送信後、時間が経過していません');
}
return Command::SUCCESS;
}
private function getTemperature()
{
$temperature = null;
$api_key = env('OPEN_WEATHER_MAP_API'); // 本来はコンフィグに登録すべきです
$url = 'https://api.openweathermap.org/data/2.5/weather?'.
'lat='. self::LATITUDE .'&'.
'lon='. self::LONGITUDE .'&'.
'appid='. $api_key .'&'.
'units=metric';
$response = Http::get($url);
if($response->ok()) {
$data = $response->json();
$temperature = Arr::get($data, 'main.temp');
}
if(! is_null($temperature)) {
return intval(
round($temperature) // 小数点以下を四捨五入
);
}
return null;
}
private function sendEmail($current_temperature)
{
$to = self::TO_EMAIL_ADDRESS;
$threshold_temperature = intval($this->option('threshold'));
Mail::to($to)->send(
new TemperatureExceeded($threshold_temperature, $current_temperature)
);
}
}
この中で重要なのがいくつかのオプションです。
というのも、アラームメールの取得はお好みで数字や時間を変更できるようにしてるんですね。
ということで、ひとつずつ内容をご紹介しましょう。
- –threshold: 何度を超えたらメールを送るか?デフォルトは 28℃
- –start: メール送信を許可する開始時間(寝てる時メール送信しないため)。デフォルトは「7:00」
- –end: メール送信を許可する終了時間(上と同じ)。デフォルトは、「23:00」
- –ignore: 一回メール送信したらその後何時間送信しないか(毎時間ごとにくるとうっとおしいので)。デフォルトは3時間
Cron でタイマー実行できるようにする
では、php artisan check:temperature
がcrontab
でタイマーするやり方をご紹介します。
環境により違ってきますが、以下のようにすることで毎時間ごとに今回つくったコマンドを実行することができます。
0 * * * * /usr/bin/php /PATH/TO/YOUR/LARAVEL/artisan check:temperature
サンプルは毎時0分に実行されます。
テストしてみる
では、実際にテストしてみましょう
なお、今回のコードは基準の気温(28℃)を超えていないとメール送信されないため、以下のように絶対に50℃(熱波…)が取得されるようにして実行することにします。
private function getTemperature()
{
return 50; // TEST:
// 以下省略
では、コマンドで以下を実行してみます。
php artisan check:temperature
すると・・・・・・
はい
気温が超えたと判別されました。
では、メールの方も確認してみましょう。
どうなったでしょうか・・・・・・
はい
うまくメールが届きました
では、最後に「一回メール送信したら、3時間は追加でメール送信しない」機能がうまくいっているか確かめて見ましょう。
このまま同じコマンドを実行します。
うまくいくでしょうか・・・・・・
はい
メール送信はスキップされました。
全て成功です
企業様へのご提案
今回のように、API
とタイマー実行を組み合わせることでいろいろと便利な機能を実装することができます。
例えば、
- 株価を監視して、独自の売買アラームをつくる
- 天気を監視して、自動で割引セール内容を切り替える
- 電車の遅延情報を監視して、社員全員に通知してあげる
- 台風発生情報を取得して、予期せぬリスクに備えるよう通知する
などなど。
ぜひそういった機能をご希望でしたらぜひお問い合わせよりご連絡ください。
お待ちしております。
おわりに
ということで、今回はLaravel
で「熱中症、要注意」メールを実装してみました。
API
は突然終了してしまうリスクはありますが、ホントに簡単にいろんな情報を取得することができるので、シンプルに何かを実装するにはおすすめです
ちなみに、もちろん温度設定を変えて「風邪ひいちゃうから暖房入れよう」メールや「乾燥肌注意報」などもできますし、データさえ取得できるなら「花粉に注意メール」なども実装できます。
ぜひ皆さんも夏休みの工作的にやってみてくださいね。
ではでは〜
「Safari って
Chrome とほぼ一緒…
って思っちゃダメでした」