Easy-to-manage touch screens
무료 오픈소스 터치스크린으로 USB 설정 가이드, 드래그‑드롭 편집기, 로컬 제어를 제공하며 Home Assistant용으로 제작되었습니다
저장소 정보는 아직 수집하지 않았습니다.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
電気通信大学のU☆POCに向けたデバイスの開発
README 전체를 불러오는 중입니다.
README 전문 보기 ↗電気通信大学 U☆PoC(ユーザ志向アイディア実証コンテスト)応募作品。
生成AIで人格を持つIoTプランター。土壌湿度・温度・照度・空気湿度のセンサーデータをもとに、植物が擬人化キャラクターとして LINE で自発的に話しかけ、こちらの返信にも応える育成支援システム。単なる数値の可視化ではなく「感情の可視化」を目指す。
docs/proposal/PlanterAI.tex → PlanterAI.pdf6ページ構成の公式サイトは site/
にある。Viteでローカル起動と静的ビルドを行い、ルートの vercel.json
からVercelへデプロイする。
公開URL:https://planterai.vercel.app/
cd site
npm ci
npm run dev
本番用の静的ファイルは npm run build で site/dist/
に生成される。node_modules/ と dist/ は生成物のためGitでは管理しない。
[土壌湿度/温度/照度/湿度センサー]
│
[ESP32] --HTTP POST (x-device-key)--> [Edge Function: ingest-sensor]
│
┌──────────────────────────────────┼───────────────┐
▼ ▼ ▼
[Supabase DB] [Gemini Flash] 状態遷移時のみ
(センサー/感情/会話ログ) (セリフ生成) │
▼
[LINE] ──ユーザーの返信──> [Edge Function: line-webhook] ──> [LINE Messaging API] ──> ユーザー
▲
[Edge Function: weekly-summary]
(pg_cron で週次の関係性サマリー生成)
サーバーサイドは Supabase Edge Functions(Deno / TypeScript) で完結している。
センサー値からセリフ生成までを3層に分け、LLM にはセリフ生成のみを担わせることでハルシネーションを抑える。
normalize.ts)—
直近5サンプルの中央値フィルタでノイズを除去し、植物プロファイルの快適レンジに照らして
0〜100 の快適スコアへ変換。emotionEngine.ts / emotionTable.ts)—
スコアの緊急度と継続時間から、ルールベースで感情(満足/軽い不満/不満/不安/苛立ち)と主訴を判定。日照不足は瞬時値では誤発火するため、積算光量による日次判定(dailyLight.ts
/ dailyLightJob.ts、1日最大2回)に分離。llm.ts)— 状態が遷移したときだけ Gemini Flash
でキャラ口調のセリフを生成し LINE
通知。生成失敗時はテンプレ(fallback.ts)にフォールバックして通知を落とさない。通知の抑制:境界付近での状態の往復(チャタリング)による LINE
乱発を防ぐため、直近通知から
NOTIFY_COOLDOWN_MINUTES(既定60分)は原則再通知しない。不調を伝えたあとの別の不調(悪化していないもの)は3倍の180分あける。満足に戻ったときと危険域(urgency=high)はクールダウンを無視して即通知する(shouldNotify・cooldownFor)。
site/ Vite製の公式Webサイト
public/images/ Webサイトで使う画像
src/ JavaScriptとCSS
*.html 6ページのHTMLエントリ
supabase/ Edge FunctionsとDBマイグレーション
functions/_shared/ 状態判定・LLM・LINEなどの共有処理
functions/*/ ingest-sensor、line-webhook、weekly-summary
migrations/ PostgreSQLスキーマ
tests/ 状態判定・通知・日照判定・入力検証・LLMのテスト
docs/
proposal/ U☆PoC提案書と図版
slides/ ポスターとプレゼン資料
qr/ 公開サイトのQRコード
hardware/models/ 3Dプリント用モデル
archive/legacy-site/ 旧シングルページLP
_shared/config.ts):植物種ごとの快適/注意/危険レンジ。現在は
pothos(ポトス)と calathea(カラテア)を定義。devices.plant_profile
で切り替える。照度は非対称に扱い、瞬時値 lux で「日照過剰(葉焼け)」を、積算
lux·h で「日照不足」を判定する。_shared/weather.ts・_shared/dailyWeather.ts):WEATHER_LATITUDE・WEATHER_LONGITUDE
を入れると、Open-Meteo(鍵は要らない)で今日の天気を見る。日が差した時間が日の長さの半分に届かない日(曇りや雨)は、14時台の予告を出さず、20時も置き場所を責めずに「明日は晴れるといいね」と言う。予報は0時と12時に取って
daily_weather
に覚え、取りそこねたら前の予報を使う。今日の分が1度も取れていなければ送るのを次の回に回す(締めは21時まで)。入れなければ天気を見ずに判定する。家の場所は細かく入れず、市くらいの粗さ(小数1〜2桁)で足りる_shared/llm.ts):amaenbo(甘えん坊)/tsundere(ツンデレ)/keigo(執事風)。devices.character_id
で切り替える。_shared/config.ts):SOIL_CALIBRATION に
SEN0193 の実測 ADC 値(空気中/水中)を設定。| レイヤー | 技術 |
|---|---|
| マイコン | ESP32 + 土壌湿度・温度・照度・湿度センサー |
| サーバー | Supabase Edge Functions(Deno / TypeScript) |
| LLM | Gemini Flash |
| 通知 | LINE Messaging API(プッシュ通知 + Webhook双方向チャット) |
| DB | Supabase(PostgreSQL、RLS全拒否 + service_roleでアクセス) |
| バッチ | pg_cron(週次サマリー) |
前提:Supabase CLI、Node.js(テスト用)、LINE公式アカウント、Gemini API キー。
# 1. DBスキーマを反映
supabase db push
# 2. Edge Functions をデプロイ
# ingest-sensor は ESP32 が JWT を持たないため --no-verify-jwt で公開し、
# x-device-key による自前認証を使う
supabase functions deploy ingest-sensor --no-verify-jwt
supabase functions deploy line-webhook --no-verify-jwt
supabase functions deploy weekly-summary --no-verify-jwt
supabase functions deploy daily-diary --no-verify-jwt
# 3. シークレットを登録
supabase secrets set \
GEMINI_API_KEY=... \
LINE_CHANNEL_ACCESS_TOKEN=... \
LINE_CHANNEL_SECRET=... \
CRON_SECRET=... WEATHER_LATITUDE=35.66 WEATHER_LONGITUDE=139.54
# WEATHER_* は日照不足を天気のせいにするかの判断に使う(なくても動く)
# (SUPABASE_URL / SUPABASE_SERVICE_ROLE_KEY は自動で注入される)
_sharedを変更したら、それを import している function を全部再デプロイする。 Supabase は_sharedを function ごとにバンドルするため、共有ライブラリのように自動追随しない。 片方だけ古い_sharedを抱えたままになり、同じコードのはずなのに挙動が割れる (実例は「PlanterAI 定型文フォールバック多発 修正記録(2026-09-02)」)。
Supabase ダッシュボードの SQL Editor で実行する(値は書き換える)。
insert into devices (device_key, plant_name, character_id, line_user_id)
values ('ここに長いランダム文字列', 'ポト助', 'amaenbo', 'あなたのLINE User ID');
LINE User ID は LINE Developers
の「チャネル基本設定」→「あなたのユーザーID」(U で始まる文字列)。
LINE公式アカウントを自分の LINE で友だち追加しておかないと通知が届かない。
鉢の line_user_id には、1対1のユーザー ID のかわりに、LINE グループの ID (C
で始まる)も入れられる。グループに入れると、通知も週の日記もそのグループに届き、家族みんなが見られる(ADR
0012)。
line-webhook)に出る「LINE のグループに招待されました:
C…」から、グループの ID を読む(無料プランのログは1日で消える)update devices set line_user_id = 'グループの ID' where id = '鉢の id';
グループでは、植物の名前を呼んだときか、公式アカウントにメンションしたときだけ返事をする(「カラ美、元気?」「@PlanterAI 元気?」)。家族どうしの会話に毎回割り込まないため。1つのトークに複数の鉢を結ぶと、名前を呼ばれた鉢が答える。
여기까지가 README 앞부분입니다. 나머지는 원문에서 읽을 수 있습니다. README 전문 보기 ↗