Initial Commit
151
.gitignore
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.xml
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
### Python template
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*,cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# dotenv
|
||||
.env
|
||||
|
||||
# virtualenv
|
||||
.venv
|
||||
venv/
|
||||
ENV/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
.idea/
|
||||
bells.py
|
||||
clock.json
|
||||
countdown.py
|
||||
events.txt
|
||||
panel.py
|
||||
panel_script.py
|
||||
requirements.txt
|
||||
res/
|
||||
weatherclock.py
|
||||
wxget.py
|
||||
91
bells.py
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from subprocess import Popen
|
||||
|
||||
from pydub import AudioSegment
|
||||
|
||||
bell1path = "res/wav/bellhit1.wav"
|
||||
bell2path = "res/wav/bellhit2.wav"
|
||||
bell3path = "res/wav/bellhit3.wav"
|
||||
bell4path = "res/wav/bellhit4.wav"
|
||||
bell5path = bell4path
|
||||
|
||||
g = AudioSegment.from_file(bell1path)
|
||||
e = AudioSegment.from_file(bell2path)
|
||||
f = AudioSegment.from_file(bell3path)
|
||||
b = AudioSegment.from_file(bell4path)
|
||||
e3 = AudioSegment.from_file(bell5path)
|
||||
|
||||
try:
|
||||
horn = AudioSegment.from_file("/home/pi/sound/traphorn.wav")
|
||||
except FileNotFoundError:
|
||||
horn = AudioSegment.empty()
|
||||
|
||||
phrase1 = [(g, .25), (f, .25), (e, .25), (b, .50)]
|
||||
phrase2 = [(e, .25), (g, .25), (f, .25), (b, .50)]
|
||||
phrase3 = [(e, .25), (f, .25), (g, .25), (e, .50)]
|
||||
phrase4 = [(g, .25), (e, .25), (f, .25), (b, .50)]
|
||||
phrase5 = [(b, .25), (f, .25), (g, .25), (e, .50)]
|
||||
rest = [(AudioSegment.empty(), .50)]
|
||||
strike = [(e3, .75)]
|
||||
trap_horn = [(horn, 0)]
|
||||
|
||||
whole_time = 3000
|
||||
|
||||
|
||||
def chime_length(chime):
|
||||
return sum(c[1] for c in chime) * whole_time + len(chime[-1][0])
|
||||
|
||||
|
||||
def play(audio):
|
||||
audio.export('/tmp/clock_chime.wav', 'wav')
|
||||
Popen(['aplay', '/tmp/clock_chime.wav', '-q'])
|
||||
|
||||
|
||||
def play_phrase(phrase):
|
||||
audio = AudioSegment.silent(chime_length(phrase))
|
||||
time = 0
|
||||
|
||||
for a, t in phrase:
|
||||
audio = audio.overlay(a, int(time))
|
||||
time += t * whole_time
|
||||
|
||||
play(audio)
|
||||
|
||||
|
||||
last_chime = None
|
||||
|
||||
|
||||
def play_chime(hour, minute):
|
||||
global last_chime
|
||||
this_chime = hour, minute
|
||||
if last_chime == this_chime:
|
||||
return
|
||||
last_chime = this_chime
|
||||
|
||||
chime = []
|
||||
|
||||
if hour == 16 and minute == 20:
|
||||
chime = trap_horn
|
||||
|
||||
if minute == 15:
|
||||
chime = phrase1
|
||||
if minute == 30:
|
||||
chime = phrase2 + phrase3
|
||||
if minute == 45:
|
||||
chime = phrase4 + phrase5 + phrase1
|
||||
if minute == 0:
|
||||
if hour > 12:
|
||||
hour -= 12
|
||||
if hour == 0:
|
||||
hour = 12
|
||||
chime = phrase2 + phrase3 + phrase4 + phrase5 + rest + strike * hour
|
||||
|
||||
if not chime:
|
||||
return
|
||||
|
||||
play_phrase(chime)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
play_chime(2, 00)
|
||||
39
clock.json
Normal file
@@ -0,0 +1,39 @@
|
||||
[
|
||||
{
|
||||
"surf": "panel_script::time",
|
||||
"anchor": "0.5,0.5"
|
||||
},
|
||||
{
|
||||
"surf": "500 500",
|
||||
"anchor": "0.5,0.5",
|
||||
"position": "0 250",
|
||||
"children": [
|
||||
{
|
||||
"surf": "panel_script::date",
|
||||
"position": "0 -60",
|
||||
"anchor": ".5 .5"
|
||||
},
|
||||
{
|
||||
"surf": "panel_script::icon",
|
||||
"position": "0 80",
|
||||
"anchor": ".5 .5",
|
||||
"pivot": "1 .5"
|
||||
},
|
||||
{
|
||||
"surf": "panel_script::temperature",
|
||||
"position": "0 80",
|
||||
"anchor": ".5 .5",
|
||||
"pivot": "0 .5"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"surf": "1280 100",
|
||||
"children": [
|
||||
{
|
||||
"surf": "panel_script::header",
|
||||
"anchor": ".5 .5"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
55
countdown.py
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import datetime
|
||||
import os
|
||||
|
||||
import timestring
|
||||
|
||||
|
||||
class Event(object):
|
||||
def __init__(self, date, label):
|
||||
self.label = label
|
||||
self.date = date
|
||||
|
||||
@property
|
||||
def time(self):
|
||||
r = timestring.Date(self.date).date - timestring.now().date # type: datetime.timedelta
|
||||
s = int(r.seconds)
|
||||
m, s = s // 60, s % 60
|
||||
h, m = m // 60, m % 60
|
||||
d, h = r.days, h % 25
|
||||
return {'days': d, 'hours': h, 'minutes': m, 'seconds': s, 'label': self.label}
|
||||
|
||||
def __format__(self, format_spec):
|
||||
return format_spec.format(**self.time)
|
||||
|
||||
def __str__(self):
|
||||
return format(self, '{days}d {hours}h {minutes}m {seconds}s to {label}')
|
||||
|
||||
|
||||
__events = []
|
||||
__event_load = 0
|
||||
|
||||
|
||||
def update_events(force=False):
|
||||
global __events, __event_load
|
||||
|
||||
event_time = os.stat('events.txt').st_mtime_ns
|
||||
if force or __event_load != event_time:
|
||||
with open('events.txt') as f:
|
||||
etext = [tuple(i.strip() for i in l.split('|')) for l in f.readlines() if
|
||||
l.strip() and not l.startswith('#')]
|
||||
__events = [Event(date, lbl) for lbl, date in etext]
|
||||
__event_load = event_time
|
||||
|
||||
|
||||
def get_events(force_update=False):
|
||||
update_events(force_update)
|
||||
|
||||
return __events
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(timestring.now())
|
||||
for e in get_events():
|
||||
print(e)
|
||||
8
events.txt
Executable file
@@ -0,0 +1,8 @@
|
||||
# datetime | event name
|
||||
# space before and after | omitted
|
||||
|
||||
Solar Eclipse | 8/21/2017 2:46:22PM
|
||||
Untrump | 1/20/2021 9:00AM
|
||||
Move-out | 5/12/2017 noon
|
||||
|
||||
# Dinner Tomorrow | Tomorrow 6:30pm
|
||||
141
panel.py
Normal file
@@ -0,0 +1,141 @@
|
||||
import importlib
|
||||
import json
|
||||
import re
|
||||
|
||||
import pygame
|
||||
|
||||
|
||||
class Panel(object):
|
||||
def __init__(self, surf, position=None, anchor=None, pivot=None, children=None):
|
||||
if isinstance(surf, tuple) or not surf:
|
||||
self.__surf = pygame.Surface(surf or (0, 0), flags=pygame.SRCALPHA)
|
||||
else:
|
||||
self.__surf = surf
|
||||
|
||||
self.position = position or (0, 0)
|
||||
self.anchor = anchor or (0, 0)
|
||||
self.pivot = pivot or self.anchor
|
||||
self.children = children or []
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
surf = self.__surf
|
||||
|
||||
if callable(surf):
|
||||
surf = surf()
|
||||
if isinstance(surf, Panel):
|
||||
return surf.size
|
||||
|
||||
return surf.get_width(), surf.get_height()
|
||||
|
||||
@property
|
||||
def surf(self):
|
||||
surf = self.__surf
|
||||
|
||||
if callable(surf):
|
||||
surf = surf()
|
||||
elif isinstance(surf, Panel):
|
||||
surf = surf.surf
|
||||
else:
|
||||
surf = surf.copy()
|
||||
|
||||
for child in self.children:
|
||||
c_surf = child
|
||||
position = (0, 0)
|
||||
|
||||
if isinstance(child, Panel):
|
||||
c_surf = child.surf
|
||||
|
||||
position = tuple(int(a * s - v * c + p) for a, v, s, c, p in
|
||||
zip(child.anchor, child.pivot, self.size, child.size, child.position))
|
||||
|
||||
if callable(c_surf):
|
||||
c_surf = c_surf()
|
||||
if isinstance(c_surf, Panel):
|
||||
c_surf=c_surf.surf
|
||||
|
||||
surf.blit(c_surf, position)
|
||||
|
||||
return surf
|
||||
|
||||
|
||||
old_modules = {}
|
||||
|
||||
|
||||
def load(file):
|
||||
loaded_modules = {}
|
||||
|
||||
def ordered_pair(s, dtype=float):
|
||||
if not s:
|
||||
return None
|
||||
|
||||
try:
|
||||
op = tuple(dtype(c) for c in (re.split(r'\s*[,x\s]\s*', s)))
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
if len(op) != 2:
|
||||
return None
|
||||
|
||||
return op
|
||||
|
||||
def script(s):
|
||||
if not s:
|
||||
return None
|
||||
|
||||
pair = re.split(r'::', s)
|
||||
|
||||
if len(pair) != 2:
|
||||
return None
|
||||
|
||||
mod, func = pair
|
||||
|
||||
if mod not in loaded_modules:
|
||||
if mod in old_modules:
|
||||
importlib.reload(old_modules[mod])
|
||||
|
||||
try:
|
||||
loaded_modules[mod] = importlib.import_module(mod)
|
||||
except ModuleNotFoundError:
|
||||
return None
|
||||
|
||||
mod = loaded_modules[mod]
|
||||
|
||||
try:
|
||||
func = getattr(mod, func)
|
||||
except AttributeError:
|
||||
return None
|
||||
|
||||
return func
|
||||
|
||||
def from_dict(d: dict):
|
||||
surf = d.get('surf', None)
|
||||
position = d.get('position', None)
|
||||
anchor = d.get('anchor', None)
|
||||
pivot = d.get('pivot', None)
|
||||
children = d.get('children', [])
|
||||
|
||||
surf = ordered_pair(surf, int) or script(surf)
|
||||
position = ordered_pair(position, int)
|
||||
anchor = ordered_pair(anchor)
|
||||
pivot = ordered_pair(pivot)
|
||||
children = [from_dict(d) for d in children]
|
||||
|
||||
return Panel(surf, position, anchor, pivot, children)
|
||||
|
||||
with open(file) as f:
|
||||
j = json.load(f)
|
||||
if isinstance(j, list):
|
||||
ls = [from_dict(d) for d in j]
|
||||
else:
|
||||
ls = [from_dict(j)]
|
||||
|
||||
old_modules.clear()
|
||||
for k, v in loaded_modules.items():
|
||||
old_modules[k] = v
|
||||
|
||||
return ls
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print(load('clock.json'))
|
||||
59
panel_script.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pygame
|
||||
|
||||
from countdown import get_events
|
||||
from panel import Panel
|
||||
from wxget import get_weather
|
||||
|
||||
pygame.font.init()
|
||||
|
||||
WHITE = (255, 255, 255)
|
||||
GRAY = (175, 175, 175)
|
||||
BLACK = (0, 0, 0)
|
||||
|
||||
font = {
|
||||
'RobotoSlab': {
|
||||
30: pygame.font.Font("res/RobotoSlab-Regular.ttf", 30),
|
||||
45: pygame.font.Font("res/RobotoSlab-Regular.ttf", 45),
|
||||
60: pygame.font.Font("res/RobotoSlab-Regular.ttf", 60),
|
||||
90: pygame.font.Font("res/RobotoSlab-Regular.ttf", 90),
|
||||
360: pygame.font.Font("res/RobotoSlab-Regular.ttf", 360),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def time():
|
||||
return font['RobotoSlab'][360].render(format(datetime.now(), '%I:%H').lstrip('0'), True, WHITE)
|
||||
|
||||
|
||||
def date():
|
||||
return font['RobotoSlab'][60].render(format(datetime.now(), '%A, %B %d'), True, GRAY)
|
||||
|
||||
|
||||
def temperature():
|
||||
f = font['RobotoSlab'][90]
|
||||
return f.render('{0[current_conditions][temperature]}\u00b0'.format(get_weather()), True, WHITE)
|
||||
|
||||
|
||||
def icon():
|
||||
return pygame.image.load('res/png/12.png')
|
||||
|
||||
|
||||
def header():
|
||||
es = get_events()
|
||||
|
||||
def item(i):
|
||||
f = font['RobotoSlab'][30]
|
||||
e = es[i]
|
||||
l = e.label
|
||||
t = '{days}d {hours}h {minutes}m'.format(**e.time)
|
||||
|
||||
return Panel((1280 // len(es), 70), anchor=((i + 1) / (len(es) + 1), .5), children=[
|
||||
Panel(f.render(l, True, WHITE), anchor=(.5, .5), pivot=(.5, .9)),
|
||||
Panel(f.render(t, True, GRAY), anchor=(.5, .5), pivot=(.5, .1)),
|
||||
])
|
||||
|
||||
return Panel((1280, 70), anchor=(.5, .5), children=[
|
||||
item(i) for i in range(len(get_events()))
|
||||
]).surf
|
||||
4
requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
pygame
|
||||
pydub
|
||||
timestring
|
||||
https://launchpad.net/python-weather-api/trunk/0.3.8/+download/pywapi-0.3.8.tar.gz
|
||||
BIN
res/RobotoSlab-Regular.ttf
Executable file
BIN
res/png/0.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
res/png/1.png
Executable file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
res/png/10.png
Executable file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
res/png/11.png
Executable file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
res/png/12.png
Executable file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
res/png/13.png
Executable file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
res/png/14.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
res/png/15.png
Executable file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
res/png/16.png
Executable file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
res/png/17.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
res/png/18.png
Executable file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
res/png/19.png
Executable file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
res/png/2.png
Executable file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
res/png/20.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
res/png/21.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
res/png/22.png
Executable file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
res/png/23.png
Executable file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
res/png/24.png
Executable file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
res/png/25.png
Executable file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
res/png/26.png
Executable file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
res/png/27.png
Executable file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
res/png/28.png
Executable file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
res/png/29.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
res/png/3.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
res/png/30.png
Executable file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
res/png/31.png
Executable file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
res/png/32.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
res/png/33.png
Executable file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
res/png/34.png
Executable file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
res/png/35.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
res/png/36.png
Executable file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
res/png/37.png
Executable file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
res/png/38.png
Executable file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
res/png/39.png
Executable file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
res/png/4.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
res/png/40.png
Executable file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
res/png/41.png
Executable file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
res/png/42.png
Executable file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
res/png/43.png
Executable file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
res/png/44.png
Executable file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
res/png/45.png
Executable file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
res/png/46.png
Executable file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
res/png/47.png
Executable file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
res/png/5.png
Executable file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
res/png/6.png
Executable file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
res/png/7.png
Executable file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
res/png/8.png
Executable file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
res/png/9.png
Executable file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
res/png/na.png
Executable file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
res/wav/bellhit1.wav
Executable file
BIN
res/wav/bellhit2.wav
Executable file
BIN
res/wav/bellhit3.wav
Executable file
BIN
res/wav/bellhit4.wav
Executable file
98
weatherclock.py
Executable file
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/python3
|
||||
import os
|
||||
|
||||
import pygame
|
||||
|
||||
import countdown
|
||||
import panel
|
||||
import wxget
|
||||
|
||||
CONFIG_PATH = 'clock.json'
|
||||
|
||||
pygame.init()
|
||||
|
||||
pygame.mouse.set_visible(False)
|
||||
|
||||
SIZE = (1280, 1024)
|
||||
mode = pygame.display.set_mode(SIZE, 1)
|
||||
pygame.display.set_caption("weather clock")
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
|
||||
def game_loop():
|
||||
panel_load = None
|
||||
parent = None
|
||||
|
||||
while True:
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_q:
|
||||
pygame.quit()
|
||||
quit()
|
||||
if event.key == pygame.K_r:
|
||||
wxget.update_weather(True)
|
||||
countdown.update_events(True)
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
quit()
|
||||
|
||||
panel_time = os.stat(CONFIG_PATH).st_mtime_ns
|
||||
if panel_time != panel_load:
|
||||
parent = panel.Panel(SIZE, children=panel.load(CONFIG_PATH))
|
||||
panel_load = panel_time
|
||||
|
||||
wxget.update_weather()
|
||||
mode.fill((0, 0, 0))
|
||||
mode.blit(parent.surf, (0, 0))
|
||||
pygame.display.update()
|
||||
|
||||
clock.tick(8)
|
||||
|
||||
# weather = wxget.__weather
|
||||
#
|
||||
# if iconName != weather['current_conditions']['icon']:
|
||||
# iconName = str(int(weather['current_conditions']['icon']))
|
||||
# icon = pygame.image.load('res/png/' + iconName + '.png')
|
||||
#
|
||||
# temp = '{0[current_conditions][temperature]}\u00b0{0[units][temperature]}'.format(wxget.get_weather())
|
||||
# temp = font60.render(temp, True, WHITE)
|
||||
# feels_like = 'Feels like ' + weather['current_conditions']['feels_like']
|
||||
# feels_like = font45.render(feels_like, True, GRAY)
|
||||
# lastupdate = Date(weather['current_conditions']['last_updated']).format('Last updated %I:%M')
|
||||
# lastupdate = font30.render(lastupdate, True, GRAY)
|
||||
#
|
||||
# status = join_horizontal(icon, join_vertical(temp, feels_like, 10, TOP_LEFT, BOTTOM_LEFT), 0)
|
||||
# status = join_vertical(status, lastupdate, 10)
|
||||
#
|
||||
# draw_surf(status, (0, -30), BOTTOM_CENTER, BOTTOM_CENTER)
|
||||
#
|
||||
# now = datetime.now()
|
||||
# time = now.strftime('%I:%M')
|
||||
# time = font360.render(time, True, WHITE)
|
||||
# date = now.strftime('%A, %B %d')
|
||||
# date = font60.render(date, True, GRAY)
|
||||
#
|
||||
# time = join_vertical(time, date, -100)
|
||||
#
|
||||
# draw_surf(time, ZERO, CENTER, (0.5, 0.4))
|
||||
#
|
||||
# event_surfs = []
|
||||
# events = countdown.events
|
||||
#
|
||||
# for e in events:
|
||||
# elbl = font45.render(e.label, True, WHITE)
|
||||
# etime = font30.render(format(e, '{days}d {hours}h {minutes}m'), True, GRAY)
|
||||
# event = join_vertical(elbl, etime, 5)
|
||||
# event_surfs.append(event)
|
||||
#
|
||||
# timer = pygame.Surface((0, 0))
|
||||
# max_w = max((e.get_width() for e in event_surfs))
|
||||
# for es in event_surfs:
|
||||
# timer = join_horizontal(timer, join_vertical(es, pygame.Surface((max_w, 1)), -1), 15)
|
||||
#
|
||||
# draw_surf(timer, ZERO, TOP_CENTER, TOP_CENTER)
|
||||
#
|
||||
# bells.play_chime(now.hour, now.minute)
|
||||
|
||||
|
||||
game_loop()
|
||||
36
wxget.py
Executable file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/python3
|
||||
from datetime import datetime
|
||||
|
||||
import pywapi
|
||||
import timestring
|
||||
|
||||
LOCATION = '28223'
|
||||
UNITS = 'imperial'
|
||||
|
||||
UPDATE_INTERVAL = 60 * 20
|
||||
|
||||
__weather = {}
|
||||
|
||||
|
||||
def update_weather(force=False):
|
||||
global __weather
|
||||
now = datetime.now()
|
||||
last_check = timestring.Date(__weather.get('current_conditions', {}).get('last_checked', now)).date
|
||||
|
||||
interval = (now - last_check).total_seconds()
|
||||
|
||||
if force or interval <= 0 or interval > UPDATE_INTERVAL:
|
||||
__weather = pywapi.get_weather_from_weather_com(LOCATION, UNITS)
|
||||
__weather.setdefault('current_conditions', {}).setdefault('last_checked', str(now))
|
||||
print('updated weather at', now)
|
||||
|
||||
|
||||
def get_weather(force_update=False):
|
||||
update_weather(force_update)
|
||||
|
||||
return __weather
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
while True:
|
||||
print('{0[current_conditions][temperature]}\u00b0{0[units][temperature]}'.format(get_weather()))
|
||||