Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added 2025/.gitkeep
Empty file.
1 change: 1 addition & 0 deletions 2025/ne241100
Submodule ne241100 added at 8040ff
12 changes: 12 additions & 0 deletions 2025_09_02.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/sh

echo"_START_"
BASE_DIR=`pwd`
echo"現在のディレクトリは${BASE_DIR}です"
ls -al
echo "${BASE_DIR}内のファイルリストを表示"

exit



Binary file added docs/ne241100_発表スライド.pdf
Binary file not shown.
14 changes: 14 additions & 0 deletions src/concentration_monitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[Unit]
Description=Concentration Monitor Service
After=network.target

[Service]
ExecStart=/usr/bin/python3 /home/pi/concentration_monitor/sensor_client.py
WorkingDirectory=/home/pi/concentration_monitor
StandardOutput=inherit
StandardError=inherit
Restart=always
User=pi

[Install]
WantedBy=multi-user.target
71 changes: 71 additions & 0 deletions src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import functions_framework
from google.cloud import firestore
import requests

# --- 設定 ---
LINE_NOTIFY_TOKEN = 'MY_LINE_NOTIFY_TOKEN'
LINE_NOTIFY_API_URL = 'https://notify-api.line.me/api/notify'
COLLECTION_NAME = 'angle_data'

# --- 判定ロジックの閾値 ---
X_MIN, X_MAX = -40, -20
Y_MIN, Y_MAX = -60, -40
CONSECUTIVE_COUNT_THRESHOLD = 10

# Firestoreクライアントの初期化
db = firestore.Client()

def send_line_notification(message):
"""LINE Notifyへ通知を送信する関数"""
try:
headers = {'Authorization': f'Bearer {LINE_NOTIFY_TOKEN}'}
data = {'message': message}
response = requests.post(LINE_NOTIFY_API_URL, headers=headers, data=data)
return response.status_code == 200
except Exception as e:
print(f"LINE通知エラー: {e}")
return False

def is_concentration_lapsed(data):
"""集中力が途切れているかを判定する関数"""
x = data.get('x_angle', 0)
y = data.get('y_angle', 0)
return Y_MIN <= y <= Y_MAX and X_MIN <= x <= X_MAX

@functions_framework.cloud_event
def concentration_check(cloud_event):
"""Firestoreへの書き込みをトリガーに実行されるメイン関数"""

docs = db.collection(COLLECTION_NAME).order_by(
'timestamp', direction=firestore.Query.DESCENDING
).limit(CONSECUTIVE_COUNT_THRESHOLD).stream()

recent_data = [doc.to_dict() for doc in docs]

if len(recent_data) < CONSECUTIVE_COUNT_THRESHOLD:
print(f"データが{CONSECUTIVE_COUNT_THRESHOLD}件未満のため、連続判定をスキップします。")
return

consecutive_lapses = 0
for data in recent_data:
if is_concentration_lapsed(data):
consecutive_lapses += 1
else:
# 連続が途切れた時点でループを抜ける
break

# 6. 通知
if consecutive_lapses == CONSECUTIVE_COUNT_THRESHOLD:
message = "【警告】集中力が途切れている可能性が非常に高いです。休憩を取りましょう。"
print(f"通知実行: {message}")
send_line_notification(message)

elif is_concentration_lapsed(recent_data[0]) and not is_concentration_lapsed(recent_data[1]):
message = "【注意】集中力が途切れている可能性があります。"
print(f"通知実行: {message}")
send_line_notification(message)

else:
print("通知条件を満たしませんでした。")

return 'OK'
Empty file added src/sample/2025/.gitkeep
Empty file.
1 change: 1 addition & 0 deletions src/sample/2025/ne241100
Submodule ne241100 added at c777f8
Empty file added src/sample/data/.gitkeep
Empty file.
12 changes: 12 additions & 0 deletions src/sample/data/cpu_thermal.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
2021-09-09T11:36:09 JST CPU Thermal level: 84
2021-09-09T11:36:25 JST CPU Thermal level: 83
2022-09-09T16:13:07 JST CPU Power: 76 mW
2022-09-09T16:13:23 JST CPU Power: 410 mW
2022-09-09T16:13:39 JST CPU Power: 392 mW
2022-09-09T16:13:55 JST CPU Power: 54 mW
2022-09-09T16:14:11 JST CPU Power: 121 mW
2022-09-09T16:14:27 JST CPU Power: 220 mW
2022-09-09T16:14:44 JST CPU Power: 124 mW
2022-09-09T16:15:00 JST CPU Power: 145 mW
2022-09-09T16:15:16 JST CPU Power: 61 mW
2022-09-09T16:15:32 JST CPU Power: 161 mW
19 changes: 19 additions & 0 deletions src/sample/getAccelerometerData.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys

