More Clever Night Light in Kivy
FleetingFollowing more clever night light, but using my a python runtime on android, so that I can use it when travelling.
import os
from datetime import datetime, timedelta
import math
import time
import requests
from kivy.app import App
from kivy.clock import Clock
from kivy.graphics import Color, Rectangle
from kivy.properties import BooleanProperty, NumericProperty, StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.spinner import Spinner
from plyer import orientation
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.progressbar import ProgressBar
from kivy.uix.screenmanager import Screen, ScreenManager, ScreenManagerException
from kivy.core.audio import SoundLoader
from helpers.osc import oschandler, to_service
from helpers.wakelock import WakeLock
from helpers.notify import notify
from android.runnable import run_on_ui_thread
from logging import getLogger
from kivy.lang import Builder
logger = getLogger(__name__)
pink = (1, 0.75, 0.8)
orange = (1, 0.5, 0)
cyan = (0, 1, 1)
white = (1, 1, 1)
class SettingsScreen(Screen):
steps = NumericProperty(4)
step_time = NumericProperty(20)
rest_time = NumericProperty(10)
total_time = StringProperty("Total: 0s")
def _update_rect(self, instance, value):
self.rect.pos = instance.pos
self.rect.size = instance.size
def __init__(self, **kwargs):
super(SettingsScreen, self).__init__(**kwargs)
with self.canvas.before:
self.color = Color(1, 1, 1, 1)
self.rect = Rectangle(size=self.size, pos=self.pos)
self.bind(size=self._update_rect, pos=self._update_rect)
layout = BoxLayout(orientation='vertical')
self.add_widget(layout)
almost_layout = BoxLayout(size_hint=(1, 0.15))
layout.add_widget(almost_layout)
almost_layout.add_widget(
Label(text="Almost", color=(0, 0, 0, 1))
)
self.almost_hour = Spinner(
text="7",
values=[str(i) for i in range(0, 24)], # numbers 0 to 100
size_hint=(None, None),
size=(200, 44),
pos_hint={'center_x': .5, 'center_y': .5}
)
almost_layout.add_widget(self.almost_hour)
self.almost_minute = Spinner(
text='30',
values=[str(i) for i in range(0, 60)], # numbers 0 to 100
size_hint=(None, None),
size=(200, 44),
pos_hint={'center_x': .5, 'center_y': .5}
)
almost_layout.add_widget(self.almost_minute)
day_layout = BoxLayout(size_hint=(1, 0.15))
layout.add_widget(day_layout)
day_layout.add_widget(
Label(text="Day", color=(0, 0, 0, 1))
)
self.day_hour = Spinner(
text="8",
values=[str(i) for i in range(0, 24)], # numbers 0 to 100
size_hint=(None, None),
size=(200, 44),
pos_hint={'center_x': .5, 'center_y': .5}
)
day_layout.add_widget(self.day_hour)
self.day_minute = Spinner(
text='0',
values=[str(i) for i in range(0, 60)], # numbers 0 to 100
size_hint=(None, None),
size=(200, 44),
pos_hint={'center_x': .5, 'center_y': .5}
)
day_layout.add_widget(self.day_minute)
self.go_button = Button(text="Go !!!",
background_color=(0, 0, 1, 1),
color=(1, 1, 1, 1),
size_hint=(1, 0.15), disabled=True)
self.go_button.bind(on_press=self.start)
layout.add_widget(self.go_button)
@oschandler("service:ready")
def _(_):
self.go_button.disabled = False
def start(self, *_):
app = App.get_running_app()
app.goto("nightlight:normal")
normal = app.sm.get_screen('nightlight:normal')
normal.almost_hour = int(self.almost_hour.text)
normal.almost_minute = int(self.almost_minute.text)
normal.day_hour = int(self.day_hour.text)
normal.day_minute = int(self.day_minute.text)
normal.start()
class NormalScreen(Screen):
def _update_rect(self, instance, value):
self.rect.pos = instance.pos
self.rect.size = instance.size
def __init__(self, **kwargs):
super(NormalScreen, self).__init__(**kwargs)
self.remaining_time = None
self.almost_hour = 13
self.almost_minute=37
self.day_hour = 13
self.day_minute=39
with self.canvas.before:
self.color = Color(0, 0, 0, 1)
self.rect = Rectangle(size=self.size, pos=self.pos)
self.bind(size=self._update_rect, pos=self._update_rect)
layout = BoxLayout(orientation='vertical')
self.add_widget(layout)
current_layout = BoxLayout(size_hint=(1, 0.15))
layout.add_widget(current_layout)
self.current_hour = Label(
text="7",
font_size="50sp",
)
current_layout.add_widget(self.current_hour)
self.sep = Label(
text=":",
font_size="50sp",
)
current_layout.add_widget(self.sep)
self.current_minute = Label(
text='30',
font_size="50sp",
)
current_layout.add_widget(self.current_minute)
self.keepon = WakeLock("nightlight:keepon", wakeup=False, partial=True)
self.wakeup = WakeLock("nightlight:wakeup", wakeup=True, partial=False)
self.keepon.acquire()
self.update_display()
@oschandler("clockwake:done:nightlight:almost")
def _(_):
self.almost()
@oschandler("clockwake:done:nightlight:day")
def _(_):
self.day()
self.bind(on_pre_enter=self.pre_enter_handler)
def pre_enter_handler(self, _):
# from plyer import orientation
# orientation.set_landscape()
from jnius import autoclass
from android import mActivity
View = autoclass('android.view.View')
option = View.SYSTEM_UI_FLAG_FULLSCREEN
from android.runnable import run_on_ui_thread
@run_on_ui_thread
def fs():
logger.debug("Entering fullscreen mode")
mActivity.getWindow().getDecorView().setSystemUiVisibility(option)
fs()
def update_display(self, *_):
now = datetime.now()
self.current_hour.text = str(now.hour).zfill(2)
self.current_minute.text = str(now.minute).zfill(2)
Clock.schedule_once(self.update_display, 61 - now.second)
def start(self):
now = datetime.now()
new_date = now.replace(hour=self.almost_hour, minute=self.almost_minute,second=0)
if now.hour > self.almost_hour or (now.hour == self.almost_hour and
now.minute > self.almost_minute):
new_date = new_date + timedelta(days=1)
duration = (new_date - now).total_seconds()
to_service("clockwake", {"duration": duration, "callback": "nightlight:almost"})
def almost(self, *_):
self.color.rgb = cyan
self.current_hour.color = (0,0,0, 1)
self.current_minute.color = (0,0,0, 1)
self.sep.color = (0,0,0, 1)
self.wakeup.acquire()
now = datetime.now()
new_date = now.replace(hour=self.day_hour, minute=self.day_minute,second=0)
duration = (new_date - now).total_seconds()
to_service("clockwake", {"duration": duration, "callback": "nightlight:day"})
def day(self):
self.color.rgb = white
class NightLightApp(App):
def goto(self, screen):
self.sm.current = screen
def back(self):
self.sm.current = 'nightlight:normal'
@staticmethod
def populate(sm):
try:
sm.get_screen('nightlight:normal')
return
except ScreenManagerException:
pass # not populated yet
sm.add_widget(SettingsScreen(name='nightlight:settings'))
sm.add_widget(NormalScreen(name='nightlight:normal'))
def build(self):
self.sm = ScreenManager()
self.populate(self.sm)
return self.sm
def run():
NightLightApp().run()