朝自動カーテン開け機「mornin’ plus」を1カ月半ほど使ってみた

昨年末参加したの忘年会プレゼント交換で頂いた朝自動カーテン開け機「mornin’ plus」を1カ月半ほど使ってみました。タイマーを設定しておき、朝になると部屋のカーテンが自動で開く事で目覚めが良くなる?という感じのアイテムです。既存のカーテン・カーテンレールに工具など一切不要で取り付ける事が出来ます。ねじ回しすら要りません。

取り付け

どういう風に動くのかというと、カーテンレールにこれをぶら下げておくとタイマー動作で左右に動作してカーテンも一緒に開閉する、という仕組みです。写真を見た方が早いですね。

見ての通り部屋の内側からは見えず、ほとんど見た目が変わりません。部屋の外側からは見えますが「白い何かが付いているな」程度で特に気になるものではないかと思います。

ちなみに先代の「mornin’」では取り付けると手動での開閉が出来なくなる仕様だったらしいですが、 「mornin’ plus」 は取り付けた後も手でカーテンを開け閉めする事が出来ます、動かす際の抵抗もあまり変わらず特に困ることは無いかと思います。

乾電池で動作するので、高い場所など交換しづらい窓には取り付けない方がよさそうです。最初についてきた試供品の電池で1カ月半交換せずにいるので電池消費はそこまで大したこと無さそうですね。公式では6カ月程度動く事になっています。

タイマー設定

タイマーの設定は Android / iOS スマートフォン向けのアプリで設定します。「あまり有名ではないアイテム・サービスや企業の出すアプリ」としてはよくある事なのですが、まぁアプリのストアでの評判がよくない……。とはいえ私の環境で使う分には不具合なく問題なく動作しております。

「mornin’ plus」 初期設定の際はBluetoothで接続が必要ですが、それ以後はBluetooth接続は必要は有りません。 「mornin’ plus」 自体に時計が有り設定も自身に保存されます。

平日のみ動作するようなタイマーも設定可能。
初期設定ではどの方向に空けるか、どの程度の距離を移動するか(どの程度開けるか)なども設定します。

タイマー設定は開けるだけでなく閉める設定も可能なので、日中は自動で開けて夜は自動で閉めるなどして数日家を空ける際の防犯などにも良いかもしれません。

使用感

起きる時間よりも少し早い時間に空けた方が目覚めが良いらしいので起床用のタイマーより30分程度早い時間に設定。寝ている間に開いているので具体的な使用感というのはなかなか難しいですが、確かに気持ち目覚めが良くなったような気がします。起きる時間に部屋が明るいというのは気持ち「起きるかー」という感覚が強まります。当然雨の日などには日光が弱いので効果が落ちますが、それはそれで今日は天気が悪い日なんだなと肌をもって感じ取れます(?)

より具体的な部分として開け閉めする際の動作音ですが、ある程度のモーター音が鳴ります。熟睡していれば全く聞こえませんが、眠りが浅いと聴こえる、ぐらいの感じです。眠りが浅いと「あーカーテン開いてるなー、起きるほどじゃないけど」ぐらいには聴こえます。もっとも、起きる時間の手前なので起きるほど気になった時はそのまま起きてしまえば良いんじゃないかと。

価格もお手頃で初期設定をしてしまえばあとは半年に一回の電池交換だけなので、なかなかコスパのいい面白実用アイテムなんじゃないかと。仮に目覚めに効果が感じられなくてもカーテンレールにぶら下がっているので置き場所に困るようなことは無いし、朝に日の光を浴びておくのは悪くないものです。

 
Share this…

マイクロフレームワークっぽく使う Symfony 4 事始め 2 ~ルーティング編~

Symfony 4 入門。 前回の記事は以下

前回までは Symfony 4.2 のインストールからTwigテンプレートを使ったWebページを一つ表示するところまでを作りました。今回はコントローラ上にルーティングを増やしていきます。

参考にすべきページは以下

Create your First Page in Symfony (Symfony Docs)
Routing (Symfony Docs)
Controller (Symfony Docs)

結構ボリュームが有るので説明してない分は参照先の公式ドキュメントを参照してください。

ルーティング

前回作成したRootControllerの定義を再確認します。

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class RootController extends AbstractController
{
    /**
     * @Route("/root", name="root")
     */
    public function index()
    {
        return $this->render('root/index.html.twig', [
            'controller_name' => 'RootController',
        ]);
    }
}

