🚗
NFCタグでトミカ読み上げアプリを作ってみた
やってみた
この動画が全てですが、ちょっと説明します。
経緯
子がトミカ好きだと、車名を覚える必要にかられます。
初期
👶「これなんて車?」
🧑「消防車だよー」
中期
👶「これなんて車?」
🧑「ポンプ消防車」
末期
👶「これなんて車?」
😰「災害、、、対策用、、、救助車?」
そう、トミカは消防車だけで何十種類もあるのです。
正直覚えきれないので、技術で解決できないか考えることにしました。
下準備
トミカ辞書を作る
まず、トミカの車種はどうやったら特定できるのかを調べました。トミカの箱には3桁の数字が書いてあり、同じ数字が車の裏にも表記されています。例えば、日野 はしご付消防車
は、No.108
です。
この数字がIDとして使えるかも!と思いましたが、そんな甘くはありません。この数字は新商品が発売されるとランダムに上書きされます。現在、No.108
のはしご付消防車
も、その前は動物運搬車(ゴリラ)
、さらに前はキャンピングカー
と一貫性皆無です。
そこで、トミカダスを参考に親番号
-子番号
の辞書を作ります。
tomica.dart
const Map<String, Map<String, String>> tomica = {
"1": {
"1-7": "日産 スカイライン(BNR34) パトロールカー",
"1-6": "日産 エクストレイル 消防指揮車",
"1-5": "三菱ふそう エアロクィーン",
"1-4": "三菱ふそう エアロクイーン",
"1-3": "日野 グランビューバス",
"1-2": "ふそう はとバス",
"1-1": "ブルーバードSSSクーペ"
},
...
"108": {
"108-4": "日野 はしご付消防車 (モリタ・スーパージャイロラダー)",
"108-3": "三菱ふそう 動物運搬車(ゴリラ)",
"108-2": "トヨタ ハイラックス キャンピングカー",
"108-1": "トヨタ カローラ 30 レビン"
},
...
}
NFCタグ
Amazonで色々売ってますが、トミカに貼れるサイズのものを選びました。
冷静に考えると1枚50円は割高...
トミカに貼る
トミカの背面は凹凸がありますが、粘着力があって結構しっかり貼れます。
キーを書き込む
NFC Toolsを使って、トミカの親番号
-子番号
をテキストで書き込みます。
上の写真のトミカは、No.115
のスバルフォレスターで、115-6
を書き込みました。
Flutterで読み上げアプリを作る
使用プラグイン
NFCタグを読み取るnfc_manager
と、テキストを読み上げるflutter_tts
を使います。
pubspec.yaml
dependencies:
flutter:
sdk: flutter
flutter_tts: ^4.0.0 # テキスト読み上げ
nfc_manager: ^3.5.0 # NFC読み取り
コード(一部略)
main.dart
main.dart
import 'package:flutter_tts/flutter_tts.dart';
import 'package:nfc_manager/nfc_manager.dart';
import './tomica.dart';
class _MyHomePageState extends State<MyHomePage> {
late FlutterTts tts;
String? _newVoiceText;
void initState() {
super.initState();
NfcManager.instance.startSession(
onDiscovered: (NfcTag tag) async {
Ndef? ndef = Ndef.from(tag);
if (ndef == null) {
// エラー処理
return;
}
try {
// NFCタグのテキスト取得
NdefMessage message = await ndef.read();
String str = '';
for (NdefRecord record in message.records) {
Uint8List payload = record.payload;
str += utf8.decode(payload);
}
// Language Codeのenを無視
var nono = str.substring(str.indexOf('en') + 2);
// 親番号切り出し
var no = nono.substring(0, nono.indexOf("-"));
setState(() {
// 読み上げ
_newVoiceText = tomica[no]?[nono];
_speak();
});
} catch (e) {
logger.e(e);
}
},
);
}
dynamic initTts() {
tts = FlutterTts();
_setAwaitOptions();
if (Platform.isAndroid) {
_getDefaultEngine();
_getDefaultVoice();
}
}
Future<void> _setAwaitOptions() async {
await tts.awaitSpeakCompletion(true);
}
Future<void> _getDefaultEngine() async {
var engine = await tts.getDefaultEngine;
}
Future<void> _getDefaultVoice() async {
var voice = await tts.getDefaultVoice;
}
Future<void> _speak() async {
await tts.setLanguage('ja-JP'); // 読み上げる言語を日本語に設定
await tts.setSpeechRate(0.7);
await tts.setVolume(1.0);
await tts.setPitch(1.0);
await tts.setVoice({'name': 'Karen', 'locale': 'ja-JP'});
if (_newVoiceText != null) {
if (_newVoiceText!.isNotEmpty) {
await tts.speak(_newVoiceText!);
}
}
}
}
オチ
🧑「ここにトミカ置いてみて」
👶「はい🚗」
📱「災害対策用救助車 V型」
🧑「(ドヤ)」
👶「・・・」
👶「パパが言ってよ」
😰「・・・」
お蔵になりました。
Discussion