2

I am very inexperienced with Python so bear with me. I am trying to set a schedule in a RaspiPico to turn a RaspPi 3B+ on at given times. The RaspPi 3B+ turns itself off at the 57th minute of every hour, the Pico is supposed to turn it on at the 24th minute of every hour. I've worked out the code so that when I manually run it through Thonny, it turns the RaspPi 3B+ on and doesnt give any error messages anymore, but when left on its own it doesn't appear to be following a schedule. To clarify there is also an RTC included in this Raspi Sandwich. Here is my code:

from machine import Pin, Timer, RTC, I2C
import time
import binascii

# I2C PINSs
I2C_PORT = 0
I2C_SDA = 20
I2C_SCL = 21

# Times when the B+ should be booted up
# Format is (hours, minutes)
# For now, keep it sorted; we could do this in code, but why not just do it by hand
SCHEDULE = [(0, 24, 0), (0, 56, 0), (1, 24, 0), (1, 56, 0), (2, 24, 0), (2, 56, 0), (3, 24, 0), (3, 56, 0), (4, 24, 0), (4, 56, 0), (5, 24, 0), (5, 56, 0), (6, 24, 0), (6, 56, 0), (7, 24, 0), (7, 56, 0), (8, 24, 0), (8, 56, 0), (9, 24, 0), (9, 56, 0)
, (10, 24, 0), (10, 56, 0), (11, 24, 0), (11, 56, 0), (12, 24, 0), (12, 56, 0), (13, 24, 0), (13, 56, 0), (14, 24, 0), (14, 56, 0), (15, 24, 0), (15, 56, 0), (16, 24, 0), (16, 56, 0), (17, 24, 0), (17, 56, 0), (18, 24, 0), (18, 56, 0), (19, 24, 0), (19, 56, 0), 
(20, 24, 0), (20, 56, 0), (21, 24, 0), (21, 56, 0), (22, 24, 0), (22, 56, 0), (23, 24, 0), (23, 56, 0)]

# This function returns the next scheduled boot time
# after the hour, minute we provide
def grab_next_time(time_tuple):
    
    current_hour, current_min, current_sec = time_tuple
    
    # Go through all scheudled boot times from first to last
    for h, m, s in SCHEDULE:
        
        # If current hour is before hour, we found the next time
        if current_hour < h:
            return (h,m, s)
        
        # If its the same hour
        elif current_hour == h:
            
            # If its before the minute, we found the next time
            if current_min < m:
                return (h,m,s)
            
            # if its the same minute
            elif current_min == m:
                
                # If its before the second, we found the next time
                if current_sec < s:
                    return (h,m,s)
        
        # If the current hour is not the same or before, lets try the next
        
    # We tried all times in the schedule,
    # we're after, so lets start from the begining
    return SCHEDULE[0]

# This function returns the time we need to wait in seconds
def wait_time(current_time, next_time):
    next_hour, next_min, next_sec = next_time[0], next_time[1], next_time[2]
    current_hour, current_min, current_sec = current_time[0], current_time[1], current_time[2]

    wait_time = (next_sec - current_sec)

    if (next_sec - current_sec) < 0:
        wait_time += 60
        next_min -= 1

    wait_time += (next_min - current_min) * 60
    
    if (next_min - current_min) < 0:
        wait_time += (60 * 60)
        next_hour -= 1
    
    wait_time += (next_hour - current_hour) * 60 * 60
    
    if (next_hour - current_hour) < 0:
        wait_time += (60 * 60 * 24)

    return wait_time
    

def start_local_rtc(date=(2017, 8, 23, 2, 12, 48, 0, 0)):
    rtc = machine.RTC()
    rtc.datetime(date)
    return rtc
    
    