PHPDocに記載の有る @Route 定義がアノテーションによるルーティングです。”/root”にマッチするURLが来た場合にこの index 関数が実行されます。nameはユニーク(他とかぶりが無い)である必要が有るので注意してください。

結果はResponseオブジェクト( Symfony\Bundle\FrameworkBundle\Controller\Response)をreturnで返します。$this->render() を呼び出すとTwigでレンダリングした結果をResponseオブジェクトとして返してくれます。

ルーティングを増やす

    /**
     * @Route("/root", name="root")
     */
    public function index()
    {
        return $this->render('root/index.html.twig', [
            'controller_name' => 'RootController',
        ]);
    }

    /**
     * @Route("/root/demo", name="root_demo")
     */
    public function demoAction()
    {
        return $this->render('root/index.html.twig', [
            'controller_name' => 'RootController::demo',
        ]);
    }

@Routeアノテーションの定義された関数を増やすします。Routeアノテーションの一つ目の引数にパス、2つ目に入力する名前は他とのかぶりが無いものにします。

引数のあるルーティング

例えば /books/detail/20/ のようなページを作りたいと思います。20の部分は可変とします。その場合パスを指定する際に{変数名}を指定するとその名前で関数の引数に変数を受け取る事が出来ます。また、例えばこの引数が必ず数字で構成される場合などは requirements の定義に変数名と正規表現の対応を記述しておくと、数字である場合のみ処理されるような制約設定が可能です。

    /**
     * @Route("/books/detail/{book_id}/", name="book_detail", 
     * requirements={"book_id"="\d+"})
     */
    public function bookDetailAction($book_id)
    {
        return $this->render('books/detail.html.twig', [
            'book_id' => $book_id,
            'book_detail' => 'dumy text'
        ]);
    }

テンプレート books/detai.html.twig は以下のように定義。受け取ったIDをそのまま表示します。

{% extends 'base.html.twig' %}

{% block title %}Book Detail{% endblock %}

{% block body %}

<h1>Book Detail ID:{{ book_id }}</h1>
<p>
    {{ book_detail }}
</p>

{% endblock %}

Webブラウザで http://127.0.0.1:8000/books/detail/20/ にアクセスしてみます。

リクエスト内容を受け取る

SymfonyにはDI(Dependency Injection : 依存性注入)の仕組みが有り、サービスクラス(≒アプリが行う処理のコア部分のクラス)のコンストラクタであったり引数で有ったりにSymfonyが認識しているクラス名や引数名を指定すると自動で必要なオブジェクトを渡してくれます。リクエスト内容を受け取るには Request のオブジェクトを受け取ります。

    /**
     * @Route("/books/detail/", name="book_detail_for_query")
     */
    public function bookDetailActionForQuery(Request $req)
    {
        $book_id = $req->query->get('book_id');

        return $this->render('books/detail.html.twig', [
            'book_id' => $book_id,
            'book_detail' => 'dumy text'
        ]);
    }

受け取った引数 $req から book_id を取り出しています。Webブラウザで http://127.0.0.1:8000/books/detail/?book_id=33 にアクセスしてみます。

HTTPメソッドに応じてルーティングする

基本的には先ほどと同じですが @Route の定義に methods={“POST”} を追加しています。これによりPOSTであった場合のルーティングを行っています。

    /**
     * @Route("/books/edit/", name="book_edit_exec", methods={"POST"})
     */
    public function bookEditExecAction(Request $req)
    {
        return $this->render('books/detail.html.twig', [
            'book_id' => 0,
            'book_detail' => '編集に成功しました'
        ]);
    }

複数のHTTPメソッドに一つの関数で対応する場合は
methods={“POST”, “PUT”}
のように定義します。

なお、先にメソッド指定のないルーティングを行った後に同じパス指定でPOSTに限定したルーティングを書いてもPOSTでのアクセスは先に定義しているメソッド縛り無しの方が呼ばれて適切に動作しません。同じパスでHTTPメソッド違いのルーティングを作る場合はGETについても適切に定義してください。

404 Not Found を返す

NotFoundHttpException 例外を発生させる事で HTTP 404 Not Found の処理を行います。直接newしてnewしてthrowしてもいいですが、$this-> createNotFoundException を使って生成する事が出来ます。この時例外は return ではなく throw する事に気を付けてください。

throw $this->createNotFoundException('見つからないようです');

設定したメッセージが表示されています。