base_dir = '/home/pi'
prj_dir = base_dir + '/csn_raspi'
data_dir = prj_dir + '/earthquakes'
base_filename = 'csn.log'

def getCurrentData():
with open(data_dir + '/' + base_filename, mode='r') as f:
reader = f.readlines()
last_index = len(reader) - 1
return reader[last_index]

if __name__ == "__main__":
_data = getCurrentData()
print(_data)
8 changes: 8 additions & 0 deletions src/sample/get_cpu_temp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

while true
do
# /usr/bin/powermetrics -b 1 -n 1 -s tasks --show-process-energy --show-process-io | sed -l "s/^/$(date +%Y-%m-%dT%H:%M:%S" "%Z) /" >> ./data/process_energy_io.dat
/usr/bin/powermetrics -b 1 -n 1 -s smc | grep "CPU Thermal level" | sed -l "s/^/$(date +%Y-%m-%dT%H:%M:%S" "%Z) /" >> ./data/cpu_thermal.dat
sleep 10
done
31 changes: 31 additions & 0 deletions src/sample/load_mat_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import scipy.io
#mat = scipy.io.loadmat('/Users/hiroki_u/MATLAB-Drive/MobileSensorData/sensorlog_20210905_221919.mat')
#mat = scipy.io.loadmat('/Users/hiroki_u/MATLAB-Drive/MobileSensorData/sensorlog_20210905_233837.mat')
mat = scipy.io.loadmat('/Users/hiroki_u/MATLAB-Drive/test.mat')

print(mat)
print(sorted(mat.keys()))
print(mat['__header__'])
print(mat['__version__'])
print(mat['__globals__'])
#print(mat['None'])
#print(mat['None'][0][3])
#print(mat['__function_workspace__'][0].shape[0])
#print(mat['__function_workspace__'][0])

#teststruct = mat['__function_workspace__']
#print(teststruct.dtype)
#print(teststruct.size)
#print(teststruct.shape)

#for _data in mat['__function_workspace__']:
# for _d in _data:
# print(_d)

print(mat['matVar1'])

for _data in mat['matVar1']:
print("x : " + str(_data[0]), end = '\t')
print("y : " + str(_data[1]), end = '\t')
print("z : " + str(_data[2]))

10 changes: 10 additions & 0 deletions src/sample/shellscript_sample_01.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh

echo ”___START___”
BASE_DIR=`pwd`
echo “現在のディレクトリは${BASE_DIR}です”
ls –al
echo “${BASE_DIR}内のファイルリストを表示”

exit

23 changes: 23 additions & 0 deletions src/sample/shellscript_sample_02.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/sh

echo ”___START___”
BASE_DIR=`pwd`
echo “現在のディレクトリは${BASE_DIR}です”
ls -al
echo “${BASE_DIR}内のファイルリストを表示しました。”
echo ""
echo “${BASE_DIR}内のファイルリストをサイズの降順に並べ替えます。”
ls -alh | sort -k 5 -h -r


