HackerShackOfficial / Smart-Mirror

Raspberry powered mirror which can display news, weather, calendar events
MIT License
911 stars 384 forks source link

Make a simple module #93

Open sudo21 opened 7 years ago

sudo21 commented 7 years ago

I would like to make a module that just displays a message at the bottom of the screen. I tried to modify one of the existing modules but I am not quite sure what everything does. Any help would be greatly appreciated.

As a side note, is there any way to remove one of the modules from the display temporarily. I've made a voice control script, and I'd like to be able to pop one of the modules on screen for 1 minute before it disappears again.

bervin61 commented 6 years ago

This is my first day with this code, but I'm fairly confident in my tkinter skills. Unfortunately, HackerHouse went with pack() rather than grid(), but we can work with it. Add this right before class Clock(Frame):

class Message(Frame):
    def __init__(self, parent, *args, **kwargs):
        Frame.__init__(self, parent, bg='black')
        # initialize label
        self.messageLbl = Label(self, text="Hello World", font=('Helvetica', large_text_size), fg="white", bg="black")
        self.messageLbl .pack(side=TOP, anchor=CENTER)

Then down in class FullscreenWindow and in function init(self), add (near the bottom - after the calendar:

self.message= Message(self.topFrame)
self.news.pack(side=CENTER, anchor=S, padx=100, pady=60)

(haven't had a chance to test this yet. it should give you an idea of what it would look like though)

As for appearing/disappearing, that should be quite easy. Following the example of changing text (in Clock). If you need more help, let me know.

sudo21 commented 6 years ago

That was very helpful! Thank you. I am still having a little trouble doing what I want though. Is it possible to check a variable, then based on that variable show a module? I have this code which it ~kind of~ working. The issue is it seems to just duplicate the module every time it's called. `class FullscreenWindow:

def __init__(self):
    global the_State
    self.tk = Tk()
    self.tk.configure(background='black')
    self.topFrame = Frame(self.tk, background = 'black')
    self.bottomFrame = Frame(self.tk, background = 'black')
    self.topFrame.pack(side = TOP, fill=BOTH, expand = YES)
    self.bottomFrame.pack(side = BOTTOM, fill=BOTH, expand = YES)
    self.state = False
    self.tk.bind("<Return>", self.toggle_fullscreen)
    self.tk.bind("<Escape>", self.end_fullscreen)
    self.updateSc()

def updateSc(self):
    if the_State == "msg":
        self.message= Message(self.bottomFrame)
        self.message.pack(side=LEFT, anchor=S, padx=100, pady=60)
        self.message.after(9000, lambda: self.message.destroy())
    if the_State == "clock":
        self.clock = Clock(self.topFrame)
        self.clock.pack(side=RIGHT, anchor=N, padx=100, pady=60)
        self.clock.after(9000, lambda: self.clock.destroy())

    self.tk.after(1000, self.updateSc)`

I don't know how else to go about this. Thank you!

bervin61 commented 6 years ago

It's a little hacky, but it works. Modify as needed. I've bound the_State to the Tab key. Not sure how you wanted to update it.

from Tkinter import *
import locale
import threading
import time

from PIL import Image, ImageTk
from contextlib import contextmanager

LOCALE_LOCK = threading.Lock()

global the_State
the_State=0

ui_locale = '' # e.g. 'fr_FR' fro French, '' as default
time_format = 12 # 12 or 24
date_format = "%b %d, %Y" # check python doc for strftime() for options
xlarge_text_size = 94
large_text_size = 48
medium_text_size = 28
small_text_size = 18

@contextmanager
def setlocale(name): #thread proof function to work with locale
    with LOCALE_LOCK:
        saved = locale.setlocale(locale.LC_ALL)
        try:
            yield locale.setlocale(locale.LC_ALL, name)
        finally:
            locale.setlocale(locale.LC_ALL, saved)

class Clock(Frame):
    def __init__(self, parent, *args, **kwargs):
        Frame.__init__(self, parent, bg='black')
        # initialize time label
        self.time1 = ''
        self.timeLbl = Label(self, font=('Helvetica', large_text_size), fg="white", bg="black")
        # initialize day of week
        self.day_of_week1 = ''
        self.dayOWLbl = Label(self, text=self.day_of_week1, font=('Helvetica', small_text_size), fg="white", bg="black")
        # initialize date label
        self.date1 = ''
        self.dateLbl = Label(self, text=self.date1, font=('Helvetica', small_text_size), fg="white", bg="black")

        self.message = 'Hello World'
        self.msgLbl = Label(self, text=self.message, font=('Helvetica', small_text_size), fg="white", bg="black")
        self.tick()

    def rePack(self):
        global the_State
        self.msgLbl.pack_forget()
        self.timeLbl.pack(side=TOP, anchor=E)
        self.dayOWLbl.pack(side=TOP, anchor=E)
        self.dateLbl.pack(side=TOP, anchor=E)
        the_State=0

    def tick(self):
        global the_State

        self.timeLbl.pack(side=TOP, anchor=E)
        self.dayOWLbl.pack(side=TOP, anchor=E)
        self.dateLbl.pack(side=TOP, anchor=E)

        if the_State==1:
            self.timeLbl.pack_forget()
            self.dayOWLbl.pack_forget()
            self.dateLbl.pack_forget()

            self.msgLbl.pack(side=LEFT, anchor=S, padx=100, pady=60)
            self.msgLbl.after(500, lambda:self.rePack())         

        with setlocale(ui_locale):
            if time_format == 12:
                time2 = time.strftime('%I:%M %p') #hour in 12h format
            else:
                time2 = time.strftime('%H:%M') #hour in 24h format

            day_of_week2 = time.strftime('%A')
            date2 = time.strftime(date_format)
            # if time string has changed, update it

            if time2 != self.time1:
                self.time1 = time2
                self.timeLbl.config(text=time2)
            if day_of_week2 != self.day_of_week1:
                self.day_of_week1 = day_of_week2
                self.dayOWLbl.config(text=day_of_week2)
            if date2 != self.date1:
                self.date1 = date2
                self.dateLbl.config(text=date2)
            # calls itself every 200 milliseconds
            # to update the time display as needed
            # could use >200 ms, but display gets jerky
            self.timeLbl.after(200, self.tick)

class FullscreenWindow:

    def __init__(self):
        self.tk = Tk()
        self.tk.configure(background='black')
        self.topFrame = Frame(self.tk, background = 'black')
        self.bottomFrame = Frame(self.tk, background = 'black')
        self.topFrame.pack(side = TOP, fill=BOTH, expand = YES)
        self.bottomFrame.pack(side = BOTTOM, fill=BOTH, expand = YES)
        self.state = False
        self.tk.bind("<Return>", self.toggle_fullscreen)
        self.tk.bind("<Escape>", self.end_fullscreen)
        self.tk.bind("<Tab>",changeState)
        # clock
        self.clock = Clock(self.topFrame)
        self.clock.pack(side=RIGHT, anchor=N, padx=100, pady=60)

    def changeState():
        global the_State
        the_State=1

    def toggle_fullscreen(self, event=None):
        self.state = not self.state  # Just toggling the boolean
        self.tk.attributes("-fullscreen", self.state)
        return "break"

    def end_fullscreen(self, event=None):
        self.state = False
        self.tk.attributes("-fullscreen", False)
        return "break"

if __name__ == '__main__':
    w = FullscreenWindow()
    w.tk.mainloop()
sudo21 commented 6 years ago

Thank you so much! I'll try it soon.