import time
import math
class BikeComputer():
MM_IN_AN_INCH = 25.4
MM_IN_A_MILE = 1609344
MM_IN_A_KILOMETER = 1000000
SECONDS_IN_AN_HOUR = 3600
SECONDS_IN_A_MINUTE = 60
MS_IN_A_SECOND = 1000.0000
displayFormat = 'metric'
displayInterval = 1000 # Update display every 1 second
clicks = 0
tripBegin = 0
lastClick = 0
lastDisplay = 0
hertz = 0.0
displayVelocity = 0.0
velocity = 0.0
avgVelocity = 0.0
maxVelocity = 0.0
distance = 0.0
wheelCircumference = 2136.0
wheelDiameter = 680.0
def __init__(self, displayFormat):
self.displayFormat = displayFormat
self.clicks = 0
self.lastDisplay = int(time.time() * BikeComputer.MS_IN_A_SECOND)
self.lastClick = int(time.time() * BikeComputer.MS_IN_A_SECOND)
self.tripBegin = int(time.time() * BikeComputer.MS_IN_A_SECOND)
self.hertz = 0.0
self.index = 0
self.displayVelocity = 0.0
self.velocity = 0.0
self.avgVelocity = 0.0
self.maxVelocity = 0.0
self.distance = 0.0
self.wheelCircumference = 2136.0 # 700c x 28 according to a Bell cycling computer chart
self.wheelDiameter = self.wheelCircumference / math.pi
def update(self, currentTime, pinState):
# get the delta from our last click
clickDelta = max((currentTime - self.lastClick), 1)
# get the delta from our last display
displayDelta = max((currentTime - self.lastDisplay), 1)
if(pinState == True):
self.clicks += 1
# calculate the instantaneous speed
self.hertz = BikeComputer.MS_IN_A_SECOND / clickDelta
# Velocity = hertz * wheel circumference, in mm/s
self.velocity = (self.hertz * self.wheelCircumference)
self.maxVelocity = max(self.velocity,self.maxVelocity)
# Distance travelled = clicks * wheel circumference, in mm
self.distance = self.clicks * self.wheelCircumference
# Update the last click
self.lastClick = currentTime
else:
# decay the speed. We know that you aren't going fast enough to have done the next click yet
self.hertz = min((BikeComputer.MS_IN_A_SECOND / clickDelta), self.hertz)
self.velocity = self.hertz * self.wheelCircumference
# Distance travelled = clicks * wheel circumference, in mm
self.distance = self.clicks * self.wheelCircumference
# If we haven't updated the display in a while, do that now
if(displayDelta > self.displayInterval):
self.updateDisplayVelocity(currentTime);
self.lastDisplay = currentTime
def updateDisplayVelocity(self,currentTime):
self.displayVelocity = self.velocity
self.avgVelocity = self.distance / (((currentTime-self.tripBegin)+1)/1000.00)
if(self.displayFormat == 'metric' and (self.displayVelocity / BikeComputer.MM_IN_A_KILOMETER * BikeComputer.SECONDS_IN_AN_HOUR) < 1.0):
self.displayVelocity = 0.0
if(self.displayFormat == 'imperial' and (self.displayVelocity / BikeComputer.MM_IN_A_MILE * BikeComputer.SECONDS_IN_AN_HOUR) < 1.0):
self.displayVelocity = 0.0
def getClicks(self):
return str(self.clicks)
def getVelocity(self):
if(self.displayFormat == 'metric'):
return (self.velocity / BikeComputer.MM_IN_A_KILOMETER) * BikeComputer.SECONDS_IN_AN_HOUR
else:
return (self.velocity / BikeComputer.MM_IN_A_MILE) * BikeComputer.SECONDS_IN_AN_HOUR
def getDisplayVelocity(self):
if(self.displayFormat == 'metric'):
return (self.displayVelocity / BikeComputer.MM_IN_A_KILOMETER) * BikeComputer.SECONDS_IN_AN_HOUR
else:
return (self.displayVelocity / BikeComputer.MM_IN_A_MILE) * BikeComputer.SECONDS_IN_AN_HOUR
def getAverageVelocity(self):
if(self.displayFormat == 'metric'):
return (self.avgVelocity / BikeComputer.MM_IN_A_KILOMETER) * BikeComputer.SECONDS_IN_AN_HOUR
else:
return (self.avgVelocity / BikeComputer.MM_IN_A_MILE) * BikeComputer.SECONDS_IN_AN_HOUR
def getMaxVelocity(self):
if(self.displayFormat == 'metric'):
return (self.maxVelocity / BikeComputer.MM_IN_A_KILOMETER) * BikeComputer.SECONDS_IN_AN_HOUR
else:
return (self.maxVelocity / BikeComputer.MM_IN_A_MILE) * BikeComputer.SECONDS_IN_AN_HOUR
def getDistance(self):
if(self.displayFormat == 'metric'):
return (self.distance / BikeComputer.MM_IN_A_KILOMETER)
else:
return (self.distance / BikeComputer.MM_IN_A_MILE)
def getFormattedWheelCircumference(self):
if(self.displayFormat == 'metric'):
return str(self.wheelCircumference) + ' mm'
else:
return str(round(self.wheelCircumference / BikeComputer.MM_IN_AN_INCH,3)) + ' in'
def getFormattedWheelDiameter(self):
if(self.displayFormat == 'metric'):
return str(self.wheelDiameter) + ' mm'
else:
return str(round(self.wheelDiameter / BikeComputer.MM_IN_AN_INCH,3)) + ' in'
def getFormattedVelocity(self):
if(self.displayFormat == 'metric'):
return str(round((self.velocity / BikeComputer.MM_IN_A_KILOMETER) * BikeComputer.SECONDS_IN_AN_HOUR, 1)) + 'kmph'
else:
return str(round((self.velocity / BikeComputer.MM_IN_A_MILE) * BikeComputer.SECONDS_IN_AN_HOUR, 1)) + 'mph'
def getFormattedDisplayVelocity(self):
if(self.displayFormat == 'metric'):
return str(round((self.displayVelocity / BikeComputer.MM_IN_A_KILOMETER) * BikeComputer.SECONDS_IN_AN_HOUR, 1)) + 'kmph'
else:
return str(round((self.displayVelocity / BikeComputer.MM_IN_A_MILE) * BikeComputer.SECONDS_IN_AN_HOUR, 1)) + 'mph'
def getFormattedAvgVelocity(self):
if(self.displayFormat == 'metric'):
return str(round((self.avgVelocity / BikeComputer.MM_IN_A_KILOMETER) * BikeComputer.SECONDS_IN_AN_HOUR, 1)) + 'kmph'
else:
return str(round((self.avgVelocity / BikeComputer.MM_IN_A_MILE) * BikeComputer.SECONDS_IN_AN_HOUR, 1)) + 'mph'
def getFormattedDistance(self):
if(self.displayFormat == 'metric'):
return str(round((self.distance / BikeComputer.MM_IN_A_KILOMETER),1))+'km'
else:
return str(round((self.distance / BikeComputer.MM_IN_A_MILE),3))+'mi'