Shop OBEX P1 Docs P2 Docs Learn Events
proj baseSta — Parallax Forums

proj baseSta

This is the start of the baseSta code. I put in the temp task just to see if it runs correctly with the RTC running also. So far it looks like no problems. Next thing I will start a logger task and see how far I get with logging the temp data with a time attached. Something like this:
sta day time temp
s0 , 01/03/24 ,12:12:24, 72.0
Not sure how I will handle the actual day heading. This will be a csv file, hopefully I will be able to use pandas and may load it to an SQLite3 database.

The next task will be using the radio for collecting other data and placing it in the csv file.

Ray

# mc_mb2.py
#
from microbit import *
import sys, time

uart.init(115200)

TMP_MS = 5000
t_tmp = time.ticks_ms()
tmpmode = 0
temp = 0

# Station ID
global sid
sid=0


def menu():
    print("       System Menu")
    print("quit - End the program.")
    print("settime - Set the clock.")
    print("showtime - Show the current time.")
    print("ontemp - Turn on the temp.")
    print("offtemp - Turn off the temp.")
    uart.write(">>>")     

hr = 0
mn = 0
sc = 0

# This starts the clock engine immediately.
@run_every(s=1)                                        # run every second
def update_rtc():
    global hr, mn, sc

    sc += 1
    if (sc == 60):
        sc = 0
        mn += 1
        if (mn == 60):
            mn = 0
            hr += 1
            if (hr == 24):
                hr = 0


def show_rtc():
    global hr, mn, sc

    print("%.2d:%.2d:%.2d" % (hr, mn, sc))

def set_time():
    global hr, mn, sc 
    inhour = input("hour(xx): ")
    inmin = input("minutes(xx): ")
    insec = input("seconds(xx): ")
    hr = int(inhour)
    mn = int(inmin)
    sc = int(insec)
    print("%.2d:%.2d:%.2d" % (hr, mn, sc))
    uart.write(">>>")

def show_tempf():
    global tmpmode

    tmpmode += 1
    if tmpmode % 2:
        #ts = str(round(temperature() * 9 / 5 + 32.0)-4.5) + "F "
        ts = str(round(temperature() * 9/5 +32)-4.5)+"F"+" S0"
    else:
        ts = str(round(temperature())) + "C "

    display.show(ts, delay=700, wait=False)



uart.write("Microbit softRTC.\n>>>")
menu()

while True:
    inbuff=""
    if uart.any():
        inbuff=uart.read().strip().decode()
        if inbuff == "quit":
            print("sys_dir program has ended.")
            sys.exit()

        elif inbuff == "settime":
            set_time()
        elif inbuff == "showtime":
            show_rtc()
            uart.write("\n>>>")
        elif inbuff == "ontemp":
            temp=1
            uart.write("\n>>>")
        elif inbuff == "offtemp":
            temp=0
            uart.write("\n>>>") 

        else:
            uart.write("not an option")
            uart.write("\n>>>")

    now = time.ticks_ms()
# this for the temp task
    if temp == 1 and now - t_tmp >= TMP_MS:
        show_tempf()
        t_tmp = now
    if temp == 0 and now - t_tmp >= TMP_MS :
        display.clear()

«1