echo “${BASE_DIR}以下のファイル名をすべて取得します。”
FILELIST=`find ${BASE_DIR} -name '*.*'`
for _FILES in ${FILELIST[@]}; do
echo ${_FILES}
FILENAME=${_FILES##*/}
echo "${FILENAME}と同じ名前のをファイル探します。"
find ${HOME}/Documents -name '${FILENAME'
done

exit

78 changes: 78 additions & 0 deletions src/sample/update_channel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import requests

api_key = ''
channle_id = ''
data_file = "./data/cpu_thermal.dat"

_ts_base_url = "https://api.thingspeak.com"
ts_update_url = _ts_base_url + "/update"
# GET https://api.thingspeak.com/update?api_key=MSUJ80Z21B6XIS7G&field1=0

# HTTPでのデータ登録のための設定
headers = {'X-THINGSPEAKAPIKEY': api_key}


#------
# powermetricsで取得したCPU die tempartureの値を取得して、配列を返す
# 引数:データが入ったファイルのパス
# return : cpu_temp リスト(配列)
# 2021-09-07T23:59:36 JST CPU die temperature: 69.77 C
#------
def getCpuTempFromFile(filename):

_cpu_temps = []

# ファイルの存在を確認
is_file = os.path.exists(filename)
if not is_file:
print("正しいファイル名を指定してください。")
sys.exit(1)

# ファイルを開いてデータを取得
with open(filename) as f:
_lines = f.readlines()
for _line in _lines: # 配列を1行ずつ取り出す
_data = _line.split() # ファイルの1行を空白で区切って配列にする
print(_data) # 1行の中身を確認
# ここで、1行のデータのどの部分をどう使うか考えて処理する
if _data[5] == 'Normal' :
_data[5] = 100
_cpu_temps.append(_data[5]) # 区切った5つ目を結果用の配列に追記する

return _cpu_temps

#------
# 指定したデータをThingSpeakに登録
# 引数:req_url, headers, post_data
#------
def post2ThingSpeak(req_url, headers, post_data):
while True:
response = requests.post(req_url, headers=headers, data=post_data)
if response.text != '0':
break
time.sleep(1)


# メイン処理
cpu_temps = []

print(data_file + " のデータをThingSpeakに登録します。")
# CPU温度の情報をファイルから取得
cpu_temps = getCpuTempFromFile(data_file)

print("CPU温度のデータが " + str(len(cpu_temps)) + " 件あります。")
# データの中身をすべて表示
print(cpu_temps)

# 最新のデータ(一番最後)をThingSpeakに登録
# 登録するデータを設定
post_data = {'field1': cpu_temps[-1]}
post2ThingSpeak(ts_update_url, headers, post_data)

print("CPU温度:" + str(cpu_temps[-1]) + " を登録しました。")
sys.exit(0)
96 changes: 96 additions & 0 deletions src/sample/web_version/collect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import time
import board
import adafruit_mpu6050
import csv
import os
from datetime import datetime
import firebase_admin
from firebase_admin import credentials, firestore

# --- 設定 ---
# Firebaseの秘密鍵ファイル
CRED_PATH = 'your-firebase-credentials.json'
# Firebaseのコレクション名
COLLECTION_NAME = 'angle_data'
# ローカル保存するCSVファイル名
CSV_FILE = 'angle_log.csv'
# データ取得間隔(秒)
INTERVAL = 5

# --- Firebaseの初期化 ---
try:
cred = credentials.Certificate(CRED_PATH)
firebase_admin.initialize_app(cred)
db = firestore.client()
print(" Firebaseの初期化に成功しました。")
except Exception as e:
print(f" Firebaseの初期化に失敗: {e}")
exit()

# --- センサーの初期化 ---
try:
i2c = board.I2C() # uses board.SCL and board.SDA
mpu = adafruit_mpu6050.MPU6050(i2c)
print(" MPU6050センサーの初期化に成功しました。")
except Exception as e:
print(f" センサーの初期化に失敗: {e}")
# ダミーモードで動作させるためのフラグ
is_dummy_mode = True
print(" センサーが見つからないため、ダミーデータで動作します。")
else:
is_dummy_mode = False

# --- CSVファイルのヘッダー書き込み ---
if not os.path.exists(CSV_FILE):
with open(CSV_FILE, 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['timestamp', 'x_angle', 'y_angle'])

# --- メインループ ---
def main():
print(" データ収集を開始します...")
while True:
try:
# タイムスタンプ取得
now = datetime.now()
timestamp_str = now.strftime('%Y-%m-%d %H:%M:%S')

# 2. センサーから角度データを取得
if is_dummy_mode:
import random
# 集中力が途切れる可能性のある値をランダムに生成
x = random.uniform(-50, -10)
y = random.uniform(-70, -30)
else:
# 実際のセンサーから値を取得 (MPU6050ライブラリは加速度を返すので、
# 実際にはカルマンフィルタ等で角度に変換する処理が必要。ここでは簡略化)
accel = mpu.acceleration
# ここでは加速度のX, Yを角度に見立てて代入します
x = accel[0]
y = accel[1]

x_angle = round(x, 2)
y_angle = round(y, 2)

print(f"[{timestamp_str}] X: {x_angle}, Y: {y_angle}")

# 3. Raspberry Pi上にローカル保存 (CSV)
with open(CSV_FILE, 'a', newline='') as f:
writer = csv.writer(f)
writer.writerow([timestamp_str, x_angle, y_angle])

# 3. クラウドに保存 (Firestore)
data = {
'x_angle': x_angle,
'y_angle': y_angle,
'timestamp': firestore.SERVER_TIMESTAMP # クラウド側の正確な時刻を記録
}
db.collection(COLLECTION_NAME).add(data)

except Exception as e:
print(f"エラーが発生しました: {e}")

time.sleep(INTERVAL)

if __name__ == '__main__':
main()
Loading