呼び出し先のコードを読めばわかりますが NotFoundException を生成して返しているだけです。この NotFoundException を更に追うと HttpException の第1引数に 404 を渡して例外を生成している事が確認できます。 404以外のステータスコードを返したい時は HttpException を直接扱えばよさそうですね。HttpExceptionを生成する際は第1引数にステータスコードを渡してやります。

throw new \Symfony\Component\HttpKernel\Exception\HttpException(
            500, 'インターナルなサーバーのエラー');

リダイレクトする

$this->redirect(‘URL’) を使う方法と $this->redirectToRoute (‘ROOT’, []) を使う方法が有ります。前者はURLを直接渡す普通のリダイレクト、後者はアノテーションでルーティングを記述する際に指定する name で指定してリダイレクトします。また、redirectToRootの場合は第2引数で連想配列などを渡しておくと自動でURLのクエリ文字列をつけ足したりなど良い感じに処理してくれます。

$this->redirect('/books/detail?book_id=20');
$this->redirectToRoute('book_detail', ['book_id' => 20]);

例えば目的のパスの定義が /books/{book_id}/ というような場合でも変数名を合わせて第2引数に渡しておけば、例えば /books/50/ といったページにリダイレクトしてくれます。

// book_detail の定義が /books/{book_id}/ だったとしてもちゃんと引数が渡る
$this->redirectToRoute('book_detail', ['book_id' => 20]);

JSONを返す

$this->json() を使います。1つ目の引数に返したいデータ(例えば連想配列など)、必要であれば2つ目の引数にHTTPステータスコードを渡します。デフォルトはHTTP 200で返します。

        return $this->json([
            'データ1' => 100,
            'データ2' => 200
        ]);

ここまででだいたいのルーティングは作る事が出来るんじゃないかと思います。また、引数を取る際にデフォルト値を設定したい場合とかも公式のドキュメントに方法が書いてありますのでご参照ください。コントローラクラスは無秩序に1ファイルに増やしていく事も可能ですが、適宜クラスを分けた方が分かりやすいかと思います。

ここまでのコードの状態は以下を参照してください。
https://github.com/lf-uraku-yuki/symfony4_tutorial/tree/tutorial02

また、ルーティングがどうなっているかは php bin/console debug:route で一覧表示する事が出来きます。

次回はサービスとDIとデータベースについて書こうと思います。

続きの記事が出来ました(2019年1月31日)

Share this…

マイクロフレームワークっぽく使う Symfony 4 事始め 1 ~インストール編~

PHPのWebアプリケーションフレームワーク Symfony 4.x をマイクロフレームワークっぽく利用し始める事始め(入門)をまとめてみたいと思います。Symfonyは公式のドキュメントがそれなりに充実しているのでそこを読める人であれば読めばOK!なんですが、あまりにも日本語の情報が無く、有ってもバージョンが古い頃の情報だったりしてちょっとつらいです。今回は以下の環境でまとめています。私自身が使い始めたばかりなのでよく分かっていない部分はよく分かっていないと書いています。

Symfony: 4.2
PHP: 7.2 (Windows版ですが他の環境と特に違いは無いです)
Composer: 導入済み
MySQL: 8.0 (Windows版ですが他の環境と特に違いは無いです)

PHPのビルトインサーバーで動作するのでApacheやNginxは開発環境で動かす分には不要です。

インストール

インストール完了までの手順は以下の記事を大いに参考にさせて頂いております。リンク先の方が詳しいです。

Symfony4をインストールして”Hello World”を表示させるまでの手順 | QUARTETCOM TECH BLOG
Installing & Setting up the Symfony Framework (Symfony Docs)

プロジェクトを作るディレクトリに移動しComposerでインストールしていきます。symfony/skeltonを導入する事で必要な最小限の諸々 + Symfonyのパッケージ管理を楽にするための仕組み Symfony Flex が導入されます。

composer create-project symfony/skeleton <プロジェクト名>

作成されたプロジェクトのディレクトリに移動し、PHPのビルトインサーバを使うための Server レシピを導入します。serverという名前指定だけで目的のパッケージが導入されますが、この部分がFlexにより支援されている部分のようです。

composer require server

導入後は以下のコマンドでビルトインサーバーが起動します。consoleファイルの中身はPHPで実行するようにshebangが設定されたPHPファイルです。Windowsの場合はコマンドの頭に「php 」を付けてPHPのファイルである事を明示的に指定してやれば同様に動きます。

php console/bin server:run

実行した様子。Ctrl+C で終了。