Comments

  • RsadeikaRsadeika Posts: 3,824

    I am having a bit of a problem with the write_logger(). It seems when I do the settime() and then start the logger, the global_log file does not show the time correctly, it just keeps capturing the same time. Is this a problem with the append process. Not sure how to get around that.

    The other problem is when I type in a command sometimes it comes back with uart.write("not an option") response even though I have that command available. Is that a problem with my keyboard or

    if uart.any():
            inbuff=uart.read().strip().decode() 
    

    process. This really an annoying problem.

    Ray

    # mc_mb4.py
    #
    from microbit import *
    import sys, time, os
    
    uart.init(115200)
    
    # Logger task.
    LOG_MS = 5000
    t_log = time.ticks_ms()
    loge = 0
    
    global sid
    sid="S0  "   # Unit ID
    global real_time
    real_time= 0
    global ts
    ts=0
    global tday
    tday = ' 1'  
    
    
    
    hr = 0
    mn = 0
    sc = 0
    #This starts the clock engine immediately.
    @run_every(s=1)                                        # run every second
    def update_rtc():
        global hr, mn, sc
    
        sc += 1
        if (sc == 60):
            sc = 0
            mn += 1
            if (mn == 60):
                mn = 0
                hr += 1
                if (hr == 24):
                    hr = 0
                    tday=tday+1  # This should update 
    
    def show_rtc():
        global hr, mn, sc
        #global real_time
        print("%.2d:%.2d:%.2d" % (hr, mn, sc))
        #real_time = "%.2d:%.2d:%.2d" % (hr, mn, sc)
    
    def menu():
        print("       System Menu")
        print("quit - End the program.")
        print("onlog - Logger started.")
        print("dir - System directory.")
        print("ontemp - Turn on the temp.")
        print("offtemp - Turn off the temp.")
        print("settime - Set the clock.")
        print("settime - Set the clock.")
        uart.write(">> ") 
    
    def set_time():
        global hr, mn, sc 
        inhour = input("hour(xx): ")
        inmin = input("minutes(xx): ")
        insec = input("seconds(xx): ")
        hr = int(inhour)
        mn = int(inmin)
        sc = int(insec)
        #print("%.2d:%.2d:%.2d" % (hr, mn, sc))
        #uart.write(">> ")
    
    
    def write_logger():
    
        global_log = []
        f = open('global_log','w')
        my_header = 'Sta ID  ' + 'Date  ' + 'Time  ' + 'Value  F' + '\n'
        global_log.append(my_header)
        f.write(global_log[0])
    
        for i in range(1,20):
            global_log.append([])
            #val_1 = random.randint(0, 10)
            val_1 = sid
            #val_2 = random.randint(0, 10)
            val_2 = str('day')+tday
            #val_3 = random.randint(0, 10)
            val_3 = (hr,mn,sc)
            #val_4 = random.randint(0, 10)
            val_4 = str(round(temperature() * 9/5 +32)-4.5) 
            values= str(val_1) + ',' + str(val_2) + ',' + str(val_3) + ',' + str(val_4) + '\n'
            global_log[i] = values
            f.write(global_log[i])
    
        f.close()
    
    
    
    uart.write("Microbit softRTC.\n>> ")
    menu()
    
    while True:
        inbuff=""
    
    
            if inbuff == "quit":
                print("Program has ended.")
                sys.exit()
            elif inbuff == "settime":
                set_time()
            elif inbuff == "showtime":
                show_rtc()
                uart.write("\n>> ") 
    
            elif inbuff == "onlog":
                write_logger()
                #loge=1
                uart.write("\n>> ")            
            elif inbuff == "offlog":
                #f.close()
                uart.write("\n>> ")       
            else:
                uart.write("not an option")
                uart.write("\n>> ") 
    
        now = time.ticks_ms()
    
    # This is for the logger task
        if loge == 1 and now - t_log >= TMP_MS:
            write_logger()
    
    
  • Try this for your menu, just fill in each of the elif's with the function calls.

    while True:
        inbuff=""
        if uart.any():
            inbuff=uart.read().strip().decode()
            if inbuff == "quit":
             #quit function 
                 uart.write("\n>>>")
            elif inbuff == "settime":
             #set time function
                uart.write("\n>>>")
            elif inbuff == "showtime":
             #show time function
                uart.write("\n>>>")
            elif inbuff == "onlog":
             #onlog function
                uart.write("\n>>>")
            elif inbuff == "offlog":
             #offlog function
                uart.write("\n>>>")
            elif inbuff != "":
                uart.write("not an option")
                uart.write("\n>>>")
    

    To log your values you only need to open the log file once and keep the file open until you have finished logging so to open and close the file you need separate functions from the "write_logger()" function. The for loop in your "write_logger()" function is just going to write the same values 20 times because they have never been refreshed. Think about something like the following

    OPEN THE LOG FILE AND WRITE THE HEADER
    WRITE DATA TO THE LOG FILE ONCE EVERY MINUTE ---- REFRESH THE TIME VALUES ---- REPEAT
    WHEN YOU FINISH LOGGING CLOSE THE FILE
    QUIT THE PROGRAM

    Don't use the List to contain the data just separate the data with commas and terminate with a newline ("\n") every time you write to file.

    def write_logger():
    
            temp = (((1.8*temperature())+32)-4.5)
            temp_string=str(round(temp,1))+"F"
    
            val_1 = sid
            val_2 = str('day')+tday
            val_3 = (hr,mn,sc)
            val_4 = temp_string
    
            values= str(val_1) + ',' + str(val_2) + ',' + str(val_3) + ',' + str(val_4) + '\n'
    
            f.write(values)
    
  • I also found the following in the microbit module that I thought might be useful, it's a way of scaling values and the example they give just happens to be temperature deg C to deg F

    temp_fahrenheit = microbit.scale(30, from_=(0, 100), to=(32, 212))

  • RsadeikaRsadeika Posts: 3,824

    I am not sure if I am getting this logging stuff correctly. Below is a small program. In theory every time I do the write command, it should append a new line. For me it looks like it just keeps over writing the first line. This should be a simple enoug program to make a correction, if I have the concept wrong.

    Ray

    # mc_mb7.py
    #
    #
    from microbit import *
    import time, sys
    
    uart.init(115200)
    
    
    #@run_every(s=3)
    def write_log():
        global f
    
        f=open('global_log','w')
        f.write("This is line 1\n") 
    
    uart.write("Log test.\n>> ")
    
    while True:    # loop
    
        inbuff=""
        if uart.any():
            inbuff=uart.read().strip().decode()
            uart.write(">> ")
            if inbuff == "quit":
                f.close()
                print("Program has ended.")
                sys.exit()
            elif inbuff == "write":
                write_log()
            elif inbuff == "close":
                f.close()
            else:
               uart.write("???") 
               uart.write("\n>> ") 
        sleep(100)
    
    
    
  • Every time you open a file in w mode it is overwritten if it already exists.

  • dgatelydgately Posts: 1,624

    @Rsadeika said:
    In theory every time I do the write command, it should append a new line. For me it looks like it just keeps over writing the first line. >This should be a simple enoug program to make a correction, if I have the concept wrong.
    f=open('global_log','w')

    The micropython on Micro:Bit does not support the 'a' (append) mode. In order to append to a file, you have to read it into a buffer, add any new text to that buffer, then re-write the file. This is unlike micropython on other microcontroller boards, which do support the append ('a') mode.

    Unfortunately you won't see this detail in the generic micropython documentation, right? You have to get this information from the Micro:Bit micropython documentation...

    It's here:
    https://microbit-micropython.readthedocs.io/en/latest/tutorials/storage.html

    And, contains this (search for 'append' in your browser from the linked page above):

    dgately

  • RsadeikaRsadeika Posts: 3,824

    I just keep missing the obvious. Below, the program works, first I do an open, then I can do multiple write and then either quit or close.

    Ray

    # mc_mb7.py
    #
    #
    from microbit import *
    import time, sys
    
    uart.init(115200)
    
    
    def write_log():
        f.write("This is line 1\n")    
    
    uart.write("Log test.\n>> ")
    
    while True:    # loop
    
        inbuff=""
        if uart.any():
            inbuff=uart.read().strip().decode()
            uart.write(">> ")
            if inbuff == "quit":
                f.close()
                print("Program has ended.")
                sys.exit()
            elif inbuff == "write":
                write_log()
            elif inbuff == "close":
                f.close()
            elif inbuff == "open":
                f=open('global_log','w')
            else:
               uart.write("???") 
               uart.write("\n>> ") 
        sleep(100)
    
    
  • dgatelydgately Posts: 1,624

    Surprised it works (due to the docs), but that's good news!

    dgately

  • @Rsadeika your on the right track, here is the same code with a boolean variable called "write_enable" that is either True or False depending on whether you want to write to file or not write to file, you can see this variable inside of your write_log method which I have now set to run every 5 seconds. As long as you only open the file once and only close it when your done you can log for a long time.

    from microbit import *
    import time, sys
    
    uart.init(115200)
    write_enable=False
    
    @run_every(s=5)
    def write_log():
        if write_enable==True:
            f.write("This is line 1\n")    
    
    uart.write("Log test.\n>> ")
    
    while True:    # loop
    
        inbuff=""
        if uart.any():
            inbuff=uart.read().strip().decode()
            uart.write(">> ")
            if inbuff == "quit":
                f.close()
                print("Program has ended.")
                sys.exit()
            elif inbuff == "write":
                write_enable=True
            elif inbuff == "close":
                write_enable=False
                f.close()
            elif inbuff == "open":
                f=open('global_log','w')
            else:
               uart.write("???") 
               uart.write("\n>> ") 
        sleep(100)
    
  • RsadeikaRsadeika Posts: 3,824

    I am having trouble figuring out how to f.write() numbers to a file. It does strings very well but numbers... I was trying to do something like x=x+1, and have the incremented number written. I tried doing a str(x) or a chr(x), and that did not work. Any suggestions.

    Ray

  • str(x) should work

    x=0
    
    @run_every(s=5)
    def write_log():
        global x
        if write_enable==True:
            x+=1
            f.write("This is line " + str(x) + "\n")    
    
  • dgatelydgately Posts: 1,624
    edited 2024-01-09 17:01

    @Rsadeika said:
    I am having trouble figuring out how to f.write() numbers to a file. It does strings very well but numbers...

    You probably don't want to write numbers into what is a text file for this. Convert the numbers to a string before writing them. Then, convert the strings back to numbers when read back from the file...

    This example creates a .csv file of numbers (as text). Then, it reads the them back in and converts them back to numbers for use.

    EDIT: writes and reads both integer & floating point numbers...

    # write/read file of comma separated numbers (mix of integers & fp)
    # example for Micro:Bit micropython
    #
    
    # open & write a file of comma separated numbers
    f = open("fpnbrs.csv", 'w')
    
    for i in range(1, 11):  # write 10 numbers to the file
        f.write(str(i))     # convert number to a string
        if i >= 7:          # make a few of them floating point
            f.write(".73")
        if i < 10:          # don't write a comma at the end...
            f.write(",")
    f.close()
    
    # file now contains: 1,2,3,4,5,6,7.73,8.73,9.73,10.73
    
    # open, read, accumulate & print from the file of comma seperated numbers
    z = 0
    file = open("fpnbrs.csv", 'r')
    content = file.read()
    intVals = content.split(",") 
    for x in intVals:
        print ("+" + x + " sum: ",end="") # x is a string
        z+=float(x)     # convert x from a string to an number (float) and do something interesting...
        print(z)
    
    file.close()
    
    %run -c $EDITOR_CONTENT
    +1 sum: 1.0
    +2 sum: 3.0
    +3 sum: 6.0
    +4 sum: 10.0
    +5 sum: 15.0
    +6 sum: 21.0
    +7.73 sum: 28.73
    +8.73 sum: 37.46
    +9.73 sum: 47.19
    +10.73 sum: 57.92
    

    dgately

  • RsadeikaRsadeika Posts: 3,824

    I added some stuff, the program seems to run without errors. This version you have to do a manual write command to put something in the csv file. I am sure that this is not crash proof, if you do not put everything in. This is a proof test. Any improvements that are suggested will be appreciated.

    Ray

    # mc_mb7.py
    #
    #
    from microbit import *
    import time, sys
    
    EVENT_MS = 5000  # Runs at 1 second
    # starts the tics
    t_start = time.ticks_ms() 
    tic_runtime = 0
    temp_runtime = 0
    
    #global x
    x=0
    global real_time
    real_time=0
    sta = "S0"
    # This will be the sensor ID
    # 00 - temperature
    sid = "00"  
    
    uart.init(115200)
    
    write_enable=False
    
    my_header = 'Sta' + '  ID' + '    Date' + '       Time' + '   Value F' + '\n'
    
    hr = 0
    mn = 0
    sc = 0
    @run_every(s=1)
    def update_rtc():
        global hr, mn, sc
        global dd
        sc += 1
        if (sc == 60):
            sc = 0
            mn += 1
            if (mn == 60):
                mn = 0
                hr += 1
                if (hr == 24):
                    hr = 0
                    dd=dd+1  # This should update the day
    
    
    def show_rtc():
        global hr, mn, sc
        #global real_time
        print("%.2d:%.2d:%.2d" % (hr, mn, sc))
    
    def set_time():
        global hr, mn, sc 
        inhour = input("hour(xx): ")
        inmin = input("minutes(xx): ")
        insec = input("seconds(xx): ")
        hr = int(inhour)
        mn = int(inmin)
        sc = int(insec)
        print("%.2d:%.2d:%.2d" % (hr, mn, sc))
       # uart.write(">> ")
    
    def set_date():
        global yr, mt, dd
        inyear = input("year(xxxx): ")
        inmonth = input("month(xx): ")
        inday = input("day(xx): ")
        yr = int(inyear)
        mt = int(inmonth)
        dd = int(inday)
        print("%.2d/%.2d/%.2d" % (mt,dd,yr))
    
    def write_log(tt):
        global x
        global hr, mn, sc
        global yr, mt, dd
        global sta, sid
        global real_time
        global real_date
        if write_enable == True:
            real_time = (str(hr)+":"+str(mn)+":"+str(sc))
            real_date = (str(mt)+"/"+str(dd)+"/"+str(yr))
            #x += 1
            #f.write("This is line " + str(x) + "\n")
            #f.write(str(hr)+":"+str(mn)+":"+str(sc)+"\n")
            f.write(sta+",  "+sid+", "+real_date+", "+" "+real_time+", "+" "+"72.4"+"\n")
    
    def write_header():
        f.write(my_header)
    
    
    def menu():
        print("       System Menu")
        print("quit - End the program.")
        print("onlog - Logger started.")
        print("offlog - Logger stopped.")
        print("settime - Set the the RTC.")
        print("setday - Set todays date.")
        uart.write(">> ")
    
    
    
    write_log(0)
    
    
    uart.write("Log test.\n>> ")
    menu()
    
    while True:    # loop
    
        inbuff=""
        if uart.any():
            inbuff=uart.read().strip().decode()
            uart.write(">> ")
            if inbuff == "quit":
                f.close()
                print("Program has ended.")
                sys.exit()
            elif inbuff == "write":
                write_enable=True
            elif inbuff == "offlog":
                write_enable=False
                f.close()
            elif inbuff == "onlog":
                f=open('global_log.csv','w')
                write_header()
                #f.write(my_header)
            elif inbuff == "settime":
                set_time()
            elif inbuff == "setday":
                set_date()
            else:
               uart.write("???") 
               uart.write("\n>> ") 
    
    
        t_elapsed = time.ticks_ms() - t_start
    # Jon's task method
        if t_elapsed >= EVENT_MS:
            tic_runtime += EVENT_MS        
            write_log(tic_runtime)  # This runs write_log              
            t_start += EVENT_MS  # Time tics
    
        sleep(100)
    
    
  • dgatelydgately Posts: 1,624

    @Rsadeika said:
    I added some stuff, the program seems to run without errors. This version you have to do a manual write command to put something in the csv file. I am sure that this is not crash proof, if you do not put everything in. This is a proof test. Any improvements that are suggested will be appreciated.

    Looks very good!

    I'm able to crash the program, choosing the 'write' command if the date and time have not yet been set. On program start you might want to set a date-time_set=False flag for the date & time not being set that can be checked in the write() function. Set that flag to True once date & time have been set.

    dgately

  • RsadeikaRsadeika Posts: 3,824

    Thanks for the observation, I have to start thinking about error proofing the system. My next step is to automate a logging procedure for the temperature sensor. I also have to keep in mind that when I get to using the radio I will be collecting other Sta information , which will be placed in the global_log.csv. Plus I hope to make use of the other sensors that are available.

    Ray

  • RsadeikaRsadeika Posts: 3,824

    I automated the onlog so it starts capturing the temperature and writing it to the log. The problem I am having is error proofing the settime/setdate as suggested. I tried a couple of different things, and it is not working for me. I guess I need some expert advice.

    Ray

    # mc_mb7.py
    #
    #
    from microbit import *
    import time, sys
    
    EVENT_MS = 15000  # Runs at 1 second
    # starts the tics
    t_start = time.ticks_ms() 
    tic_runtime = 0
    #temp_runtime = 0
    global hr, mn, sc
    #global x
    x=0
    global real_time
    real_time=0
    sta = "S0"
    # This will be the sensor ID
    # 00 - temperature
    sid = "00"  
    
    uart.init(115200)
    
    write_enable=False
    time_enable=False
    date_enable=False
    
    my_header = 'Sta' + '  ID' + '    Date' + '       Time' + '   Value F' + '\n'
    
    hr = 0
    mn = 0
    sc = 0
    @run_every(s=1)
    def update_rtc():
        global hr, mn, sc
        global dd
        sc += 1
        if (sc == 60):
            sc = 0
            mn += 1
            if (mn == 60):
                mn = 0
                hr += 1
                if (hr == 24):
                    hr = 0
                    dd=dd+1  # This should update the day
    
    
    def show_rtc():
        global hr, mn, sc
        #global real_time
        print("%.2d:%.2d:%.2d" % (hr, mn, sc))
    
    def set_time():
        global time_enable  
        global hr, mn, sc    
        inhour = input("hour(xx): ")
        inmin = input("minutes(xx): ")
        insec = input("seconds(xx): ")
        hr = int(inhour)
        mn = int(inmin)
        sc = int(insec)
        time_enable=True
        print("%.2d:%.2d:%.2d" % (hr, mn, sc))
       # uart.write(">> ")
    
    def set_date():
        global date_enble
        global yr, mt, dd     
        inyear = input("year(xxxx): ")
        inmonth = input("month(xx): ")
        inday = input("day(xx): ")
        yr = int(inyear)
        mt = int(inmonth)
        dd = int(inday)
        date_enable=True
        print("%.2d/%.2d/%.2d" % (mt,dd,yr))
    
    #@run_every(s=3)
    def write_log(tt):
        global x
        global hr, mn, sc
        global yr, mt, dd
        global sta, sid
        global real_time
        global real_date
        temp = (((1.8*temperature())+32)-4.5)
        temp_string=str(round(temp,1)) 
        if write_enable == True:
            real_time = (str(hr)+":"+str(mn)+":"+str(sc))
            real_date = (str(mt)+"/"+str(dd)+"/"+str(yr))
            #x += 1
            #f.write("This is line " + str(x) + "\n")
            #f.write(str(hr)+":"+str(mn)+":"+str(sc)+"\n")
            f.write(sta+",  "+sid+", "+real_date+", "+" "+real_time+", "+" "+temp_string+"\n")
    
    def write_header():
        f.write(my_header)
    
    
    def menu():
        print("       System Menu")
        print("quit - End the program.")
        print("onlog - Logger started.")
        print("offlog - Logger stopped.")
        print("settime - Set the the RTC.")
        print("setday - Set todays date.")
        uart.write(">> ")
    
    
    
    write_log(0)
    
    
    uart.write("Log test.\n>> ")
    menu()
    
    while True:    # loop
    
        inbuff=""
        if uart.any():
            inbuff=uart.read().strip().decode()
            uart.write(">> ")
            if inbuff == "quit":
                f.close()
                print("Program has ended.")
                sys.exit()
    #        elif inbuff == "write":
    #            write_enable=True
            elif inbuff == "offlog":
                write_enable=False
                f.close()
            elif inbuff == "onlog":
                #if date_enable==False and time_enable==False:
                #    print("settime and setdate have not been done.")
                #    uart.write("\n>> ")
                #else:
                #    if date_enable==True and time_enable==True:
                f=open('global_log.csv','w')
                f.write(my_header)
                write_enable=True
                #f.write(my_header)
            elif inbuff == "settime":
                set_time()
            elif inbuff == "setdate":
                set_date()
            else:
               uart.write("???") 
               uart.write("\n>> ") 
    
    
        t_elapsed = time.ticks_ms() - t_start
    # Jon's task method
        if t_elapsed >= EVENT_MS:
            tic_runtime += EVENT_MS        
            write_log(tic_runtime)  # This runs write_log              
            t_start += EVENT_MS  # Time tics
    
        sleep(100)
    
    
  • dgatelydgately Posts: 1,624
    edited 2024-01-11 03:37

    @Rsadeika said:
    I automated the onlog so it starts capturing the temperature and writing it to the log. The problem I am having is error proofing the settime/setdate as suggested. I tried a couple of different things, and it is not working for me. I guess I need some expert advice.

    I just edited the "onlog" case... It just gives the warning if date & time not set... But, If date & time have been set, it opens the log file, writes the header and sets write_enable to True. Seems to work.

            elif inbuff == "onlog":
                if date_enable==False and time_enable==False:
                    print("settime and setdate have not been done.")
                    uart.write("\n>> ")
                else:
                    f=open('global_log.csv','w')
                    f.write(my_header)
                    write_enable=True
    

    You might want to add a 'clearlog' command and a command that just prints the log (or a portion of it) to the shell. Even if those commands are only available while testing & debugging the code. And, maybe a "?" command that just prints the menu again.

    Oh and it appears that (some, like setdate & settime) commands return with a '>> ???' after printing the date/time. Something is left in the input buffer, I guess.

    Just some ideas (take with a grain of salt)...

    dgately

  • RsadeikaRsadeika Posts: 3,824

    Here is my latest version, so far it runs without errors. I added def system_stat(), which I ended up using @run_every(s=5). I tried using Jon's task method, but I guess I could not get the timing right, it just would not work correctly. '>> ???', this one I cannot figure out, I do not know how to fix that one, at this point.

    Another weird thing, in the quit command I added a Image.SMILE, when I do a quit, the smile shows up very quickly, but is overtaken by the Image.YES. Not sure what is going on there.

    Ray

    # mc_mb7.py
    #
    #
    from microbit import *
    import time, sys, os
    
    # This is the write_log task
    WRITE_MS = 15000  # Runs at 1 second
    # starts the tics
    t_start = time.ticks_ms() 
    tic_runtime = 0
    
    # This is the system status
    ##ST_MS = 15000
    #t_start = time.tics_ms()
    ##st_runtime = 0
    
    
    global hr, mn, sc
    #global x
    x=0
    global real_time
    real_time=0
    sta = "S0"
    # This will be the sensor ID
    # 00 - temperature
    sid = "00"  
    
    uart.init(115200)
    
    write_enable=False
    time_enable=False
    date_enable=False
    
    my_header = 'Sta' + '  ID' + '    Date' + '       Time' + '    Value' + '\n'
    
    hr = 0
    mn = 0
    sc = 0
    @run_every(s=1)
    def update_rtc():
        global hr, mn, sc
        global dd
        sc += 1
        if (sc == 60):
            sc = 0
            mn += 1
            if (mn == 60):
                mn = 0
                hr += 1
                if (hr == 24):
                    hr = 0
                    dd=dd+1  # This should update the day
    
    
    def show_rtc():
        global hr, mn, sc
        #global real_time
        print("%.2d:%.2d:%.2d" % (hr, mn, sc))
    
    def set_time():
        global time_enable  
        global hr, mn, sc    
        inhour = input("hour(xx): ")
        inmin = input("minutes(xx): ")
        insec = input("seconds(xx): ")
        hr = int(inhour)
        mn = int(inmin)
        sc = int(insec)
        time_enable=True
        print("%.2d:%.2d:%.2d" % (hr, mn, sc))
       # uart.write(">> ")
    
    def set_date():
        global date_enable
        global yr, mt, dd     
        inyear = input("year(xxxx): ")
        inmonth = input("month(xx): ")
        inday = input("day(xx): ")
        yr = int(inyear)
        mt = int(inmonth)
        dd = int(inday)
        date_enable=True
        print("%.2d/%.2d/%.2d" % (mt,dd,yr))
    
    #@run_every(s=3)
    def write_log(tt):
        global x
        global hr, mn, sc
        global yr, mt, dd
        global sta, sid
        global real_time
        global real_date
        temp = (((1.8*temperature())+32)-4.5)
        temp_string=str(round(temp,1)) 
        if write_enable == True:
            real_time = (str(hr)+":"+str(mn)+":"+str(sc))
            real_date = (str(mt)+"/"+str(dd)+"/"+str(yr))
            #x += 1
            #f.write("This is line " + str(x) + "\n")
            #f.write(str(hr)+":"+str(mn)+":"+str(sc)+"\n")
            f.write(sta+",  "+sid+", "+real_date+", "+" "+real_time+", "+" "+temp_string+"\n")
    
    def write_header():
        f.write(my_header)
    
    def listDir():
        x=os.listdir()
        print(x)
        uart.write("\n>> ")
    
    def uname():
        y=os.uname()
        print(y)
        uart.write("\n>>>")
    
    @run_every(s=5)
    def system_stat():
    
        if write_enable == True:
            display.show(Image.YES)
        elif write_enable == False:
            display.show(Image.NO)
        else:
            display.show(Image.SMILE)
    
    def menu():
        print("       System Menu")
        print("quit - End the program.")
        print("dir - System directory.")
        print("system - System information.")
        print("onlog - Logger started.")
        print("offlog - Logger stopped.")
        print("settime - Set the the RTC.")
        print("setday - Set todays date.")
        uart.write(">> ")
    
    
    
    write_log(0)
    #system_stat(0)
    
    uart.write("Log test.\n>> ")
    menu()
    
    while True:    # loop
    
        inbuff=""
        if uart.any():
            inbuff=uart.read().strip().decode()
            uart.write(">> ")
            if inbuff == "quit":
                f.close()
                print("Program has ended.")
                display.show(Image.SMILE)
                sys.exit()
    
    #        elif inbuff == "write":
    #            write_enable=True
            elif inbuff == "dir":
                listDir()
            elif inbuff == "system":
                uname() 
            elif inbuff == "offlog":
                write_enable=False
                #f.close()
            elif inbuff == "onlog":
                #if date_enable==False and time_enable==False:
                #    print("settime and setdate have not been done.")
                #    uart.write("\n>> ")
                #else:
                if date_enable==True and time_enable==True:
                    f=open('global_log.csv','w')
                    f.write(my_header)
                    write_enable=True
                else:
                    print("settime and setdate have not been done")
                    uart.write("\n>> ")
            elif inbuff == "settime":
                set_time()
            elif inbuff == "setdate":
                set_date()
            else:
               uart.write("???") 
               uart.write("\n>> ") 
    
    
        t_elapsed = time.ticks_ms() - t_start
    # Jon's task method
        if t_elapsed >= WRITE_MS:
            tic_runtime += WRITE_MS        
            write_log(tic_runtime)  # This runs write_log              
            t_start += WRITE_MS  # Time tics
    
    #    if t_elapsed >= ST_MS:
    #        st_runtime += ST_MS
    #        system_stat(tic_runtime)
    #        t_start += ST_MS
    
        sleep(100)
    
    
    
  • RsadeikaRsadeika Posts: 3,824

    I am trying to figure out a simplified way of doing a calendar thing. Will the code that I added to the update_rtc() do what I think it will do. I guess another opinion is needed for this. Is there a simpler way of doing this.

    Ray

    def set_date():
        global date_enable
        global yr, mt, dd     
        inyear = input("year(xxxx): ")
        inmonth = input("month(xx): ")
        inday = input("day(xx): ")
        yr = int(inyear)
        mt = int(inmonth)
        dd = int(inday)
        date_enable=True
        print("%.2d/%.2d/%.2d" % (mt,dd,yr))
    
    
    
    hr = 0
    mn = 0
    sc = 0
    @run_every(s=1)
    def update_rtc():
        global hr, mn, sc
        global dd
        sc += 1
        if (sc == 60):
            sc = 0
            mn += 1
            if (mn == 60):
                mn = 0
                hr += 1
                if (hr == 24):
                    hr = 0
                    #dd=dd+1  # This should update the day
                    if dd == 29 and yy == 2024:  # leap year
                        dd=1
                    elif dd == 30:
                        if mt == 4 or mt == 6 or mt == 9 or mt == 11:
                            dd=1
                    elif dd == 31:
                        if mt == 1 or mt == 3 or mt == 5 or mt == 7 or mt == 8 or mt == 10 or mt == 12:
                            dd=1
                    else:
                        dd=dd+1
    
    
  • JonnyMacJonnyMac Posts: 8,973
    edited 2024-01-12 02:25

    Use an external I2C RTC chip that will hold time and date (using a battery) between power outages. Your master controller can always update the slave controllers (just like your cell phone gets the time and date from cell towers).

  • dgatelydgately Posts: 1,624

    Ray,

    Parallax sells a DS3231 AT24C32 Real Time Clock Module at $4.95 (US)...
    https://parallax.com/product/ds3231-at24c32-real-time-clock-module/

    Here's 'mostly' your code running with the DS3231 RTC module in-place of the software RTC. It still uses the task method to initiate logging, but the date & time data comes from the DS3231 RTC...

    The RTC was set earlier today and has been running even while the Micro:Bit has been unplugged.

    dgately

  • RsadeikaRsadeika Posts: 3,824

    @dgately, if you get a chance could you provide a picture of your hardware setup. I am trying keep away from doing the breadboard stuff, but you may have a neat setup.

    I was looking for a plug and play solution for the RTC, but there is virtually nobody selling a solution that I like. But did come across one outfit that is selling something interesting, the drawback, all of their sample code is using that make software.

    Ray

  • dgatelydgately Posts: 1,624
    edited 2024-01-12 16:35

    @Rsadeika said:
    @dgately, if you get a chance could you provide a picture of your hardware setup. I am trying keep away from doing the breadboard stuff, but you may have a neat setup.

    Just a prototype breadboard setup. Small breadboard, Parallax Edge I/O Adapter & RTC module and 2 15K pull-up resistors. You could replace the breadboard with something like this: tinyurl.com/35d2jzt6 OR https://www.adafruit.com/product/571?gad_source=1 for a permanent solution.

    dgately

  • JonnyMacJonnyMac Posts: 8,973

    I think that RTC module already has pull-ups, so you may not need to add them to the breadboard.

  • RsadeikaRsadeika Posts: 3,824

    Thanks dgately, that looks simple enough. I know I have an RTC and a BME somewhere, in my parts box. I will have to see what other sensors I have, that are not on the micro:bit. Now if Parallax would provide an official schematic for these sensors as it would used with the micro:bit, that would make things a little easier. I am hoping that dgately will provide the source code for working with these sensors.

    Ray

  • JonnyMacJonnyMac Posts: 8,973

    Now if Parallax would provide an official schematic for these sensors as it would used with the micro:bit, that would make things a little easier.

    Waiting for Parallax to do everything you want in exactly the manner you want it will leave you unhappy. It's a tiny company with next to no resources.

    The internet can be your friend. I used the words MICROBIT and RTC in a search engine that lead to lots of options; surely, there is something in that mix that will help you.

  • RsadeikaRsadeika Posts: 3,824

    I looked in my parts drawer and found a ds1302 RTC board that Parrallax used to sell. The pins MISO, MOSI, SCK might be for serial connection, not sure about that. I think the micro:bit is looking for an SCL and SCA connection. I will have to look at micro:bit pinout to see if the ds1302 can be connected.

    Ray

  • dgatelydgately Posts: 1,624

    @Rsadeika said:
    Thanks dgately, that looks simple enough. I know I have an RTC and a BME somewhere, in my parts box. I will have to see what other sensors I have, that are not on the micro:bit. Now if Parallax would provide an official schematic for these sensors as it would used with the micro:bit, that would make things a little easier. I am hoping that dgately will provide the source code for working with these sensors.

    As JonnyMac stated, the pull-ups are not needed, so wiring is even easier :)

    Parallax provides a datasheet for the RTC module, which gives the details on what needs to be sent to it and what data the module returns. BTW: It can also return temperature values (I have an code example of that as well). I found an example of how you would wire it up to an Arduino Uno, then looking at a Micro:Bit pinout image (https://tech.microbit.org/hardware/edgeconnector/), found scl & sda on pins 19 & 20.

    As far as source code, I used the following site, then melded the example code from there with your demo program. There's not a lot of error checking & definitely needs optimization (uart vs print, etc) at some point. I left the software RTC code in the program for now, but would 'optimize' that out, for my use.
    multiwingspan.co.uk/micro.php?page=rtc

    # mc_mb7_rtc.py
    # Uses an external DS3231 RTC module
    # Based on: http://multiwingspan.co.uk/micro.php?page=rtc
    
    from microbit import *
    import time, sys
    
    # various vars (some not needed for this example)
    EVENT_MS = 15000  # Runs at 1 second
    # starts the tics
    t_start = time.ticks_ms() 
    tic_runtime = 0
    #temp_runtime = 0
    global hr, mn, sc
    #global x
    x=0
    global real_time
    real_time=0
    sta = "S0"
    # This will be the sensor ID
    # 00 - temperature
    sid = "00"  
    
    uart.init(115200)
    
    write_enable=False
    time_enable=False
    date_enable=False
    
    my_header = 'Sta' + '  ID' + '    Date' + '       Time' + '   Value F' + '\n'
    
    hr = 0
    mn = 0
    sc = 0
    @run_every(s=1)
    def update_rtc():
        global hr, mn, sc
        global dd
        sc += 1
        if (sc == 60):
            sc = 0
            mn += 1
            if (mn == 60):
                mn = 0
                hr += 1
                if (hr == 24):
                    hr = 0
                    dd=dd+1  # This should update the day
    
    # convert RTC values for logging
    def bcd2dec(bcd):
        return (((bcd & 0xf0) >> 4) * 10 + (bcd & 0x0f))
    
    def dec2bcd(dec):
        tens, units = divmod(dec, 10)
        return (tens << 4) + units
    
    # set an oboard software RTC time
    def set_time():
        global time_enable  
        global hr, mn, sc    
        inhour = input("hour(xx): ")
        inmin = input("minutes(xx): ")
        insec = input("seconds(xx): ")
        hr = int(inhour)
        mn = int(inmin)
        sc = int(insec)
        time_enable=True
        print("%.2d:%.2d:%.2d" % (hr, mn, sc))
       # uart.write(">> ")
    
    # set an oboard software RTC date
    def set_date():
        global date_enble
        global yr, mt, dd     
        inyear = input("year(xxxx): ")
        inmonth = input("month(xx): ")
        inday = input("day(xx): ")
        yr = int(inyear)
        mt = int(inmonth)
        dd = int(inday)
        date_enable=True
        print("%.2d/%.2d/%.2d" % (mt,dd,yr))
    
    # set the external battery backed-up RTC date & time
    def set_time_rtc():
        global time_enable  
        global hr, mn, sc        
    
        inDay = input("Day(xx): ")
        inMonth = input("Month(xx): ")
        inYear = input("Year(xxxx): ")
        inWkDay = input("Day of the week (1-7, Sunday is 1): ")
        inHour = input("Hour(xx): ")
        inMin = input("Minutes(xx): ")
        inSec = input("Seconds(xx): ")
    
        hr = int(inHour)
        mn = int(inMin)
        sc = int(inSec)
        yr = int(inYear)
        mt = int(inMonth)
        dd = int(inDay)
        wd = int(inWkDay)
    
        # prepare & write to the external RTC
        t = bytes([sc,mn,hr,wd,dd,mt,yr-2000])
        for i in range(0,7):
            i2c.write(addr, bytes([i,dec2bcd(t[i])]), repeat=False)
    
        # print("%.2d:%.2d:%.2d" % (hr, mn, sc))
        # print("%.2d/%.2d/%.2d" % (mt,dd,yr))
    
        date_enable==True
        time_enable==True
    
    #@run_every(s=3)
    def write_log(tt):
        global x
        global hr, mn, sc
        global yr, mt, dd
        global sta, sid
        global real_time
        global real_date
        temp = (((1.8*temperature())+32)-4.5)
        temp_string=str(round(temp,1)) 
        if write_enable == True:
            real_time = (str(hr)+":"+str(mn)+":"+str(sc))
            real_date = (str(mt)+"/"+str(dd)+"/"+str(yr))
            #x += 1
            #f.write("This is line " + str(x) + "\n")
            #f.write(str(hr)+":"+str(mn)+":"+str(sc)+"\n")
            f.write(sta+",  "+sid+", "+real_date+", "+" "+real_time+", "+" "+temp_string+"\n")
    
    def write_log_rtc(tt):
        global x
        global hr, mn, sc
        global yr, mt, dd
        global sta, sid
        global real_time
        global real_date
    
        temp = (((1.8*temperature())+32)-4.5)       # Micro:Bit temperature
        temp_string=str(round(temp,1))
    
        # get external RTC data and write to the log
        i2c.write(addr, b'\x00', repeat=False)
        buf = i2c.read(addr, 7, repeat=False)
        sc = bcd2dec(buf[0])                        # seconds
        mn = bcd2dec(buf[1])                        # minutes
        if buf[2] & 0x40:                           # hour
            hr = bcd2dec(buf[2] & 0x1f)
            if buf[2] & 0x20:
                hr += 12
        else:
            hr = bcd2dec(buf[2])
        wday = buf[3]                               # day of the week (1-7)
        dd = bcd2dec(buf[4])                        # day
        mt = bcd2dec(buf[5] & 0x1f)                 # month
        yr = bcd2dec(buf[6])+2000                   # year
    
        if write_enable == True:                    # write formatted time, date & temp
            real_time = (str(hr)+":"+str(mn)+":"+str(sc))
            real_date = (str(mt)+"/"+str(dd)+"/"+str(yr))
            f.write(sta+",  "+sid+", "+real_date+", "+" "+real_time+", "+" "+temp_string+"\n")
    
    def write_header():
        f.write(my_header)
    
    def get_rtc():
    
        # print the current RTC data
        i2c.write(addr, b'\x00', repeat=False)
        buf = i2c.read(addr, 7, repeat=False)
        ss = bcd2dec(buf[0])
        mm = bcd2dec(buf[1])
        if buf[2] & 0x40:
            hh = bcd2dec(buf[2] & 0x1f)
            if buf[2] & 0x20:
                hh += 12
        else:
            hh = bcd2dec(buf[2])
        wday = buf[3]
        DD = bcd2dec(buf[4])
        MM = bcd2dec(buf[5] & 0x1f)
        YY = bcd2dec(buf[6])+2000
        print(str(MM) + "/" + str(DD) + "/" + str(YY) + " - " + str(hh) + ":" + str(mm) + ":" + str(ss) + " day: " + str(wday))
    
    def menu():
        print("       System Menu")
        print("quit - End the program.")
        print("onlog - Logger started.")
        print("offlog - Logger stopped.")
        print("settime - Set the the RTC.")
        print("setdate - Set todays date.")
        print("setrtc - Set external RTC date & time.")         # set the date & time on the external RTC
        print("getrtc - Display external RTC date & time .")    # dump the RTC date & time to the shell
        uart.write(">> ")
    
    ##################### MAIN ###################
    
    write_log(0)
    
    uart.write("Log test.\n>> ")
    menu()
    
    addr = 0x68
    buf = bytearray(7)
    #set_time(10,14,12,5,11,1,2023)
    
    while True:    # loop
    
        inbuff=""
        if uart.any():
            inbuff=uart.read().strip().decode()
            uart.write(">> ")
    
    # QUIT
            if inbuff == "quit":
                f.close()
                print("Program has ended.")
                sys.exit()
    # OFFLOG
            elif inbuff == "offlog":
                write_enable=False
                f.close()
                print("Logging off")
                uart.write(">> ")            
    # ONLOG
            elif inbuff == "onlog":
                #if date_enable==False and time_enable==False:
                #    print("settime and setdate have not been done.")
                #    uart.write("\n>> ")
                #else:
                    f=open('global_log.csv','w')
                    f.write(my_header)
                    print("Logging on")
                    write_enable=True
                    uart.write(">> ")
    # SETTIME
            elif inbuff == "settime":
                set_time()
                uart.write(">> ")
    # SETDATE
            elif inbuff == "setdate":
                set_date()
                uart.write(">> ")
    # SETRTC
            elif inbuff == "setrtc":
                set_time_rtc()
                uart.write(">> ")
    # GETRTC
            elif inbuff == "getrtc":
                get_rtc()
                uart.write(">> ")
            else:
               uart.write("???") 
               uart.write("\n>> ") 
    
        t_elapsed = time.ticks_ms() - t_start
    # Jon's task method
        if t_elapsed >= EVENT_MS:
            tic_runtime += EVENT_MS        
            #write_log(tic_runtime)     # This runs write_log
            write_log_rtc(tic_runtime)  # This runs write_log_rtc with data from the external RTC
            t_start += EVENT_MS  # Time tics
            # get_rtc()
    
        sleep(100)
    

    Most of the details of what & how came from quick Google searches and from these sites:
    https://microbit-micropython.readthedocs.io/en/v2-docs/
    https://docs.micropython.org/en/latest/

    dgately

  • RsadeikaRsadeika Posts: 3,824

    Concerning te ds1302, I noticed that the micro:bit has MISO, MOSI, SCK pins. I guess as an experiment I could use some alligator clips to connect up to the micro:bit and the ds1302. Looking at the dgately def set_time_rtc(), I think that should work for the ds1302. The last time I used the ds1302 was when I had it hooked up on the Activity Board and I was using SimpleIDE. SimpleIDE had a function for the ds1302, that made life so much easier. The thing that I do not remember is if the ds1302 needs pull-ups.

    Ray

  • RsadeikaRsadeika Posts: 3,824

    I went ahead and ordered a couple of micro:bit boards, edge connector, and RTC. Now I can start thinking more about the NoT, and how I will proceed. I also found, in my parts box a BME680, and I noticed it uses scl and sda. Since the RTC uses those pins, it may be a little more difficult to figure out how the micro:bit uses more than one I2C device, let alone trying to find the API to work the BME680.

    Ray

Sign In or Register to comment.