Git Product home page Git Product logo

hometime's Introduction

๐Ÿ‘‹ A place where VEEB Projects shares some things.

Also, have a look at our:

or chat to us in real time on:

  • IRC (#veebprojects on irc.libera.chat)

hometime's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

hometime's Issues

False Working Hours

Occasionally I get a "False" reading to the working hours/working variable and the display won't show anything. My understanding was that when connected to the google calendar API that the working hours are set by the events on the calendar rather than the set hours in the config or clockin/out times so I'm not understanding how events could be outside working hours in that case. I did make sure the clockin/out times in the config file were definitely before / after any calendar events, and the current time is within the working hours set by the events. I've tried to debug, but I can't quite seem to find the issue. Any ideas would be much appreciated!

Code problems

I think the latest fix has some issues with indentation :

    wdt = machine.WDT(timeout=8000)  # enable watchdog timer with a timeout of 8s
    while True:
while True:

Also i saw you removed some parameters from the "hourtoindex" function, but not everywhere, i thik that might also be an issue
index = hourtoindex(hour, clockin, clockout)

How to add API Key on google calendar

Hi there. Fist of all i like your project it looks great! I've already replicated part of it:)
But for the part of the integration with Google Calendar API i'm having some issues.
Now that the code has migrated from OAUTH and a local server to directly accessing the Google Calendar API i can't get it working because in My Google Calendar API / Credentials section i only have two options: OAuth 2.0 Client IDs and Service Accounts.

Is this a coutry based limitation, or maybe i'm not looking in the right section of the configuration?

thanks!

Events are not displayed on the bar

The events are not beeing displayed on the bar.
I think the calendar is correctly integrated because the start and end times are adopted.
I don't know if it is an mistake on my end or in the code. Please let me know if you have any idea how to ficsit.

Calendar:
image

config.py:

CALENDAR = "###############################################@group.calendar.google.com"
APIKEY = "##############################"
TIMEZONE = "Europe/Berlin"
# Lighting
PIXELS = 240
GPIOPIN = 15
BARCOL = (0, 20, 0)
EVENTCOL = (0, 20, 20)      # list of tuples used as meeting colours
FLIP = False                # Flip display (set to True if the strip runs from right to left)
GOOGLECALBOOL = True        # Boolean for whether to check google calendar page
IGNORE_HARDCODED = True     # Set to True if you want Clock in at the start of first meeting and Clockout at end of last meeting
SCHEDULE = {                # This doesn't get used if IGNORE_HARDCODED is True. Othewise, it's the working hours for the week
    "monday": [
      {
        "clockin": "0",
        "clockout": "0"
      }
    ],
    "tuesday": [
      {
        "clockin": "0",
        "clockout": "0"
      }
    ],
    "wednesday": [
      {
        "clockin": "0",
        "clockout": "0"
      }
    ],
    "thursday": [
      {
        "clockin": "0",
        "clockout": "0"
      }
    ],
    "friday": [
      {
        "clockin": "0",
        "clockout": "0"
      }
    ],
    "saturday": [
      {
        "clockin": "0",
        "clockout": "0"
      }
    ],
    "sunday": [
      {
        "clockin": "0",
        "clockout": "0"
      }
    ]
}

main.py:

"""
    Progress Bar. Takes a pico W and a light strip to make a physical progress bar.
    PoC, fok and make it better
    
     Copyright (C) 2023 Veeb Projects https://veeb.ch

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>
"""

from phew import access_point, connect_to_wifi, is_connected_to_wifi, dns, server
from phew.template import render_template
import machine
import _thread
import utime
import time
import network
import config
import urequests
import neopixel
import math
import os
import json


# Time with daylight savings time and time zone factored in, edit this to fit where you are
worldtimeurl = "https://timeapi.io/api/TimeZone/zone?timezone=" + config.TIMEZONE
# The ID of the public Google Calendar to be used
calendar = config.CALENDAR
# The API key for google... Not sure why it is needed, but it seems to be
api_key = config.APIKEY
n = config.PIXELS           # Number of pixels on strip
p = config.GPIOPIN          # GPIO pin that data line of lights is connected to
barcolor = config.BARCOL    # RGB for bar color
eventcollist = config.EVENTCOL# RGB for event color
schedule = config.SCHEDULE  # Working hours in config file (only used if google calendar not used)
flip = config.FLIP
googlecalbool = config.GOOGLECALBOOL
led = machine.Pin("LED", machine.Pin.OUT)
led.off()
led.on()
time.sleep(1)
eventbool = False # Initialising, no need to edit
checkevery = 10   # Number of cycles before refreshing schedule/clocking times
AP_NAME = "pi pico"
AP_DOMAIN = "pipico.net"
AP_TEMPLATE_PATH = "ap_templates"
WIFI_FILE = "wifi.json"


def machine_reset():
    utime.sleep(1)
    print("Resetting...")
    machine.reset()

def get_today_appointment_times(calendar_id, api_key, tz):
    # Get the date from the RTC
    rtc = machine.RTC()
    year, month, day, _, hour, minute, _, _ = rtc.datetime()

    # Format the date
    date = "{:04d}-{:02d}-{:02d}".format(year, month, day)

    # Format the request URL
    url = f"https://www.googleapis.com/calendar/v3/calendars/{calendar_id}/events"
    url += f"?timeMin={date}T00:00:00Z&timeMax={date}T23:59:59Z&timeZone={tz}&key={api_key}"

    # Send the request
    response = urequests.get(url)
    data = response.json()
    # Extract the appointment times
    appointment_times = []
    for item in data.get("items", []):
         if item["status"] == "cancelled":
             continue
         start = item["start"].get("dateTime", item["start"].get("date"))
         appointment_times.append(start)
         start = item["end"].get("dateTime", item["end"].get("date"))
         appointment_times.append(start)
    print(appointment_times)
    return appointment_times


def whatday(weekday):
    dayindex = int(weekday)
    nameofday = [
                    'monday',
                    'tuesday',
                    'wednesday',
                    'thursday',
                    'friday',
                    'saturday',
                    'sunday']
    day = nameofday[dayindex]
    return day


def set_time(worldtimeurl):
        print('Grab time:',worldtimeurl)
        response = urequests.get(worldtimeurl) 
        # parse JSON
        parsed = response.json()
        datetime_str = str(parsed["currentLocalTime"])
        year = int(datetime_str[0:4])
        month = int(datetime_str[5:7])
        day = int(datetime_str[8:10])
        hour = int(datetime_str[11:13])
        minute = int(datetime_str[14:16])
        second = int(datetime_str[17:19])
        offset = int(parsed["currentUtcOffset"]["seconds"])/3600
        # update internal RTC
        machine.RTC().datetime((year,
                      month,
                      day,
                      0,
                      hour,
                      minute,
                      second,
                      0))
        dow = time.localtime()[6]
        return dow,offset
    

def bar(np, upto, clockin, clockout):
    barupto = hourtoindex(upto, clockin, clockout)
    for i in range(barupto):
        np[i] = barcolor
        

def flipit(np,n):
    temp=[0]*n
    for i in range(n):
        temp[i]=np[i]
    for i in range(n):
        np[i]=temp[n-1-i]
    return np


def timetohour(time_string):

    # Extract the time portion from the string
    if time_string.count('-') == 2:
        time_part = time_string.split("T")[1].split("+")[0]
    else:
        time_part = time_string.split("T")[1].split("-")[0]
    # Split the time into hours, minutes, and seconds
    hours, minutes, seconds = time_part.split(":")

    parsed_time = int(hours)+int(minutes)/60+int(seconds)/3600

    return parsed_time


def addevents(np, response, clockin, clockout):
    indexes = []
    for x in response:
        hour = timetohour(x)
        index = hourtoindex(hour, clockin, clockout)
        if valid(index):
            indexes.append(index)
    #pop out pairs of values and paint in meetings
    try:
        index = 0
        while True:
            end = indexes.pop()
            start= indexes.pop()
            for i in range(start,end):
                if valid(i):
                    np[i] = eventcollist[index % len(eventcollist)]
            index = (index + 1) 
    except:
        pass
        
    

def valid(index):
    valid = False
    if index <= n and index >= 0:
        valid = True
    return valid


def off(np):
    print('Turn off all LEDs')
    for i in range(n):
        np[i] = (0, 0, 0)
        np.write()

def hourtoindex(hoursin, clockin, clockout):
    index = int(math.floor(n*(hoursin - clockin)/(clockout-clockin)))
    if index < 0 or index > n:
        index = -1
    return index


def eventnow(hoursin, response):
    event = False
    for x in response:
        hour = timetohour(x)
        if abs(hour - hoursin) < 30/3600:
            event = True
    return event


def wheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if pos < 0 or pos > 255:
        r = g = b = 0
    elif pos < 85:
        r = int(pos * 3)
        g = int(255 - pos * 3)
        b = 0
    elif pos < 170:
        pos -= 85
        r = int(255 - pos * 3)
        g = 0
        b = int(pos * 3)
    else:
        pos -= 170
        r = 0
        g = int(pos * 3)
        b = int(255 - pos * 3)
    return (r, g, b)


def rainbow_cycle(np):
    print ('Rainbow!')
    for j in range(255):
        for i in range(n):
            pixel_index = (i * 256 // n) + j
            np[i] = wheel(pixel_index & 255)
        np.write()


def atwork(clockin, clockout, time):
    work = False
    if (time >= clockin) & (time <clockout):
        work = True
    return work


def breathe(np, seconds):
        n = 0
        index = 0
        sleeptime = .05
        breathespeed = .1
        cycles = seconds/sleeptime
        while index < cycles:
            val = int((255/2)*(1+math.sin(n)))
            for j in range(144):
                np[j]=(val, val , val)      # Set LED to a converted HSV value
            np.write()
            n = (n + breathespeed ) % 360
            time.sleep(sleeptime)
            index = index + 1

            

def sorted_appointments(array):
    # This is just a placeholder for when/if the google api sends garbled times
    array=sorted(array)
    return array
    

def application_mode():
    global clockin, clockout
    print("Entering application mode.")
    count = 1
    # When you plug in, update rather than wait until the stroke of the next minute
    print("Connected to WiFi")
    np = neopixel.NeoPixel(machine.Pin(p), n)
    rainbow_cycle(np)
    time.sleep(1)
    off(np)
    led.off()
    dow, offset = set_time(worldtimeurl)
    checkindex = 0
    appointment_times = []
    print('Begin endless loop')
    while True:
        try:
            # wipe led clean before adding stuff
            for i in range(n):
                np[i] = (0, 0, 0)
            eventbool = False
            checkindex = checkindex + 1
            now = time.gmtime()
            hoursin = float(now[3])+float(now[4])/60 + float(now[5])/3600  # hours into the day
            dayname = whatday(int(now[6]))
            if checkindex == 1:
                clockin = float(schedule[dayname][0]['clockin'])
                clockout = float(schedule[dayname][0]['clockout'])
                if googlecalbool is True: # overwrite clockin/clockout times if Google Calendar is to be used
                    appointment_times = []
                    clockin = 0
                    clockout = 0
                    eventbool = False
                    print('Updating from Google Calendar')
                    try:
                        appointment_times = get_today_appointment_times(calendar, api_key, config.TIMEZONE)
                        appointment_times = sorted_appointments(appointment_times)
                        print(appointment_times)
                        eventbool = eventnow(hoursin, appointment_times[::2]) # only the even elements (starttimes)
                        if config.IGNORE_HARDCODED is True:
                            clockin = timetohour(appointment_times[0])
                            clockout = timetohour(appointment_times[len(appointment_times)-1]) 
                    except:
                        print('Scheduling issues')
            working = atwork(clockin, clockout, hoursin)
            print(working, clockin, clockout, hoursin)
            if working is True:
                print('Pour yourself a cup of ambition')
                # Draw the events
                addevents(np, appointment_times, clockin, clockout)
                # Draw the bar
                bar(np, hoursin, clockin, clockout)
                if eventbool is True:
                    # If an event is starting, breathe LEDs
                    breathe(np, 30)
                else:
                    # Toggle the end led of the bar
                    count = (count + 1) % 2
                    # The value used to toggle lights
                    ledindex = min(hourtoindex(hoursin, clockin, clockout), n)
                    np[ledindex] = tuple(z*count for z in barcolor)
                    # Just the tip of the bar
                if abs(hoursin - clockout) < 10/3600: # If we're within 10 seconds of clockout reset
                    machine.reset()
                if flip == True:
                    np = flipit(np,n)
                    print('Flipped')
            # reset the google check index if needed
            if (checkindex > checkevery):
                checkindex = 0
            np.write()
            time.sleep(1)
        except Exception as e:
            print('Exception:',e)
            off(np)
            time.sleep(1)
            machine.reset()
        except KeyboardInterrupt:
            off(np)


def setup_mode():
    print("Entering setup mode...")

    def ap_index(request):
        if request.headers.get("host") != AP_DOMAIN:
            return render_template(f"{AP_TEMPLATE_PATH}/redirect.html", domain=AP_DOMAIN)

        return render_template(f"{AP_TEMPLATE_PATH}/index.html")

    def ap_configure(request):
        print("Saving wifi credentials...")

        with open(WIFI_FILE, "w") as f:
            json.dump(request.form, f)
            f.close()

        # Reboot from new thread after we have responded to the user.
        _thread.start_new_thread(machine_reset, ())
        return render_template(f"{AP_TEMPLATE_PATH}/configured.html", ssid=request.form["ssid"])

    def ap_catch_all(request):
        if request.headers.get("host") != AP_DOMAIN:
            return render_template(f"{AP_TEMPLATE_PATH}/redirect.html", domain=AP_DOMAIN)

        return "Not found.", 404

    server.add_route("/", handler=ap_index, methods=["GET"])
    server.add_route("/configure", handler=ap_configure, methods=["POST"])
    server.set_callback(ap_catch_all)

    ap = access_point(AP_NAME)
    ip = ap.ifconfig()[0]
    dns.run_catchall(ip)
    server.run()

# Main Logic

# Figure out which mode to start up in...
try:
    os.stat(WIFI_FILE)

    # File was found, attempt to connect to wifi...
    with open(WIFI_FILE) as f:
        wifi_credentials = json.load(f)
        ip_address = connect_to_wifi(wifi_credentials["ssid"], wifi_credentials["password"])

        if not is_connected_to_wifi():
            # Bad configuration, delete the credentials file, reboot
            # into setup mode to get new credentials from the user.
            print("Bad wifi connection!")
            print(wifi_credentials)
            os.remove(WIFI_FILE)
            machine_reset()

        print(f"Connected to wifi, IP address {ip_address}")
        application_mode()  # Contains all the progress bar code

except Exception:
    # Either no wifi configuration file found, or something went wrong,
    # so go into setup mode.
    setup_mode()

Hometime

Is it possible to make the day longer for a spesific time in the calendar, because school doesnt end always at 13:00

Improvement for WIFI credentials

I want to to an improvement with setting up WIFI credentials
If a pushbutton is pressed the board could enter in AP mode and offer a simple page where WIFI credentials are set, then getback on normal mode

What do you think about it? I could try writing the code :)

Event date parsing gives error for zones west of Z

Awesome project!

One problem I noted was that on line 115 in timetohour(time_string):

# Extract the time portion from the string time_part = time_string.split("T")[1].split("+")[0]

gives an error because my time zone is - not + from Z:

Connected to WiFi Turn off all LEDs Grab time: https://timeapi.io/api/TimeZone/zone?timeZone=America/Vancouver (2023, 5, 16, 21, 43, 13, 1, 136) Begin endless loop https://www.googleapis.com/calendar/v3/calendars/mycalendarurl%40group.calendar.google.com/events?timeMin=2023-05-16T00:00:00-07:00&timeMax=2023-05-16T23:59:59-07:00&key=MyKeyGoesHere ['2023-05-16T22:00:00-07:00', '2023-05-16T22:45:00-07:00', '2023-05-16T21:15:00-07:00', '2023-05-16T22:00:00-07:00'] too many values to unpack (expected 3) Turn off all LEDs

So I changed the "+" to a "-" in the time_part calculation, and it no longer errored-out. I realize Micropython doesn't have the full datetime, and your elegant workaround might need some tweaking or documenting.

One other thing is that the get_today_appointment_times function (line 45) uses Z rather than local times, so my -07:00 from Z would often omit events and offset the ones that still fell within the workday window:

url = f"https://www.googleapis.com/calendar/v3/calendars/{calendar_id}/events" url += f"?timeMin={date}T00:00:00Z&timeMax={date}T23:59:59Z&key={api_key}"

Again, with no datetime, it makes dealing with time zones a pain. My workaround was to change the Z to my Z offset:

url = f"https://www.googleapis.com/calendar/v3/calendars/{calendar_id}/events" url += f"?timeMin={date}T00:00:00-07:00&timeMax={date}T23:59:59-07:00&key={api_key}"

But that's cheating!

Thanks for posting such great ideas - my 9-year-old is building sploosh for her school's hydroponics lab.

Question about configuring the Google Calendar integration

So if i understand correct for the Google Calendar intergration to work one needs to have:

  • an event at the begining of the day
  • an event at the end of the day
  • zero or more events between ?

Have i understood correct? I am asking because i am want to write an instructable (tutoral) for the project

Google Calendar - "Scheduling Issues"

Hello! I REALLY want to make this project work, but I am struggling a bit with the google calendar. I was able to do the OAuth credentials, I have the GCal API Key, I see that it functions without errors once its pulled with my code, but the light isn't showing the progress bar/events. The WIFI connection is good, the lights/connections are fine as they show the rainbow initially, but then once it pulls events (which it prints), the light goes dark. I checked the time zone and that is ok as well. Calendar is public. It just prints the following:

pdating from Google Calendar https://www.googleapis.com/calendar/v3/calendars/[email protected]/events?timeMin=2023-06-03T00:00:00Z&timeMax=2023-06-03T23:59:59Z&timeZone=America/Los_Angeles&key=*** ['2023-06-03T12:00:00-07:00', '2023-06-03T12:30:00-07:00', '2023-06-03T13:00:00-07:00', '2023-06-03T14:00:00-07:00', '2023-06-03T14:30:00-07:00', '2023-06-03T15:30:00-07:00', '2023-06-03T16:00:00-07:00', '2023-06-03T17:00:00-07:00'] Scheduling issues appointment_times: ['2023-06-03T12:00:00-07:00', '2023-06-03T12:30:00-07:00', '2023-06-03T13:00:00-07:00', '2023-06-03T14:00:00-07:00', '2023-06-03T14:30:00-07:00', '2023-06-03T15:30:00-07:00', '2023-06-03T16:00:00-07:00', '2023-06-03T17:00:00-07:00'] Scheduling issues appointment_times: [] Scheduling issues appointment_times: [] Scheduling issues appointment_times: [] Scheduling issues

Any help would be much appreciated!

Bar not working when Flip is true

I have tested the bar with Flip = True in config.py and it does not work

Logs:

MicroPython v1.20.0 on 2023-04-26; Raspberry Pi Pico W with RP2040
Type "help()" for more information.

%Run -c $EDITOR_CONTENT
2023-06-30 08:34:58 [debug / 153kB] - got ip address
Connected to wifi, IP address 192.168.1.110
Entering application mode.
Rainbow!
Connected to WiFi
Turn off all LEDs
Grab time: https://timeapi.io/api/TimeZone/zone?timezone=Europe/Bucharest
Begin endless loop
Updating from Google Calendar
['2023-06-30T08:00:00+03:00', '2023-06-30T08:15:00+03:00', '2023-06-30T19:00:00+03:00', '2023-06-30T19:15:00+03:00']
['2023-06-30T08:00:00+03:00', '2023-06-30T08:15:00+03:00', '2023-06-30T19:00:00+03:00', '2023-06-30T19:15:00+03:00']
clockin: 8.0
Pour yourself a cup of ambition
Exception: bytearray index out of range
Turn off all LEDs

Connection lost (device reports readiness to read but returned no data (device disconnected or multiple access on port?))

Use Stop/Restart to reconnect.

Logs when its working (but with flip=False):

MicroPython v1.20.0 on 2023-04-26; Raspberry Pi Pico W with RP2040
Type "help()" for more information.

%Run -c $EDITOR_CONTENT
2023-06-28 11:38:47 [debug / 150kB] - got ip address
Connected to wifi, IP address 192.168.1.110
Entering application mode.
Rainbow!
Connected to WiFi
Turn off all LEDs
Grab time: https://timeapi.io/api/TimeZone/zone?timezone=Europe/Bucharest
Begin endless loop
Updating from Google Calendar
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00']
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
Updating from Google Calendar
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00']
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5
['2023-06-19T08:30:00+03:00', '2023-06-19T09:30:00+03:00', '2023-06-19T21:30:00+03:00', '2023-06-19T21:35:00+03:00', '2023-06-27T21:30:00+03:00', '2023-06-27T21:45:00+03:00', '2023-06-28T08:30:00+03:00', '2023-06-28T09:00:00+03:00']
clockin: 8.5

[BUG] Events not triggert

When you use reocurring events, the eventbool doesnt get set to true, when clockout should trigger, the pico doesnt reboot and the LEDs dont turn off.

2 Colors

I think I have a good idea but I don't know how to implement it. When an Event is active, you cannot see the progress of the Event.
In my case I chose to set events in the breaks and not the Lessons.

Here is my idea:
We make a progress bar for the whole day in (0, 0, 10) and a second progress bar for the Event in (0, 10, 0). So when a Event is active, the two bars are layerd over each other. When a Pixel is used by both, it should be (0, 10, 10).
When this mode is enabled, events should not be marked on the bar, when none is active.

I hope you like this idea, just implement it when you want, no need to do this soon.
If you don't like it, close this issue.

GUI improvment

What do you think of a simple GUI for setting parameters like 9-5 intervals each day?

One way it could work would be:

  • use presses a phisical button connected to a GPIO PIN
  • the script reboots and sets the board as AP mode, you can connect to it's WIFI with a predefined password
  • the user navigates to it's IP / settings page
  • WIFI credentials are settable
  • 9-5 intervals are also settable
  • A save button is available, when pressed the board the server saves the settings, and reboots in normal operations mode

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.