diff --git a/Dockerfile b/Dockerfile index dbd1405..c76193f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,7 @@ ENV api_key= \ onmin=30 \ offhour=20 \ offmin=30 \ + update_interval=6 \ HTTP_PROXY=$all_proxy \ HTTPS_PROXY=$all_proxy diff --git a/README.md b/README.md new file mode 100644 index 0000000..9295ca1 --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# Google Traffic Screen [![Build Status](https://travis-ci.org/alatas/google-traffic-screen.svg?branch=master)](https://travis-ci.org/alatas/google-traffic-screen) +It's a project that can display the latest traffic information based on an origin location to multiple different locations. It uses Google Distance Matrix API. You need a valid GoogleMaps API key to query the latest information. + +Now, It's only available as docker image only + +## Quick Start +``` +docker pull alatas/google-traffic-display +docker run -ti -p 80:80 -e "api_key=your google maps api key" alatas/google-traffic-display +``` diff --git a/docker-compose.yml b/docker-compose.yml index 4ae427d..ebe5719 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,6 +17,7 @@ services: - language=en - units=imperial - traffic_model=best_guess + - update_interval=6 #update interval in min - all_proxy= #set proxy ports: - "80:80" diff --git a/googletrafficscreen.py b/googletrafficscreen.py index 8c399cc..ec471fc 100644 --- a/googletrafficscreen.py +++ b/googletrafficscreen.py @@ -14,157 +14,187 @@ import googlemaps -class Location: - def __init__(self, name, address): - self.name = name - self.address = address - self.distance = "", - self.eta = "", - self.level = 0, - self.speed = 0 +class Location(object): + + def __init__(self, name, address): + self.name = name + self.address = address + self.distance = "", + self.eta = "", + self.level = 0, + self.speed = 0 def copydefaults(): - if not os.path.isfile('www/index.html'): - print 'default index file copied' - copyfile('www/default-index.html', 'www/index.html') + if not os.path.isfile('www/index.html'): + print 'default index file copied' + copyfile('www/default-index.html', 'www/index.html') - if not os.path.isfile('www/locations.json'): - print 'default locations copied' - copyfile('www/default-locations.json', 'www/locations.json') + if not os.path.isfile('www/locations.json'): + print 'default locations copied' + copyfile('www/default-locations.json', 'www/locations.json') def loadlocations(): - with open('locations.json', 'r') as output: - print 'locations loaded' - return json.loads(output.read(), encoding='utf8') + with open('www/locations.json', 'r') as output: + locs = json.loads(output.read(), encoding='utf8')['locations'] + print 'locations loaded' + return [ + Location(loc['name'].encode('utf-8').strip(), + loc['address'].encode('utf-8').strip()) for loc in locs + ] + + +def loadorigin(): + with open('www/locations.json', 'r') as output: + loc = json.loads(output.read(), encoding='utf8')['origin'] + return { + "name": loc['name'].encode('utf-8').strip(), + "address": loc['address'].encode('utf-8').strip() + } def savesettings(): - with open('settings.json', 'w') as input: - input.write(json.dumps(settings)) - print 'settings saved' + with open('www/settings.json', 'w') as inp: + inp.write(json.dumps(SETTINGS)) + print 'settings saved' def startwebserver(): - Handler = SimpleHTTPServer.SimpleHTTPRequestHandler - httpd = SocketServer.TCPServer(("", 80), Handler) - print 'serving at port 80' - httpd.serve_forever() + handler = SimpleHTTPServer.SimpleHTTPRequestHandler + httpd = SocketServer.TCPServer(("", 80), handler) + print 'serving at port 80' + httpd.serve_forever() def isonduty(): - now = datetime.now().time() - if ontime <= offtime: - return ontime <= now < offtime - else: - return ontime <= now or now < offtime + now = datetime.now().time() + if ON_TIME <= OFF_TIME: + return ON_TIME <= now < OFF_TIME + else: + return ON_TIME <= now or now < OFF_TIME def run(): - while True: - if not isonduty(): - print "out of working hours" - else: - try: - pagesize = 25 # max size for free developer account - origins = [settings['origin']['address']] - alldestinations = [dest.address for dest in locations] - pageddestinations = [alldestinations[i:i+pagesize] - for i in range(0, len(alldestinations), pagesize)] - - for page, destinations in enumerate(pageddestinations): - ret = gmaps.distance_matrix(origins, destinations, mode=settings['params']['mode'], language=settings['params']['language'], - units=settings['params']['units'], departure_time=datetime.now(), traffic_model=settings['params']['traffic_model']) - - for i, element in enumerate(ret['rows'][0]['elements']): - locationItem = locations[(pagesize * page) + i] - - if element['status'] == 'OK': - updateelement(element, locationItem) - else: - resetelement(locationItem) - - with open('data.json', 'w') as output: - output.write(json.dumps( - [obj.__dict__ for obj in locations])) - - print 'data.json file updated {0}/{1}\n'.format( - page+1, len(pageddestinations)) - except Exception as e: - print 'Error when getting data from google\n{0}'.format(str(e)) - time.sleep(60) - - print 'sleeping for 3 min' - time.sleep(3 * 60) - - -def resetelement(locationItem): - locationItem.distance = "..." - locationItem.eta = 0 - locationItem.speed = 0 - locationItem.level = 0 - print '{0} couldn''t updated'.format(locationItem.name) - - -def updateelement(element, locationItem): - distance_km = float(element['distance']['value']) / 1000 - duration_hr = float(element['duration_in_traffic']['value']) / 3600 - - locationItem.distance = element['distance']['text'] - locationItem.eta = element['duration_in_traffic']['value'] - locationItem.speed = int(round(distance_km / duration_hr, 0)) - locationItem.level = findlevel( - locationItem.speed, int(element['distance']['value'])) - print '{0} updated {1} km - {2} km/h'.format( - locationItem.name, distance_km, locationItem.speed) + while True: + if not isonduty(): + print "out of working hours" + else: + try: + pagesize = 25 # max size for free developer account + origins = [SETTINGS['origin']['address']] + alldestinations = [dest.address for dest in LOCATIONS] + pageddestinations = [ + alldestinations[i:i + pagesize] + for i in range(0, len(alldestinations), pagesize) + ] + + for page, destinations in enumerate(pageddestinations): + ret = GMAPS.distance_matrix( + origins, + destinations, + mode=SETTINGS['params']['mode'], + language=SETTINGS['params']['language'], + units=SETTINGS['params']['units'], + departure_time=datetime.now(), + traffic_model=SETTINGS['params']['traffic_model']) + + for i, element in enumerate(ret['rows'][0]['elements']): + locationitem = LOCATIONS[(pagesize * page) + i] + + if element['status'] == 'OK': + updateelement(element, locationitem) + else: + resetelement(locationitem) + + with open('data.json', 'w') as output: + output.write(json.dumps([obj.__dict__ for obj in LOCATIONS])) + + print 'data.json file updated {0}/{1}\n'.format( + page + 1, len(pageddestinations)) + except Exception as e: + print 'Error when getting data from google\n{0}'.format(str(e.message)) + time.sleep(60) + + print 'sleeping for %d min' % UPDATE_INTERVAL + time.sleep(UPDATE_INTERVAL * 60) + + +def resetelement(locationitem): + locationitem.distance = "..." + locationitem.eta = 0 + locationitem.speed = 0 + locationitem.level = 0 + print '{0} couldn''t updated'.format(locationitem.name) + + +def updateelement(element, locationitem): + distance_km = float(element['distance']['value']) / 1000 + duration_hr = float(element['duration_in_traffic']['value']) / 3600 + + locationitem.distance = element['distance']['text'] + locationitem.eta = element['duration_in_traffic']['value'] + locationitem.speed = int(round(distance_km / duration_hr, 0)) + locationitem.level = findlevel(locationitem.speed, + int(element['distance']['value'])) + print '{0} updated {1} km - {2} km/h'.format(locationitem.name, distance_km, + locationitem.speed) def findlevel(speed, distance): - level1 = 6 * math.log(0.000984982 * distance) - level2 = 12 * math.log(0.000984982 * distance) - level3 = 17 * math.log(0.000984982 * distance) - if speed <= level1: - return "1" - elif speed <= level2: - return "2" - elif speed <= level3: - return "3" - else: - return "4" + level1 = 6 * math.log(0.000984982 * distance) + level2 = 12 * math.log(0.000984982 * distance) + level3 = 17 * math.log(0.000984982 * distance) + if speed <= level1: + return "1" + elif speed <= level2: + return "2" + elif speed <= level3: + return "3" + else: + return "4" def startupdate(): - thread = threading.Thread(target=run) - thread.daemon = True - thread.start() + thread = threading.Thread(target=run) + thread.daemon = True + thread.start() copydefaults() -os.chdir('www') -gmaps = googlemaps.Client(key=os.environ['api_key']) - -locations = loadlocations() -settings = {"origin": locations['origin'], "params": {"mode": os.environ['mode'], - "language": os.environ['language'], - "units": os.environ['units'], - "traffic_model": os.environ['traffic_model'], - "onhour": os.environ['onhour'], - "onmin": os.environ['onmin'], - "offhour": os.environ['offhour'], - "offmin": os.environ['offmin']}} + +GMAPS = googlemaps.Client(key=os.environ['api_key']) + +LOCATIONS = loadlocations() +SETTINGS = { + "origin": loadorigin(), + "params": { + "mode": os.environ['mode'], + "language": os.environ['language'], + "units": os.environ['units'], + "traffic_model": os.environ['traffic_model'], + "onhour": os.environ['onhour'], + "onmin": os.environ['onmin'], + "offhour": os.environ['offhour'], + "offmin": os.environ['offmin'], + "update_interval": os.environ["update_interval"] + } +} + savesettings() -locations = [Location(loc['name'].encode('utf-8').strip(), loc['address'].encode('utf-8').strip()) - for loc in locations['locations']] -ontime = time2(int(settings['params']['onhour']), - int(settings['params']['onmin'])) -offtime = time2(int(settings['params']['offhour']), - int(settings['params']['offmin'])) +ON_TIME = time2( + int(SETTINGS['params']['onhour']), int(SETTINGS['params']['onmin'])) +OFF_TIME = time2( + int(SETTINGS['params']['offhour']), int(SETTINGS['params']['offmin'])) -print 'working hours is between {0} -> {1}'.format(ontime, offtime) -print '{0} locations are loaded'.format(len(locations)) +UPDATE_INTERVAL = int(SETTINGS['params']['update_interval']) + +print 'working hours is between {0} -> {1}'.format(ON_TIME, OFF_TIME) +print '{0} locations are loaded'.format(len(LOCATIONS)) print 'starting server and updater' +os.chdir('www') + startupdate() startwebserver()