SwitchBotのシーリングライトプロが追加できない(インターネットに接続されない)時に解決した方法
解決した方法
これでSwitchBotアプリからシーリングライトプロを操作できるようになりました。
経緯
という問題が起きていてサポートに連絡したら「iPhoneかAndroidのデザリングで追加してみて!」という指示が来たので
にしてWifiルーターの電源切ってAndroidのSwitchBotアプリからシーリングライトプロを追加したら普通に追加された。 (追加する時に使うSSIDはiPhoneのインターネット共有のもの。パスワードも。)
当然家の中でiPhoneのテザリングをずっと使うわけがないので、
で再度Android端末からシーリングライトプロを追加したら、無事自宅のWifiルーターでもシーリングライトプロをSwitchBotアプリで操作できるようになった。
その他
SwitchBotアプリのシーリングライトプロの詳細からWifi設定いじった辺りで接続がおかしくなったような気がする。 Wifi設定変更するなら一回アプリからデバイスを削除して、再度追加する時にネットワーク変更したほうが良いような気がする。
LaravelのテストをGitHub Actions (MySQL)で実行する
テストはローカルで実行できていたけど、せっかくなのでGitHub Actionsでも実行できるようにしてみた。
sqliteだとテーブル定義が想定と異なりテストの実行が失敗するのでMySQLを使うことにする。
Laravelのバージョンは10.17.1
$ php artisan --version Laravel Framework 10.17.1
最終的な成果物
.github/workflows/unittest.yml
# ベースになった設定 # https://laravel-news.com/laravel-ci-with-github-action name: Run tests on: push: branches: - master - feature/** pull_request: branches: - master jobs: tests: name: Run tests runs-on: ubuntu-latest steps: - name: Start MySQL run: | sudo systemctl start mysql.service mysql -uroot -proot -e "CREATE DATABASE IF NOT EXISTS testing" mysql -uroot -proot -e "SHOW DATABASES" - uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.2' extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv coverage: none - name: Run composer install run: composer install -n --prefer-dist - name: Run node.js run: | npm install npm run prod - name: Prepare Laravel Application run: | touch .env.testing echo "${{ vars.DOT_ENV_TESTING }}" >> .env.testing - name: Run tests run: php artisan test
Laravel Newsで紹介されていた設定にいくつかstepを追加して、php artisan test
が通るようになった。
DBの名前はtestingにしているので適当なものに変更する。
テストで使う.env.testing
の中身は、GitHub上でDOT_ENV_TESTING
という変数名で登録しておく。
Settings > Secrets and variables > Variable > Repository variables
これも適当な変数名にして大丈夫。
phpunit.xml
のDB_CONNECTION
、DB_DATABASE
も設定する必要があるかも。
phpunit.xml
<env name="APP_ENV" value="testing"/> <env name="DB_CONNECTION" value="mysql"/> <env name="DB_DATABASE" value="testing"/>
.env
のDBの設定はこんな感じ。
.env.testing
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=testing DB_USERNAME=root DB_PASSWORD=root
詰まった所
sqliteだとテーブル定義がおかしくなる。
本番環境ではMySQL
を使っており、ローカルでの開発やテストの時はsqlite
を使おうかと思っていたが、何かsqliteを使うと想定とは違うテーブル定義になってテストでエラーが発生していた。
public function up() { Schema::table('users', function (Blueprint $table) { $table->string('twitter_id') ->after('id'); }); }
こういったafter()を使ったマイグレーションがうまく通ってないような気がする(もしかしたらドキュメントとかに書いてあるかも...?)
after()が使えないのは良いが、そもそもカラムが追加されてないようだったのでローカルの開発もテストも本番環境と同じMySQLを使うようにした。
Expected response status code [200] but received 500.
最初からプロジェクトにあるテストでExpected response status code [200] but received 500.
というエラーが出ていた。
npm install && npm run prod
を実行することでフロントのリソースを準備してあげることでエラーが解消された。
• Tests\Feature\ExampleTest > the application returns a successful response Expected response status code [200] but received 500. Failed asserting that 200 is identical to 500. The following exception occurred during the last request: ....... Mix manifest not found at: /home/runner/work/aaa/aaa/public/mix-manifest.json at tests/Feature/ExampleTest.php:19 15▕ public function test_the_application_returns_a_successful_response() 16▕ { 17▕ $response = $this->get('/'); 18▕ ➜ 19▕ $response->assertStatus(200); 20▕ } 21▕ } 22▕
GitHub ActionsでのMySQLやNode.jsの準備の仕方
ネットで記事を検索すると- services
でimageを指定したりする方法を見かけたが、ubuntu-latest
には最初からMySQL
やnode.js
がインストールされていてそれを使うのがお手軽そうだったのでそちらを採用した。
本当ならservices
で指定した方が良いのかもしれないが、その辺りは良く分からなかった。。。。
最後に
Proプランだと月3000分使えるので色々使っていきたいですね。
CIつながりでCircleCI
の無料枠どのくらいだったっけなと思って調べたら、去年大幅に無料枠増やしたんですね。
2,500クレジット/週
から30,000クレジット/月
って凄いな。
30,000クレジットで6000分ということは5クレジットで1分?
ということは週500分から月6000分になったのか。。。
ProプランなのにGitHub Actions使ってなくてもったいないかなーと思って今回使ってみたけど、月3000分以上使う人はCircleCIの方が良いかもしれませんね。
Laravelでパスワードレス認証(マジックリンク)を実装する + Laravel Voltでログアウトする
これからSNSを作ろう、作ったSNSを世にだそうとしている開発者につぐ。
— 👹秋田の猫🐱 (@ritou) 2023年7月3日
とりあえずでパスワード認証を使うな!
Twitter, Gmail, Appleログインとかの方が良いかもしれないけど今回はマジックリンクで実装する。
下記のライブラリで実装する。
こっちでも良いかもしれない。
環境構築
Laravel Valetで環境構築をする。
今までLaravel Sail使ってたけどmacOSではLaravel Valetの方が便利みたい。
実際使ってみたけどいちいちsail upとか打たなくてすむし、複数のサイトを気楽に管理できるから今のところ良さそう。
ファイル変更したときにブラウザリロードする必要があるけど、それも少し調べれば解決方法あるかも。
laravel new resend
valet open resend # 多分 http://resend.testというサイトが開く
resend.com
マジックリンクをメールで送信する必要があるので今回はResendを使用する。
以前アカウントを作って何も使ってなかったから使おうと思っただけで、他のサービスでも問題ないと思います。
Userモデルの変更(primary keyをULIDにする)
最終的には下記のようなリンクが生成されるが、この時ユーザーIDが含まれて個人的に少し嫌なので、IDをULIDに変更する。
# idが連番 http://resend.test/magic-login/1?expires=1690636947&user_type=app-models-user&signature=07a7b9d4bbc20d7c889edfe627b9e7a7d24236c681f26172e6d13bac185a348e # idがulid http://resend.test/magic-login/01h6ce5tydqwtmvpe2j17ahhp1?expires=1690636947&user_type=app-models-user&signature=07a7b9d4bbc20d7c889edfe627b9e7a7d24236c681f26172e6d13bac185a348e
2014_10_12_000000_create_users_table.php
<?php return new class extends Migration { /** * Run the migrations. */ public function up(): void { Schema::create('users', function (Blueprint $table) { // $table->id(); $table->ulid('id')->primary(); // <--- idをULIDにする $table->string('name'); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } /** * Reverse the migrations. */ public function down(): void { Schema::dropIfExists('users'); } };
User.php
<?php namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Concerns\HasUlids; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Support\Str; use Laravel\Sanctum\HasApiTokens; class User extends Authenticatable { use HasApiTokens, HasFactory, Notifiable, HasUlids; // <- HasUlids を追加
Webで検索するとboot()とかでidにulidセットしたり、$keyType = 'string';にしたり色々方法見かけたけど今はHasUlidsだけで大丈夫そう(多分)
users
のpassword
もいらないかも。
開発ではsqlite
を使うと便利だと思う。
sqlite
使う時は.env
を少し修正する必要がある。
.env
DB_CONNECTION=sqlite # <--- 多分デフォルトはmysqlになっているのでsqliteに変更 DB_HOST=127.0.0.1 DB_PORT=3306 # DB_DATABASE=db.sqlite # DB_DATABASEはコメントアウトする DB_USERNAME=root DB_PASSWORD=
sqlite
を使う時はDB_DATABASE
をコメントアウトしないと下記のようなエラーが出る。
理由はなんとなく分かるけどちゃんとは理解してない。
Database file at path [db.sqlite] does not exist. Ensure this is an absolute path to the database.
変更したらmigrate
とdb:seed
をやっておく。
php artisan migrate php artisan db:seed
ログインURL生成
フォーム作って、コントローラーでリクエスト受けて...とかやってると面倒なので今回はcommandを使う。
php artisan make:command Tests/TestGenLoginLink
とりあえず一番最初のユーザーのログインリンクを生成する。
TestGenLoginLink.php
<?php namespace App\Console\Commands\Tests; use App\Models\User; use Grosv\LaravelPasswordlessLogin\LoginUrl; use Illuminate\Console\Command; class TestGenLoginLink extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'test:gen:loginlink'; /** * The console command description. * * @var string */ protected $description = 'ログインリンク生成'; /** * Execute the console command. */ public function handle() { $user = User::first(); $generator = new LoginUrl($user); $url = $generator->generate(); $this->info($url); } }
下記のコマンドで最初のユーザーのログインリンクを生成できる。
$ php artisan test:gen:loginlink http://resend.test/magic-login/01h6h6fk862hrz0t389gymex76?expires=1690650694&user_type=app-models-user&signature=60c851c17e1d2b5060f96c2366a8694731ecf35c24dcff512b97688e69be172a
実際にログインしてみる
welcome.blade.php
を下記のように書き換えてブラウザでURLにアクセスする
<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Laravel</title> <!-- Fonts --> <link rel="preconnect" href="https://fonts.bunny.net"> <link href="https://fonts.bunny.net/css?family=figtree:400,600&display=swap" rel="stylesheet"/> </head> <body> <div> @if(Auth::check()) logged in: {{Auth::user()->id }} @else guest @endif </div> </body> </html>
ログイン前
ログイン後
ログインリンクをメールで送る
Resend.comではResendファサードが用意されているようだけど、今回はMailファサードを使用する。
メールの内容はMarkdown
を使って記述もできるので今回はそちらを使用する。
php artisan make:mail LoginLink --markdown=emails.auth.login_link
LoginLink.php
とlogin_link.blade.php
が生成されるのでそれぞれ修正する。
Mailableの方に変数を定義しておくと、bladeファイルの方からアクセスできる。
LoginLink.php
<?php namespace App\Mail; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Mail\Mailable; use Illuminate\Mail\Mailables\Content; use Illuminate\Mail\Mailables\Envelope; use Illuminate\Queue\SerializesModels; class LoginLink extends Mailable { use Queueable, SerializesModels; /** * Create a new message instance. */ public function __construct( public string $url // <--- ログインリンク用の変数追加 ){} ...
login_link.blade.php
<x-mail::message> <x-mail::button :url="$url"> Login </x-mail::button> Thanks,<br> {{ config('app.name') }} </x-mail::message>
とりあえずこれでメールを送る準備が出来た。
Controller用意してとかやってると面倒なので、ログインリンク送信もCommandを使用する。
今回はUser::first()のログインリンクを指定のメールアドレスに送信しているが、本来はUserに登録されたメールアドレスを使用する(重要)
ライブラリの作者も間違ったユーザーへ送信しないようにREADMEで注意をしている。
The biggest mistake I could see someone making with this package is creating a login link for one user and sending it to another. Please be careful and test your code. I don't want anyone getting mad at me for someone else's silliness.
(このパッケージで誰かが犯しそうな最大のミスは、あるユーザー用のログインリンクを作成し、それを別のユーザーに送信することです。気をつけてコードをテストしてください。他人の愚かな行為で私に怒られたくないのです。)
php artisan make:command Tests/TestSendLoginLink
resend.comは初期設定だと登録したメールアドレスにしか送信できないようなので、もし送信したいメアドを変更したい場合は設定が必要(未確認)
TestSendLoginLink
<?php namespace App\Console\Commands\Tests; use App\Mail\LoginLink; use Grosv\LaravelPasswordlessLogin\LoginUrl; use Illuminate\Console\Command; use Illuminate\Support\Facades\Mail; class TestSendLoginLink extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'test:mail:loginlink'; /** * The console command description. * * @var string */ protected $description = 'ログインリンク送信テスト'; /** * Execute the console command. */ public function handle() { $to = "<resend.comに登録したメアド>"; // 念のため $confirm = $this->confirm("send email to?: $to"); if (!$confirm) { return; } // こんなことは普通やらないけど今回は例としてfirstのユーザーを使用している $user = User::first(); $generator = new LoginUrl($user); $url = $generator->generate(); $result = Mail::to($to)->send(new LoginLink($url)); } }
下記のコマンドで実際にメールを送信できる。
$ php artisan test:mail:loginlink send email to?: xxxx@test.com (yes/no) [no]: > yes $
下記のようなメールが送信されてきてボタンをタップするとログインが完了する。
Laravel Voltでログアウト(おまけ)
先日LaraconUSでLaravel Voltが発表されましたね。
見た感じVueというかReactというかそういったライブラリっぽい書き方をPHPで実現できるライブラリのようです。
Livewireも使ったこと無いけど良い機会なので試しに使ってみようと思います。
ついでにBlade Componentも使ったこと無いのでそれも使ってみる(素のBladeしか使ったことなかった)
Laravel Folioというルーティングライブラリも発表されたが今回は使わない。
Livewire 3.0(beta)とVolt 1.0(beta)をインストールする。
$ composer require livewire/livewire:^3.0@beta livewire/volt:^1.0@beta $ php artisan volt:install
とりあえずrootとなるBlade Componentを作成する。
--view
フラグを付けるとapp/View/Components/
にComponentクラスが生成されない(匿名コンポーネントが生成される。)
$ php artisan make:component app --view
コンポーネントはresources/views/components/
に追加される。
とりあえずwelcome.blade.php
の<body>
内以外をコピーしてくる。
app.blade.php
<!DOCTYPE html> <html lang="{{ str_replace('_', '-', app()->getLocale()) }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Laravel</title> <!-- Fonts --> <link rel="preconnect" href="https://fonts.bunny.net"> <link href="https://fonts.bunny.net/css?family=figtree:400,600&display=swap" rel="stylesheet"/> </head> <body> {{$slot}} </body> </html>
Blade Component
に別の要素を追加する時は$slot
を使うので<body>
内は$slot
としている。
そしてwelcome.blade.php
は下記のように書き換えることができる。
welcome.blade.php
<x-app> <div> @if(Auth::check()) logged in: {{Auth::user()->id }} @else guest @endif </div> </x-app>
Volt Componentを追加する。
make:volt
でVolt Componentが生成できる。
生成されたコンポーネントはresources/views/livewire
ディレクトリに生成される。
$ php artisan make:volt auth
下記のようなテンプレートが生成される。
auth.blade.php
<?php use function Livewire\Volt\{state}; // ?> <div> // </div>
ここにログアウト機能を追加していく。
Laravel Voltでログアウトする
最終的にはこんな感じになった
auth.blade.php
<?php use Illuminate\Support\Facades\Auth; use function Livewire\Volt\{computed}; $user = computed(function () { return Auth::user(); }); $logout = fn() => Auth::logout(); ?> <div> @if($this->user) logged in: {{ $this->user->id }}<br/> <button wire:click="logout">Logout</button> @else guest @endif </div>
welcome.blade.php
を下記のように変更する。
<x-app> <livewire:auth /> </x-app>
実行結果。
ログイン状態:
ログアウトボタン押下:
gif動画をアップロードしようと思ったけどなぜか失敗するので静止画。
まとめ
マジックリンク実装ついでに使ったことない(+あまり使ったこと無い)機能も色々使ってみました。
Laravel Volt便利ですね。
TipKit試してみた
Xcode15 beta5でTipKitが使えるようになったので試してみた(もうbeta5まで出たのか...)
TipKitがXcode 15 beta 5にやってきました!是非お試しください!!https://t.co/wTt5qe3g03
— Masashi Toyota (@toyochang) 2023年7月25日
import SwiftUI import TipKit struct FavoriteLandmarkTip: Tip { var title: Text { Text("Save as a Favorite") } var message: Text? { Text("Your favorite landmarks always appear at the top of the list.") } var asset: Image? { Image(systemName: "star") } } struct ContentView: View { var tip = FavoriteLandmarkTip() var body: some View { VStack { TipView(tip, arrowEdge: .bottom) Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .task { try? await Tips.configure { DisplayFrequency(.immediate) DatastoreLocation(.applicationDefault) } } .padding() } }
TipViewを消すとトルツメされる。


AVPlayerで最初から再生する方法
再生中のアイテムを最初にシークして再生。
if player.isEnded { // extension player.currentItem?.seek(to: .zero, completionHandler: nil) } player.play()
再生終了しているか確認する方法。
AVPlayerで再生中のアイテムが再生終了しているかどうかを確認する方法
extension AVPlayer { var isEnded: Bool { currentItem?.currentTime() == currentItem?.duration } }