donutsorelse
Published © GPL3+

Using Fitbit to Make Scary Movies Scarier

By using my wife's Fitbit, I trigger different scary events in the room based on her heart rate.

IntermediateFull instructions provided4 hours104
Using Fitbit to Make Scary Movies Scarier

Things used in this project

Story

Read more

Schematics

Arduino Schematics

Super simple schematic for servo usage

Code

Python Code

Python
This does the majority of the work for this project
import time
import requests
import sys
import oauth2 as oauth
import serial
import asyncio
from kasa import SmartDimmer
from datetime import datetime, timedelta
from playsound import playsound


ser = serial.Serial('<ADD SERIAL PORT HERE (eg. COM5)>', 9600)

#To get new access token, click the tutorial link in the api - https://dev.fitbit.com/apps
access_token ='<TOKEN HERE>'
user_id = '<USER ID HERE>'

p = SmartDimmer("<PUT YOUR DIMMER'S IP ADDRESS HERE>")

minuteAdjustment = timedelta(minutes=15)
mostRecentTime = datetime.now() - minuteAdjustment #just a starting place

async def setBrightness(brightness):
    await p.update()  # Request the update
    print(p.alias)  # Print out the alias
    await p.set_brightness(brightness)

async def turnOn(isOn):
	await p.update()  # Request the update
	print(p.alias)  # Print out the alias
	if isOn:
		p.turn_on
	else:
		p.turn_off

def getFitbitData():
	try:
		date = datetime.now()
		start_time = date - minuteAdjustment
		end_time = date


		strDate = date.strftime("%Y-%m-%d")
		strStart = start_time.strftime("%H:%M")
		strEnd = end_time.strftime("%H:%M")


		hr_request = requests.get('https://api.fitbit.com/1/user/'+ user_id +'/activities/heart/date/' + strDate  + '/1d/1sec/time/' + strStart + '/' + strEnd + '.json', headers={'Authorization': 'Bearer ' + access_token})
		print("Status Code "+str(hr_request.status_code))
        #This means you're spamming fitbit and they don't like it - time to take a break
		if hr_request.status_code == 429:
			print("Retry after" + hr_request.headers["Retry-After"])
			time.sleep(int(hr_request.headers["Retry-After"]))
		# Store intraday heart data
		intraday_hr_data = hr_request.json()['activities-heart-intraday']['dataset']
		print(intraday_hr_data)
		if len(intraday_hr_data)>0:
			val = intraday_hr_data[len(intraday_hr_data)-1]['value']
			eventTime = intraday_hr_data[len(intraday_hr_data)-1]['time']	#don't trigger the same event over and over
			print(eventTime)
			global mostRecentTime
			print(mostRecentTime)
			if eventTime != mostRecentTime:
				mostRecentTime = eventTime
				print(val)
				ser.write(val)

				#Non-random - that way we also get to know the heart rate exactly for fun :)  (all higher than resting, tho)
				#Scurry sounds -
				if val >90:
					ser.write(val.encode())
				if val <80:
					asyncio.run(setBrightness(30))
					print("Option 1")
				else:
					if val <85:
						asyncio.run(setBrightness(15))
						print("Option 2")
					else:
						if val <90:
							asyncio.run(setBrightness(5))
							print("Option 3")
                #You'll obviously need to adjust this based on the sounds you've picked
				if val == 94 or val == 84 or val == 104:
					playsound('blehNoise.mp3')
					print("Option 4")
				if val == 95 or val == 85 or val == 105:
					playsound('Straw Squeak.mp3')
					print("Option 5")
				if val == 96 or val == 86 or val == 106:
					playsound('scream1.mp3')
					print("Option 6")
				if val == 97 or val == 87 or val == 107:
					playsound('scream2.mp3')
					print("Option 7")
				if val == 102 or val == 88 or val == 108:
					playsound('Swoosh.mp3')
					print("Option 8")
				if val >98 and val != 105:
					print("Option 9")
                    #Flicker the lights (this one is fun)
					asyncio.run(setBrightness(1))
					time.sleep(1)
					asyncio.run(setBrightness(100))
					time.sleep(1)
					asyncio.run(setBrightness(1))
					time.sleep(1)
					asyncio.run(setBrightness(100))
					time.sleep(1)
					asyncio.run(setBrightness(1))
				if val == 101:
					playsound('weKillU.mp3')
					print("Option 10")
				if val == 105:
					asyncio.run(turnOn(False))
					print("Option 11")
	except Exception as e: print(e)
		#nothing needs to happen - just don't want the program to stop running



#Loop indefinitely, fetching fitbit data every 30 seconds
while True:
	getFitbitData()
	time.sleep(30)

Arduino Code

Arduino
Super simple, but easily modifiable
#include <Servo.h>

Servo name_servo;

int servo_position = 0;
int incomingByte = 0;   // for incoming serial data
bool hasRun = false;
long triggerTime;

void setup() {

  Serial.begin (9600);
  name_servo.attach (3);
  triggerTime= millis()+(1000L*60L*90L);  //Failsafe - ensure the servo is triggered at least once regardless of fitbit
}

void loop() {

  //Since there's only 1 option, if anything comes in on serial, we trigger the event
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();
  
    //Decode from python - 
    Serial.print("I received: ");
    Serial.println(incomingByte, DEC);

    if(!hasRun)
      runServo();
  }
  
  //The failsafe
  if(!hasRun && millis()>=triggerTime){
    runServo();
  }
}

void runServo(){

  //Spin the servo
  for (servo_position = 0; servo_position <=360; servo_position +=1){
    name_servo.write(servo_position);
    delay(10);
  }
  hasRun=true;
}

Credits

donutsorelse
21 projects • 21 followers
I make different stuff every week of all kinds. Usually I make funny yet useful inventions.
Contact

Comments

Please log in or sign up to comment.