MicroPython, Error running script in REPL

I wrote a script to communicate with the RTC. When I run the script via Thonny, it works fine.

When I call the script via REPL (run(“rtc_en.py”)), I get the error message: “An error occurred: name ‘rtime_ds’ isn’t defined.”

Does anyone have any suggestions as to where the error might be?


from machine import I2C, Pin, RTC
import time
import utime

class DS3231:
    def __init__(self, i2c, address=0x68):
        self.i2c = i2c
        self.addr = address

    def _bcd2dec(self, bcd):
        return (bcd // 16) * 10 + (bcd % 16)

    def _dec2bcd(self, dec):
        return (dec // 10) * 16 + (dec % 10)

    def datetime(self, dt=None):
        if dt is None:
            data = self.i2c.readfrom_mem(self.addr, 0x00, 7)
            second = self._bcd2dec(data[0] & 0x7F)
            minute = self._bcd2dec(data[1])
            hour = self._bcd2dec(data[2])
            weekday = self._bcd2dec(data[3])
            day = self._bcd2dec(data[4])
            month = self._bcd2dec(data[5] & 0x1F)
            year = self._bcd2dec(data[6]) + 2000
            return (year, month, day, weekday, hour, minute, second, 0)
        else:
            year, month, day, weekday, hour, minute, second = dt[:7]
            year -= 2000
            data = bytearray([
                self._dec2bcd(second),
                self._dec2bcd(minute),
                self._dec2bcd(hour),
                self._dec2bcd(weekday),
                self._dec2bcd(day),
                self._dec2bcd(month),
                self._dec2bcd(year)
            ])
            self.i2c.writeto_mem(self.addr, 0x00, data)

    def temperature(self):
        data = self.i2c.readfrom_mem(self.addr, 0x11, 2)
        msb = data[0]
        lsb = data[1] >> 6  # only top two bits
        temp = msb + (0.25 * lsb)
        # DS3231 encodes temperature as a 10-bit signed value
        if msb & 0x80:  # negative value
            temp -= 256
        return temp

# Initialize I2C1 (SDA = GPIO6, SCL = GPIO7)
i2c = I2C(1, scl=Pin(7), sda=Pin(6))
rtime_ds = DS3231(i2c)
rtc_internal = RTC()

def show_menu():
    print("\n===== DS3231 Menu =====")
    print("1 - Show date and time")
    print("2 - Show temperature")
    print("3 - Set date and time")
    print("4 - Sync DS3231 → internal RTC")
    print("q - Quit")
    print("========================")

def print_datetime():
    dt = rtime_ds.datetime()
    print("Date: {:04d}-{:02d}-{:02d}".format(dt[0], dt[1], dt[2]))
    print("Time: {:02d}:{:02d}:{:02d}".format(dt[4], dt[5], dt[6]))

def print_temperature():
    temp = rtime_ds.temperature()
    print("Temperature: {:.2f} °C".format(temp))

def set_datetime():
    try:
        input_str = input("Enter new date and time (Format: YYYY-MM-DD HH:MM:SS): ")
        date_str, time_str = input_str.strip().split(" ")
        year, month, day = [int(x) for x in date_str.split("-")]
        hour, minute, second = [int(x) for x in time_str.split(":")]

        # Calculate weekday (Monday=1 ... Sunday=7)
        weekday = utime.localtime(utime.mktime((year, month, day, hour, minute, second, 0, 0)))[6] + 1

        # Set DS3231 time
        rtime_ds.datetime((year, month, day, weekday, hour, minute, second))
        print("Time successfully set on DS3231.")

        # Also update internal RTC
        rtc_internal.datetime((year, month, day, weekday, hour, minute, second, 0))
        print("Internal RTC updated as well.")

    except Exception as e:
        print("Invalid input! Please follow the format.")
        print("Details:", e)

def sync_to_internal_rtc():
    try:
        dt = rtime_ds.datetime()
        rtc_internal.datetime(dt)
        print("Internal RTC synchronized with DS3231.")
    except Exception as e:
        print("Error during synchronization:", e)

# Main loop
while True:
    show_menu()
    choice = input("Your choice: ").strip()

    if choice == "1":
        print_datetime()
    elif choice == "2":
        print_temperature()
    elif choice == "3":
        set_datetime()
    elif choice == "4":
        sync_to_internal_rtc()
    elif choice.lower() == "q":
        print("Program exited.")
        break
    else:
        print("Invalid selection. Please enter 1, 2, 3, 4 or q.")

show us your run() function

you probably need exec(..., globals())

or just import it

1 Like

I use the run() function from picocalc_system.py

def run(filename):
    """
    Simple run utility.
    Attempts to run python file provided by filename, returns when done.
    
    Inputs: python file filename/filepath 
    Outputs: None, runs file
    """
    try:
        exec(open(filename).read())
    except OSError:
        print(f"Failed to open file: {filename}")
    except Exception as e:
        print(f"An error occurred: {e}")
    return

If I run it directly via exec(open(…)) it works. Thank you man.

1 Like

I found that it is (may be?) better to use:

exec(open(…), {}, {})

This prevents the current environment from leaking into the running script, unless you want that.

1 Like