VOOZH about

URL: https://qiita.com/inamori/items/9fccb65528f28f3a81bc

⇱ 心臓が止まったらSNSに「死にました」と投稿する #Python - Qiita


👁 Image
1346

Go to list of users who liked

562

Share on X(Twitter)

Share on Facebook

Add to Hatena Bookmark

More than 5 years have passed since last update.

@inamori(_ Inamori)

心臓が止まったらSNSに「死にました」と投稿する

1346
Last updated at Posted at 2017-08-14

概要

👁 スクリーンショット 2017-08-14 20.10.02.png

fitbit(alta HR)で心拍数をモニタリングして、心拍数が0になったらSNSに「死にました」と投稿するスクリプトを書きました。

リポジトリ

僕はほぼ24時間fitbitを付けっぱなしにしているので、fitbitごと壊れる死に方でない限り大体カバーできるはずです。

fitbit alta HRとは
  • リストバンド型ウェアラブル端末の1つで、常時心拍数などを測れます
  • Pure Pulseという技術で従来のデバイスより正確に測れるらしいです
  • APIが充実しています

Fitbit APIで心拍数を監視する

Fitbitアプリを登録する

  • こちらから登録できます
  • 心拍数データを取るためには「OAuth 2.0 Application Type」を「Personal」にする必要があります

心拍数を取得する

  • python-fitbitを使わせてもらいました。使い方は他に多くの解説記事があるので割愛
  • access_tokenには有効期限があるので、fitbit.Fitbitをコールする時、refresh_cbを指定して自動更新されるようにしておく
  • 時間と心拍数を分けて取り出してるのは、後述の回帰分析で使うためです
class FitbitClient(object):
 def __init__(self):
 self.client_id = os.getenv('FITBIT_CLIENT_ID')
 self.client_secret = os.getenv('FITBIT_CLIENT_SECRET')
 token_file_name = os.getenv('TOKEN_FILE_NAME')
 tokens = open(token_file_name).read()
 token_dict = literal_eval(tokens)
 self.access_token = token_dict['access_token']
 self.refresh_token = token_dict['refresh_token']

 def refresh_call_back(token):
 with open(token_file_name, 'w') as f:
 f.write(str(token))
 self.access_token = token['access_token']
 self.refresh_token = token['refresh_token']

 self.client = fitbit.Fitbit(
 self.client_id, self.client_secret,
 access_token=self.access_token, refresh_token=self.refresh_token,
 refresh_cb=refresh_call_back
 )

 def request_heart_beats(self, date, limit=30):
 data_sec = self.client.intraday_time_series('activities/heart', date, detail_level='1sec')
 heart_sec = data_sec['activities-heart-intraday']['dataset']
 heart_sec = heart_sec[-limit:]
 seconds = map(self.fetch_sec, heart_sec)
 beats = map(lambda data: data['value'], heart_sec)
 return seconds, beats

 @staticmethod
 def fetch_sec(data):
 t = time.strptime(data['time'], '%H:%M:%S')
 return t.tm_hour * 3600 + t.tm_min * 60 + t.tm_sec

シャワーに行くたび死ぬのを防ぐ

心拍数を取得するところまでは簡単にできます。
あとはどうやって死んだことを確認するかですが、安直に「心拍数が0か、あるいはデータが返ってこなかったら死亡」とやってしまうと、シャワー浴びにちょっと外しただけで死にかねません。

そこで「直近30個のデータから回帰分析し、60秒後の心拍数が10未満と予測されたら死んだと見なす」というちょっとややこしいロジックで判定することにしました。
衰弱死でも病死でも失血死でも、だいたい死ぬ時は徐々に心拍数が下がってから死ぬだろう、という前提に基づいてます。
サンプルを取りすぎると、急激な運動の後のクールダウンでも誤判定してしまう弱点がありますが、まあ30データ(≒30〜60秒分のデータ)なら大丈夫でしょう。

class PhysicalHealthChecker(object):
 def __init__(self, provider, event_emitter):
 self.event_emitter = event_emitter
 self.heart_beat_provider = provider
 seconds, beats = self.heart_beat_provider.request_heart_beats('today')
 expected_beat = np.polyval(np.polyfit(seconds, beats, 1), seconds[-1] + 60)
 if self.is_alive(expected_beat):
 print 'still alive.'
 else:
 timestamp_file_name = 'death_time.txt'
 death_time = open(timestamp_file_name, 'r').read()
 if not death_time:
 print 'dead.'
 self.event_emitter.emit('death')
 with open(timestamp_file_name, 'w') as file:
 file.write(datetime.now().strftime("%Y/%m/%d %H:%M:%S"))

 @staticmethod
 def is_alive(heart_beat):
 return heart_beat >= 10


if __name__ == '__main__':
 ifttt_key = os.getenv('IFTTT_WEB_HOOK_KEY')
 fitbitHealthChecker = PhysicalHealthChecker(FitbitClient(), IftttEventEmitter(ifttt_key))

死んだらSNSに投稿する

IFTTTに「If {Webhook} Then {Twitter/Facebook POST}」なAppletを事前に作り、webhookをコールするだけです

👁 スクリーンショット 2017-08-14 23.14.00.png

class IftttEventEmitter(object):
 def __init__(self, secret_key):
 self.secret_key = secret_key

 def emit(self, event_name):
 requests.get('https://maker.ifttt.com/trigger/' + event_name + '/with/key/' + self.secret_key)

  • あとはcronなりで回すだけです

既知の問題

  • APIで当日分の心拍数しか取ってないので、日付をまたいで死んだら誤作動しそうです

応用編

  • 闇の組織と交渉する時に「やめときな。俺が死んだら例のファイルは信頼できる仲間の所に転送される事になってる」というやつができます
  • 僕には全く関係無い話ですが、死ぬ時いかがわしいファイルを自動で消したい!という用途にも使えそうです
1346

Go to list of users who liked

562
21

Go to list of comments

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1346

Go to list of users who liked

562