class ds3231(object):
    NowTime = b'\x00\x45\x13\x02\x24\x05\x21'
    w  = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
    address = 0x68
    start_reg = 0x00
    alarm1_reg = 0x07
    control_reg = 0x0e
    status_reg = 0x0f

    def __init__(self,i2c_port,i2c_scl,i2c_sda):
        self.bus = I2C(i2c_port,scl=Pin(i2c_scl),sda=Pin(i2c_sda))
    
    def read_time(self):
        t = self.bus.readfrom_mem(int(self.address),int(self.start_reg),7)
        seconds = (t[0]&0x0F) + 10 * ((t[0]>>4)&0x07)
        minutes = (t[1]&0x0F) + 10 * ((t[1]>>4)&0x07)
        hour = (t[2]&0x0F) +  20 * ((t[2]>>4)&0x02) #hour   (  11 1111)
        dow = t[3]&0x07  #week
        day = (t[4]&0x0F) + 10 * ((t[4]>>4)&0x03)  #day
        month = (t[5]&0x1F) + 10 * ((t[5]>>4)&0x01) #month
        year = 2000 + ((t[6]&0x0F) + 10 * ((t[6]>>4)&0x0F))  # year        
        
        #(year, month, day, weekday, hours, minutes, seconds, subseconds)
        return (year, month, day, hour, minutes, seconds, 0, 0)
        #print("20%x/%02x/%02x %02x:%02x:%02x %s" %(t[6],t[5],t[4],t[2],t[1],t[0],self.w[t[3]-1]))

    # For a second, override the start pin
    def start_pi():
        boot = Pin(21, Pin.OUT)
        boot.value(0)
        time.sleep(0.1) # 100 ms should do
        boot = Pin(21, Pin.IN) # Setting the pin to IN should make it float
    
if __name__ == '__main__':
    
    # On startup grab the time from the RTC
    hw_rtc = ds3231(I2C_PORT, I2C_SCL, I2C_SDA)
    time_rtc = hw_rtc.read_time()
    print(time_rtc)    
    local_rtc = start_local_rtc()
    
    # This is our infinite loop
while True:
        current_time = local_rtc.datetime()
        current_time = (current_time[4], current_time[5], current_time[6])
        print(current_time)
        next_time = grab_next_time(current_time)
        print("Next time: ", next_time)
        wait_time = wait_time(current_time, next_time)
        print("Wait time: ", wait_time)
        
        # If within 30 seconds, start the pi
        if wait_time < 30:
            start_pi()
        # If we need to wait for more than 30 seconds, keep waiting
        else:    
            time.sleep(wait_time - 5)
        

The person I am working with mentioned that the Pico will "poke" the Pi and not stop poking until the specified time. hence why my schedule is listed as "(0,24,0), (0,56,0)". In my head this is supposed to start the "poking" at the 24th minute after midnight and stop at the 56th minute. As was stated before this obviously isn't what is going on. Some help would be appreciated.

  • Sorry, just a different matter but I think it would be helpful to tell you. I think it is not difficult to simulate your idea on `wokwi` if you could find the related components. Then, people will help you quickly! https://wokwi.com/ – Mohamad Ghaith Alzin May 18 '22 at 00:25
  • I think you need to read this so it might be related! https://mpython.readthedocs.io/en/master/library/micropython/machine/machine.RTC.html https://docs.micropython.org/en/latest/library/pyb.RTC.html – Mohamad Ghaith Alzin May 18 '22 at 00:50
  • I'm not sure if I understand your problem 100%, but why don't you use a scheduler library to trigger your functions. Because of the RTC? – jpotyka May 18 '22 at 01:09
  • jpotyka, could you elaborate? – Jackson A Swan May 18 '22 at 19:36
  • My first thought was to use a scheduler library to schedule the callback function. Something like that: https://github.com/rguillon/schedule or https://github.com/DigonIO/scheduler But then I noticed that you are using a RTC. So you can not use a library to schedule because of the RTC? – jpotyka May 18 '22 at 23:03
  • I don't know what a scheduler is, nor do I know how it interacts with a RTC. I'm new to this. – Jackson A Swan May 18 '22 at 23:41
  • A scheduler is a library or software module that allows to execute a function at a target time/minute/hour/day So the user can focus on his program logic, rather then implementing the scheduler himself. Take a look at the first link I commented above. Maybe it will help you in the future. How to connect it with the RTC I can not tell you, I only program on normal PCs. – jpotyka May 19 '22 at 22:25

0 Answers0