傘持ち忘れ防止の声掛け装置📣(obnizを活用したIoTプロトタイプの作成)
【製品アイデア】
今日の天気が雨ならオカンが「傘もっていき!」と言ってくれるおせっかい声掛け装置
-
使用するセンサのイメージ
超音波センサ(ドアに近づいたら動作) -
使用するアクチュエータのイメージ
サーボモータ(サーボモータでボイスレコーダの再生ボタンを押す)
↑事前に「傘もっていき!」を録音しておく -
使用するAPI
OpenWeather(livedoor 天気互換は前回使ったから今回は違うやつで、余裕がなかったらlivedoor 天気互換を使う)
作業イメージ
- 一旦、OpenWeatherのAPIを利用して現在の富山の天気が雨ならLチカするプログラムを作る
- 今日の富山の6-18の間に雨が含まれていたら"T"を出力するようにする
- 今日の富山の6-18の間に雨が含まれていたらサーボモータを動かす
- 超音波センサが○○mm以内かつ今日の富山の6-18間に雨が含まれていれば動作
- 玄関のドアに設置、調整
以降余裕があれば空きポートに実装(多分ないけどQiita記事たくさんありそうだからすぐ実装できそうなら)
- チルトセンサのON、OFFをobnizのディスプレイに出力
- チルトセンサのON、OFFをLINE Botで確認できるようにする(オカン言葉で)
- サムターンに設置、調整→外出先でも家の鍵をかけたかわかる
https://oshiete.ai/workspace)に作ってもらう
まず、現在の富山の天気が雨ならLチカするプログラムをGTP-4o(## 命令
あなたはobnizを使用して、天気が雨の場合、LEDを点灯させるプログラムを作りたい。
開発者コンソールで実行できるサンプルコードを書いてください。
## 使用するAPI
https://openweathermap.org/api
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/obniz@3.30.0/obniz.js"></script>
</head>
<body>
<script>
// ObnizデバイスIDとOpenWeatherMap APIキーを設定
const obnizId = "";
const weatherAPIKey = "";
// 天気情報を取得する関数
async function getWeather() {
const url = `https://api.openweathermap.org/data/2.5/weather?q=yourcity&appid=${weatherAPIKey}`;
const response = await fetch(url);
const weatherData = await response.json();
return weatherData;
}
// LEDを制御する関数
async function controlLED() {
const obniz = new Obniz(obnizId);
await obniz.connectWait();
// LEDをobnizのデジタルピン0に接続
const led = obniz.wired("LED", {anode:0});
const weatherData = await getWeather();
console.log(weatherData.weather[0].main);
// 天気データに基づいてLEDを点灯/消灯
if (weatherData.weather[0].main === "Rain") {
led.on(); // 点灯
} else {
led.off(); // 消灯
}
}
// プログラム開始
controlLED();
</script>
</body>
</html>
GTP-4oだと定義をconstとletで書いてくれるからうれしい。
3.5 Turboだとvarだったような気がする。
APIキーとobnizIDを入力して、yourcityを"toyama"にしてdone
- 一旦、OpenWeatherのAPIを利用して富山の天気が雨ならLEDを点灯するプログラムを作る
「COEIROINK」という読み上げソフトで「音声合成お母さん」というモデルを使えるらしい笑
APIのurlを以下に変更して3時間ごとの天気を取得
- const url = `https://api.openweathermap.org/data/2.5/weather?q=toyama&appid=${weatherAPIKey}`;
+ const url = `https://api.openweathermap.org/data/2.5/forecast?q=toyama&appid=${weatherAPIKey}`;
以下で6時~18時の天気をコンソールログで確認
console.log(weatherData.list[2].weather[0].main);
console.log(weatherData.list[3].weather[0].main);
console.log(weatherData.list[4].weather[0].main);
console.log(weatherData.list[5].weather[0].main);
console.log(weatherData.list[6].weather[0].main);
if文でweatherData.list[2].weather[0].main~weatherData.list[6].weather[0].mainの中に"Rain"が含まれている場合、コンソールログに"T"を出力させてみる
3ラリーもしてしまった。
## 命令
・weatherData.list[2].weather[0].main
・weatherData.list[3].weather[0].main
・weatherData.list[4].weather[0].main
・weatherData.list[5].weather[0].main
・weatherData.list[6].weather[0].main
に "Rain"が含まれている場合、"T"出力し、"Rain"が含まれない場合は、"F"を出力したい。
for文とif文使った##JavaScriptコードを出力して
for (let i = 2; i <= 6; i++) {
if (weatherData.list[i].weather[0].main === "Rain") {
console.log("T");
} else {
console.log("F");
}
}
×:1回の結果ごとに"T", "F"を出力
## 命令
一回一回出力するのではなく最終的に一回だけ出力したい
let containsRain = false;
for (let i = 2; i <= 6; i++) {
if (weatherData.list[i].weather[0].main === "Rain") {
containsRain = true;
break; // "Rain"が見つかったらループを終了
}
}
if (containsRain) {
console.log("T");
} else {
console.log("F");
}
×:最終的に"T"と"F"の配列を返してきた
## 命令
TとFを全て出力するのではなく、Tが含まれていればTだけを返し、Tが含まれていなければFだけ返したい
let containsRain = false;
for (let i = 2; i <= 6; i++) {
if (weatherData.list[i].weather[0].main === "Rain") {
containsRain = true;
break; // "Rain"が見つかったらループを終了
}
}
if (containsRain) {
console.log("T");
} else {
console.log("F");
}
○: "T"だけ返ってきた!
done
- 今日の富山の6-18の間に雨が含まれていたら"T"を出力するようにする
今度はweatherData.list[2].weather[0].main~weatherData.list[6].weather[0].mainの中に"Rain"が含まれている場合、サーボモータを動かすように変更(一旦角度はテキトーで)
これはGTPに聞かずともSG90サンプルコード(https://docs.obniz.com/ja/sdk/parts/ServoMotor/README.md)でなんとかなりそう
async function play() {
const obniz = new Obniz(obnizId);
await obniz.connectWait();
const weatherData = await getWeather();
// サーボモータを0~2pinに接続
const servo = obniz.wired("ServoMotor", {gnd:0,vcc:1,signal:2});
let containsRain = false;
for (let i = 2; i <= 6; i++) {
if (weatherData.list[i].weather[0].main === "Rain") {
containsRain = true;
break; // "Rain"が見つかったらループを終了
}
}
if (containsRain) {
console.log("T");
servo.angle(10.0);
servo.angle(0);
} else {
console.log("F");
}
}
// プログラム開始
play();
GPT-4)に聞いてみる。(教えてAIのGTP-4oは今日のチャット数の上限を迎えてしまった。)
自力で天気=雨 and 超音波センサ<50mmならサーボ起動させようと思ったけどエラー出たからリートン(あなたはobnizのエキスパートです。
天気を取得してRainかつ超音波センサが50mm以下ならサーボモータを90度回転させたい
以下の##JavaScriptコードでエラーがでる。修正点を教えて
##JavScriptコード
// ObnizデバイスIDとOpenWeatherMap APIキーを設定
const obnizId = "";
const weatherAPIKey = "";
copy
// 天気情報を取得する関数
async function getWeather() {
const url = `https://api.openweathermap.org/data/2.5/forecast?q=toyama&appid=${weatherAPIKey}`;
const response = await fetch(url);
const weatherData = await response.json();
return weatherData;
}
// LEDを制御する関数
async function play() {
const obniz = new Obniz(obnizId);
await obniz.connectWait();
const weatherData = await getWeather();
// サーボモータを0~2pinに接続
const servo = obniz.wired("ServoMotor", {gnd:0,vcc:1,signal:2});
// 超音波センサを7~11pinに接続
const hcsr04 = obniz.wired('HC-SR04', {
gnd: 8,
echo: 9,
trigger: 10,
vcc: 11,
});
// setIntervalで定期実行
setInterval(async () => {
let containsRain = false;
for (let i = 2; i <= 6; i++) {
if (weatherData.list[i].weather[0].main === "Rain") {
containsRain = true;
break; // "Rain"が見つかったらループを終了
}
}
if (containsRain) {
console.log("T");
} else {
console.log("F");
servo.angle(90.0);
await obniz.wait(1000);
servo.angle(0);
}
}, 1000);
// プログラム開始
play();
// ObnizデバイスIDとOpenWeatherMap APIキーを設定
const obnizId = "********";
const weatherAPIKey = "********";
// 天気情報を取得する関数
async function getWeather() {
const url = `https://api.openweathermap.org/data/2.5/forecast?q=toyama&appid=${weatherAPIKey}`;
const response = await fetch(url);
const weatherData = await response.json();
return weatherData;
}
// LEDを制御する関数
async function play() {
const obniz = new Obniz(obnizId);
await obniz.connectWait();
// サーボモータを0~2pinに接続
const servo = obniz.wired("ServoMotor", {gnd:0,vcc:1,signal:2});
// 超音波センサを7~11pinに接続
const hcsr04 = obniz.wired('HC-SR04', {
gnd: 8,
echo: 9,
trigger: 10,
vcc: 11,
});
// setIntervalで定期実行
setInterval(async () => {
const weatherData = await getWeather();
let containsRain = false;
for (let i = 2; i <= 6; i++) {
if (weatherData.list[i].weather[0].main === "Rain") {
containsRain = true;
break; // "Rain"が見つかったらループを終了
}
}
// 超音波センサで距離を取得
const distance = await hcsr04.measureWait();
console.log(`Distance: ${distance} mm`);
if (containsRain && distance <= 50) {
console.log("Rain detected and distance <= 50mm");
servo.angle(90);
await obniz.wait(500);
servo.angle(0);
} else {
console.log("No rain or distance > 50mm");
}
}, 1000); // 1秒ごとに実行
}
// プログラム開始
play();
なんか動いたラッキー
音声合成お母さんが思ったイメージではなかったので却下。(声がかわいすぎる。少なくともオカンではない)
動画編集で使っているCapCut(https://www.capcut.com/ja-jp/)のテキスト読み上げに歌ってくれる機能があるみたいなのでそれを使う。
パソコンから音声を流してボイスレコーダーで撮る。
ボイスレコーダのボタン硬くてサーボモータのホーンで押せねえ。。。
わたなべさんに相談したけど、サーボの強いモデルを買うか、SG90の2個使いか。
仕事終わり富山唯一の実店舗を見に行ってみる。最悪パソコンのエンターを押させてパソコンから流すか。。。
チルトセンサ(傾きセンサ)調達してきたけどやっぱり実装する余裕はなさそう。
今日発信してからチャレンジしてみよう。最低限の発信最優先。前回のりこさんから学んだ。