コントローラなどを生成できる maker レシピ、コントローラを実装する際に定義ファイルの編集ではなくコントローラコード上のアノテーションで行えるようにする annot レシピを導入します。アノテーションでルーティングする機能は実態としては sensio/framework-extra-bundle に含まれています。デバッグ・プロファイリングに便利な debug-pack も導入します。

composer require maker
composer require annot
composer require debug-pack

テンプレートエンジンにTwigを使いたいので twig レシピを導入します。APIサーバーとして使う(JSONしか返さないつもり)なら入れなくても良いんじゃないかと思います。

composer require twig

これで「何かしらのURLにアクセスしたらコントローラがルーティングしてテンプレートエンジンがテンプレートを使ってページを表示する」という基本部分が完成しました(DB処理は後からふれます)。

色々と導入してきましたが、それに伴いconsoleコマンドでCLI実行できる機能も増えています。 bin/console xxx:xxx で使えるコマンドの一覧は特に引数を渡さずに実行すると確認できます。

php bin/console

以下が実行結果。多いので中略しています。

Hello World

決まった文字が文字が表示されるだけのページを作ってみます。以下のコマンドでコントローラを作成します。

php bin/console make:controller RootController

テンプレートとコントローラが作成されました。 maker:controller は便利コマンド的な物なので作り込んで来たら既存のコントローラをコピペするなどして手動で作成しても良いのですが、最初はこれを叩いた方が簡単です。

この時点でのプロジェクトのルート配下のファイル・ディレクトリ構成は以下のような感じになっています。

  • /bin :consoleコマンドやあとで導入するphpunitコマンドがここに入ります。
  • /config :各種設定ファイルが入ります。
  • /public :ドキュメントルートはここ。index.phpの場所。
  • /src :PHPのコード
    • Controller :コントローラーが作られる場所。
  • /template :Twigテンプレートの場所。src配下ではない。
  • /var :ログファイルであったりなどがここに作られます。
  • /vendor :Composerで導入されていくパッケージ。
  • .env :これもSymfonyの環境設定に関わるファイル。ここで環境によって設定を変えたりできる?
  • composer.json :Composerで導入されたパッケージの管理。
  • composer.lock :同上。
  • symfony.lock :Symfony関連のパッケージ管理。謎が多い。

コントローラのコードは以下のようになっています。

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;

class RootController extends AbstractController
{
    /**
     * @Route("/root", name="root")
     */
    public function index()
    {
        return $this->render('root/index.html.twig', [
            'controller_name' => 'RootController',
        ]);
    }
}

PHPDocに記載の有る @Route 定義がアノテーションによるルーティングです。”/root”にマッチするURLが来た場合にこの index 関数が実行されます。nameはユニーク(他とかぶりが無い)である必要が有るので注意してください。

結果はResponseオブジェクト( Symfony\Bundle\FrameworkBundle\Controller\Response)をreturnで返します。$this->render() を呼び出すとTwigでレンダリングした結果をResponseオブジェクトとして返してくれます。JSONで返したい場合は $this->json() という関数が有ります。

Twigテンプレートは以下のようになっています。

普通のTwigテンプレートなので特に必要はないかと思いますが、念のため雑に説明しておきます。

  • {{ xxx }} 変数の表示。自動でHTMLスケープされます。
  • {% xxx %} 変数を表示する以外の分岐やループなどの機能は {% で囲まれます。
  • {# xxx #} コメントアウト。コメントアウトは {# で囲みます。

$this->render() 時に渡した変数 controller_name からコントローラー名「RootController」が表示されるようになっていますね。

ではページを見てみます。php bin/console server:run でビルトインサーバを起動し、Webブラウザで http://127.0.0.1:8000 にアクセスします。

これはデフォルトのルートページ的な物になり、画面左下にも出ているように HTTP 404 Not Foundとなっています。ページ下部に表示されているステータスコード、処理時間、エラーログ確認などが debug-pack で導入された機能によって表示されているプロファイラ機能です。クリックするとより詳細な情報を確認する事が出来ます。

作成したコントローラに対応する http://127.0.0.1/root にアクセスしてみます。

目的のページが表示されました。画面左下よりステータスコードも HTTP 200 (正常) となっていますね。

とりあえずここまででページを表示するための最低限のものが動くようになりましたが、ルーティングの詳細やDB処理などまだ必要な物が有ります。次はルーティングについてまとめます。

ここまでのコードの状態は以下を参照してください。
https://github.com/lf-uraku-yuki/symfony4_tutorial/tree/tutorial01

続きの記事

Share this…