Need some RV3028, Pico, Micro Python, Date Time, help

I have a RV3028 setup and working on a Pi Pico, code is posted below.
This gets me the following for 24 time
14/02/2022
11:29:30
If I go 12 hour I get
11:29:30AM

The AM or PM jiggles back and forth as the seconds tick by.

What I’s like is 12 Hour as 11:29 AM or 11:29:30 AM.
I’d really like to ditch the seconds and have a space or : between the AM PM.

import time

from pimoroni_i2c import PimoroniI2C
from breakout_rtc import BreakoutRTC

PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}
PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}
i2c = PimoroniI2C(**PINS_BREAKOUT_GARDEN)

rtc = BreakoutRTC(i2c)
rtc.set_backup_switchover_mode(3)
rtc.set_24_hour()
rtc.update_time()

while True:
    
    if rtc.read_periodic_update_interrupt_flag():
        rtc.clear_periodic_update_interrupt_flag()

        if rtc.update_time():
            rtc_date = rtc.string_date()
            rtc_time = rtc.string_time()

    display.set_pen(255, 255, 255)
    display.text(rtc.string_date(), 30, 0, 240, 3)
    display.text(rtc.string_time(), 190, 0, 240, 3)

There are a couple of ways:

  • string methods to cut off the seconds (probably not a good idea on a microcontroller)
  • read the separate values and print those
  • ask for / create a new C++ method that the MicroPython can call and pass a time format string

I didn’t try the first way and I don’t know the layer between MicroPython and the C++ library works for the third way though I want to look into that one day soon.

I was able to get the second way working, in your code it would be:

    hours = rtc.get_hours()
    minutes = rtc.get_minutes()
    display.text(rtc.string_date(), 30, 0, 240, 3)
    display.text(f"{hours:02}:{minutes:02}", 190, 0, 240, 3)

It adds zeros padding so the single digit numbers for hours and minutes don’t move the AM and PM.

Your code doesn’t look complete, I’m guessing it a section from a larger script. Below is my complete script that works on the Pico Explorer Base. I am still quite new to the Pico coding and it’s getting a bit late in the evening so please excuse my messy code.

Just as I was typing this reply I realised I’d not tested the 12-hour vs 24-hour setup. I added a little testing, personally I always work in 24-hour time if possible. I don’t see how the MicroPython library could set a a 12-hour 3 PM with the set_hour method.

It is getting quite late so I might have missed something. Unfortunately, there isn’t great documentation for the RV3028 breakout, I used the source code from https://github.com/pimoroni/pimoroni-pico. Though I am thankful for Pimoroni creating those nice devices and the library code at all, I can certainly appreciate how much work goes into that let along creating documentation for all the code.

from pimoroni_i2c import PimoroniI2C
from breakout_rtc import BreakoutRTC
import picoexplorer as explorer
import time

width = explorer.get_width()
height = explorer.get_height()
display_buffer = bytearray(width * height * 2)  # 2-bytes per pixel (RGB565)

explorer.init(display_buffer)

PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}  # i2c pins 4, 5 for Breakout Garden
PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}  # Default i2c pins for Pico Explorer
#i2c = PimoroniI2C(**PINS_BREAKOUT_GARDEN)
i2c = PimoroniI2C(**PINS_PICO_EXPLORER)

rtc = BreakoutRTC(i2c)
rtc.set_24_hour()
#rtc.set_12_hour()
rtc.update_time()

# was in https://github.com/pimoroni/pimoroni-pico/blob/main/micropython/examples/breakout_rtc/demo.py
#rtc.enable_periodic_update_interrupt(True)

# print(f'rtc unix: {rtc.get_unix()}')
# rtc_date = rtc.string_date()
# rtc_time = rtc.string_time()
# print("Date: ", rtc_date, ", Time: ", rtc_time, sep="")

# this failed, it was returning 2944 for a date during 14-Feb-2022,
# maybe not setup right during this testing
#if rtc.get_unix() < 5000:

# quick hacks to set a value
# the RV3028 seems to default to 2000
if rtc.get_year() < 2020:
#if rtc.get_minutes() < 55:
    # seconds, minutes, hours, weekday day, month, year
    #rtc.set_time(55,59,22,0,14,2,2022)
    
    # testing 24-hour time
    rtc.set_time(55,59,15,0,14,2,2022)
    
    # test single digit time
    #rtc.set_time(55,59,3,0,14,2,2022)
    print('reset')
    #rtc.set_to_compiler_time()

rtc.set_backup_switchover_mode(3)

hours = 0
minutes = 0
while True:
    explorer.set_pen(120, 40, 60)
    explorer.clear()
    
    if rtc.read_periodic_update_interrupt_flag():
        rtc.clear_periodic_update_interrupt_flag()

        if rtc.update_time():
            rtc_date = rtc.string_date()
            rtc_time = rtc.string_time()
            #print("Date: ", rtc_date, ", Time: ", rtc_time, sep="")
            
            # Tested method:
            # get_date() = day i.e. 1 to 28, 29, 30 or 31
            # get_unix() = unix timestamp value
            # get_year() = year number
            
            hours = rtc.get_hours()
            minutes = rtc.get_minutes()
            #print(f"{rtc.string_date()} {hours}:{minutes}")
            
#             unix_ts = rtc.get_unix()
#             dt = time.localtime(unix_ts)
#             print(f"val: {dt}")
            
    explorer.set_pen(255, 255, 255)
    #display.text(rtc.string_date(), 30, 0, 240, 3)
    #display.text(rtc.string_time(), 190, 0, 240, 3)
            
    ## on Pico Explorer display, fits full 00/00/0000 00:00:00 
    #explorer.text(rtc.string_date(), 5, 0, 240, 2)
    #explorer.text(rtc.string_time(), 160, 0, 240, 2)
    
    # on Pico Explorer display, would fit 00/00/0000 00:00
    # otherwise it cuts off the seconds
    #explorer.text(rtc.string_date(), 5, 0, 240, 3)
    #explorer.text(rtc.string_time(), 160, 0, 240, 3)
    
    # on Pico Explorer display, fits 00/00/0000 00:00
    #explorer.text(rtc.string_date(), 5, 0, 240, 3)
    #explorer.text(f"{hours}:{minutes}", 160, 0, 240, 3)
    
    # on Pico Explorer display, fits 00/00/0000 00:00
    # adds zero padding to the time
    explorer.text(rtc.string_date(), 5, 0, 240, 3)
    explorer.text(f"{hours:02}:{minutes:02}", 160, 0, 240, 3)
    
    explorer.update()

    time.sleep(0.1)
1 Like

Yeah, I just cut and pasted what I thought was needed from my original big file. I have two LCD’s, a 1.5 inch 240 x 240 breakout and a Display Pack V2 that is 240 x 320.
Weather info displays, indoor outdoor temp & humidity on one and wind speed rainfall etc on the other. Still a work in progress. The full wall of text, currently in use file is as follows. I’ll give your code a try in a little bit.

'''
This file lets you make a little indoor weather station.
Pi Pico
Large solderless breadboard
1.54" SPI Color Square LCD (240x240) Breakout
Pico Display Pack V2 (320x240) Colour LCD
BME280 - Temperature, Pressure, Humidity Sensor Breakout
BME688 - Temperature, Pressure, Humidity Sensor Breakout
RV3028 RTC
'''
#import utime
import time
import machine
import gc
import picodisplay2 as display2

from machine import ADC, Pin

from pimoroni_i2c import PimoroniI2C
from breakout_colourlcd240x240 import BreakoutColourLCD240x240
from breakout_bme280 import BreakoutBME280
from breakout_bme68x import BreakoutBME68X
from breakout_ltr559 import BreakoutLTR559
from breakout_rtc import BreakoutRTC

vsys = ADC(29)              # reads the system input voltage
charging = Pin(24, Pin.IN)  # reading GP24 tells us whether or not USB power is connected
conversion_factor = 3 * 3.3 / 65535

full_battery = 4.2                  # these are our reference voltages for a full/empty battery, in volts
empty_battery = 2.8                 # the values could vary by battery size/manufacturer so you might need to adjust them

#width = display2.get_width()
#height = display2.get_height()
#display_buffer = bytearray(display2.get_width() * display2.get_height() * 2)
display_buffer = bytearray(320 * 240 * 2)  # 2-bytes per pixel (RGB565)
#display2 = BreakoutColourLCD240x240(display_buffer, cs=(17), bl=(20))
display1 = BreakoutColourLCD240x240(display_buffer, cs=(22), bl=(21))
display2.init(display_buffer)
display1.set_backlight(0.8)
display2.set_backlight(0.8)

PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}
PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}
i2c = PimoroniI2C(**PINS_BREAKOUT_GARDEN)

bme_out = BreakoutBME68X(i2c)
bme_in = BreakoutBME280(i2c,0x77)

ltr = BreakoutLTR559(i2c)

rtc = BreakoutRTC(i2c)
rtc.set_backup_switchover_mode(3)
rtc.set_24_hour()
rtc.update_time()

min_temp_in = None
max_temp_in = None
min_temp_out = None
max_temp_out = None
min_press_out = None
max_press_out = None

start_time = time.time()

rtc.enable_periodic_update_interrupt(True)

while True:
    
    if rtc.read_periodic_update_interrupt_flag():
        rtc.clear_periodic_update_interrupt_flag()

        if rtc.update_time():
            rtc_date = rtc.string_date()
            rtc_time = rtc.string_time()
    
    time_elapsed = time.time() - start_time
    
    reading = ltr.get_reading()
    #print("Lux:", reading[BreakoutLTR559.LUX], "Prox:", reading[BreakoutLTR559.PROXIMITY])
    
    # read the sensors
    temp_in, press_in, hum_in = bme_in.read()
    temp_out, press_out, hum_out, gas_resistance, status, gas_index, meas_index = bme_out.read() 
            
    # convert pressure to mb
    pressuremb = press_out / 100
    
    # header
    display1.set_pen(200, 200, 200)
    display1.text("in", 30, 0, 60, 3)
    display1.text("out", 170, 0, 195, 3)
    display1.text("min", 95, 78, 150, 3)
    display1.text("max", 92, 100, 150, 3) 
        
    # indoor temperature
    temp_in = round(temp_in)
    
    if temp_in < 0:
        display1.set_pen(255, 255, 255)
    elif 0 <= temp_in < 12:
        display1.set_pen(0, 0, 255)
    elif 12 <= temp_in < 17:
        display1.set_pen(255, 255, 0)
    elif 17 <= temp_in < 25:
        display1.set_pen(0, 255, 0)
    elif 25 <= temp_in < 30:
        display1.set_pen(255, 140, 0)
    elif temp_in >= 30:
        display1.set_pen(255, 0, 0)
    else:
        display1.set_pen(0, 0, 0)
        
    display1.text('{:.0f}'.format(temp_in) + '`c', 15, 35, 60, 4)

    # outdoor temperature
    temp_out = round(temp_out)
    if temp_out < 0:
        display1.set_pen(255, 255, 255)
    elif 0 <= temp_out < 12:
        display1.set_pen(0, 0, 255)
    elif 12 <= temp_out < 17:
        display1.set_pen(255, 255, 0)
    elif 17 <= temp_out < 25:
        display1.set_pen(0, 255, 0)
    elif 25 <= temp_out < 30:
        display1.set_pen(255, 140, 0)
    elif temp_out >= 30:
        display1.set_pen(255, 0, 0)
    else:
        display1.set_pen(0, 0, 0)
        
    display1.text('{:.0f}'.format(temp_out) + '`c', 160, 35, 240, 4)

    # indoor min max temperature readings
    if time_elapsed > 5:
        if min_temp_in is not None and max_temp_in is not None:
            if temp_in < min_temp_in:
                min_temp_in = int(temp_in)
            elif temp_in > max_temp_in:
                max_temp_in = int(temp_in)
        else:
            min_temp_in = int(temp_in)
            max_temp_in = int(temp_in)
            
    if min_temp_in is not None and max_temp_in is not None:
        min_string_in = ('{:.0f}'.format(min_temp_in))
        max_string_in = ('{:.0f}'.format(max_temp_in))
    else:
        min_string_in = ""
        max_string_in = ""
        
    if min_temp_in is not None and max_temp_in is not None:
        if min_temp_in < 0:  # very cold
            display1.set_pen(255, 255, 255)
        elif 0 <= min_temp_in < 12:  # cold
            display1.set_pen(0, 0, 255)
        elif 12 <= min_temp_in < 17: # cool
            display1.set_pen(255, 255, 0)
        elif 17 <= min_temp_in < 25: # warm
            display1.set_pen(0, 255, 0)
        elif 25 <= min_temp_in < 30: # hot
            display1.set_pen(255, 140, 0)
        elif min_temp_in >= 30:      # very hot
            display1.set_pen(255, 0, 0)
        else:
            display.set_pen(0, 0, 0)
            
        display1.text(min_string_in, 25, 78, 190, 3)
        
        if max_temp_in < 0:  # very cold
            display1.set_pen(255, 255, 255)
        elif 0 <= max_temp_in < 12:  # cold
            display1.set_pen(0, 0, 255)
        elif 12 <= max_temp_in < 17: # cool
            display1.set_pen(255, 255, 0)
        elif 17 <= max_temp_in < 25: # warm
            display1.set_pen(0, 255, 0)
        elif 25 <= max_temp_in < 30: # hot
            display1.set_pen(255, 140, 0)
        elif max_temp_in >= 30:      # very hot
            display1.set_pen(255, 0, 0)
        else:
            display1.set_pen(0, 0, 0)
            
        display1.text(max_string_in, 25, 100, 190, 3)  
   
    # outdoor min max temperature readings
    if time_elapsed > 5:
        if min_temp_out is not None and max_temp_out is not None:
            if temp_out < min_temp_out:
                min_temp_out = int(temp_out)
            elif temp_out > max_temp_out:
                max_temp_out = int(temp_out)
        else:
            min_temp_out = int(temp_out)
            max_temp_out = int(temp_out)
            
    if min_temp_out is not None and max_temp_out is not None:
        min_string_out = ('{:.0f}'.format(min_temp_out))
        max_string_out = ('{:.0f}'.format(max_temp_out))
    else:
        min_string_out = ""
        max_string_out = ""
        
    if min_temp_out is not None and max_temp_out is not None:
        if min_temp_out < 0:  # very cold
            display1.set_pen(255, 255, 255)
        elif 0 <= min_temp_out < 12:  # cold
            display1.set_pen(0, 0, 255)
        elif 12 <= min_temp_out < 17: # cool
            display1.set_pen(255, 255, 0)
        elif 17 <= min_temp_out < 25: # warm
            display1.set_pen(0, 255, 0)
        elif 25 <= min_temp_out < 30: # hot
            display1.set_pen(255, 140, 0)
        elif min_temp_out >= 30:      # very hot
            display1.set_pen(255, 0, 0)
        else:
            display1.set_pen(0, 0, 0)
            
        display1.text(min_string_out, 180, 78, 190, 3)
        
        #max_temp_out = round(max_temp_out)
        
        if max_temp_out < 0:  # very cold
            display1.set_pen(255, 255, 255)
        elif 0 <= max_temp_out < 12:  # cold
            display1.set_pen(0, 0, 255)
        elif 12 <= max_temp_out < 17: # cool
            display1.set_pen(255, 255, 0)
        elif 17 <= max_temp_out < 25: # warm
            display1.set_pen(0, 255, 0)
        elif 25 <= max_temp_out < 30: # hot
            display1.set_pen(255, 140, 0)
        elif max_temp_out >= 30:      # very hot
            display1.set_pen(255, 0, 0)
        else:
            display1.set_pen(0, 0, 0)
            
        display1.text(max_string_out, 180, 100, 190, 3)  

    # indoor humidity
    
    if hum_in < 30:
        display1.set_pen(255, 140, 0)
    elif 30 <= hum_in < 61:
        display1.set_pen(0, 255,0)
    elif 61 <= hum_in < 81:
        display1.set_pen(255, 255, 0)
    elif hum_in >= 81:
        display1.set_pen(255, 0, 0)
    else:
        display1.set_pen(0, 0, 0)
        
    #display1.text((int(hum_in)), 20, 80, 240, 3)
    display1.text('{:.0f}'.format(hum_in) + '%', 10, 140, 105, 4)

    # outdoor humidity
    
    if hum_out < 30:
        display1.set_pen(255, 140, 0)
    elif 30 <= hum_out < 61:
        display1.set_pen(0, 255,0)
    elif 61 <= hum_out < 81:
        display1.set_pen(255, 255, 0)
    elif hum_out >= 81:
        display1.set_pen(255, 0, 0)
    else:
        display1.set_pen(0, 0, 0)
        
    #display1.text((int(hum_in)), 20, 80, 240, 3)
    display1.text('{:.0f}'.format(hum_out) + '%', 160, 140, 105, 4)
        
    # battery state
    voltage = vsys.read_u16() * conversion_factor
    percentage = 100 * ((voltage - empty_battery) / (full_battery - empty_battery))
    if percentage > 100:
        percentage = 100.00
    
    if charging.value() == 1:         # if it's plugged into USB power...
        display1.set_pen(0, 255, 0)
        #display1.text("ok", 20, 200, 240, 3)
        display1.text('{:.1f}'.format(voltage) + "v", 10, 200, 240, 3)
        display1.text("ok", 170, 200, 240, 3)
        display1.text('{:.0f}%'.format(percentage), 5, 220, 240, 3)
        display1.text('{:.0f}%'.format(percentage), 155, 220, 240, 3)
        display1.set_backlight(0.8)
        display2.set_backlight(0.8)
        #display1.set_led(0,0,225)
    else:                             # if not, display the battery stats
        display1.set_pen(255, 255, 0)
        display1.text('{:.1f}'.format(voltage) + "v", 10, 200, 240, 3)
        display1.text('{:.0f}%'.format(percentage), 5, 220, 240, 3)
        display1.text('{:.1f}'.format(voltage) + "v", 160, 200, 240, 3)
        display1.text('{:.0f}%'.format(percentage), 155, 220, 240, 3)
        display1.set_backlight(0.4)
        display2.set_backlight(0.4)
        #display1.set_led(125,0,0)
        
#    display1.text('{:.2f}'.format(voltage) + "v", 0, 200, 240, 3)
#    display1.text('{:.0f}%'.format(percentage), 5, 220, 240, 3)
#    display1.text('{:.2f}'.format(voltage) + "v", 150, 200, 240, 3)
#    display1.text('{:.0f}%'.format(percentage), 155, 220, 240, 3)

    # time to update display 1
    display1.update()
    display1.set_pen(0, 0, 0)
    display1.clear()
    
    #date_string = local_dt.strftime("%B %-d")
    #time_string = local_dt.strftime("%-I:%M %p")
    #date_string = date.strftime("%B %-d")
    #time_string = time.strftime("%-I:%M %p")
    
    # draw date and time on dislay 2
    display2.set_pen(255, 255, 255)
    display2.text(rtc.string_date(), 30, 0, 240, 3)
    display2.text(rtc.string_time(), 190, 0, 240, 3)

    
   
    # outddor pressure reading on display 2    
    if pressuremb < 982:
        display2.set_pen(255, 0, 0)
        display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 105, 3)
        display2.text("very low", 105, 110, 240, 3)
    elif 982 <= pressuremb < 1004:
        display2.set_pen(255, 255, 0)
        display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 105, 3)
        display2.text("low", 105, 110, 240, 3)
    elif 1004 <= pressuremb < 1026:
        display2.set_pen(0, 255, 0)
        display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 105, 3)
        display2.text("unsetled", 105, 110, 240, 3)
    elif 1026 <= pressuremb < 1048:
        display2.set_pen(0, 0, 255)
        display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 105, 3)
        display2.text("high", 105, 110, 240, 3)
    elif pressuremb >= 1048:
        display2.set_pen(255, 140, 0)
        display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 105, 3)
        display2.text("very high", 105, 110, 240, 3)
    else:
        display2.set_pen(0, 0, 0)
        display2.text('{:.0f}'.format(pressuremb) + 'mb', 0, 110, 105, 3)
        display2.text("", 105, 110, 240, 3)
    
    """
    # outdoor min max pressure readings
    if time_elapsed > 15:
        if min_press_out is not None and max_press_out is not None:
            if press_out < min_press_out:
                min_press_out = int(press_out)
            elif press_out > max_press_out:
                max_press_out = int(press_out)
        else:
            min_press_out = int(press_out)
            max_press_out = int(press_out)
            
    if min_press_out is not None and max_press_out is not None:
        min_press_string_out = ('{:.0f}'.format(min_press_out))
        max_press_string_out = ('{:.0f}'.format(max_press_out))
    else:
        min_press_string_out = ""
        max_press_string_out = ""
        
    if min_press_out is not None and max_press_out is not None:    
        if min_press_out < 982:
            display2.set_pen(255, 0, 0)
        elif 982 <= min_press_out < 1004:
            display2.set_pen(255, 255, 0)
        elif 1004 <= min_press_out < 1026:
            display2.set_pen(0, 255, 0)
        elif 1026 <= min_press_out < 1048:
            display2.set_pen(0, 0, 255)
        elif min_press_out >= 1048:
            display2.set_pen(255, 140, 0)
        else:
            display2.set_pen(0, 0, 0)
       
        display1.text(min_prees_string_out, 170, 60, 190, 3)
        
        #max_temp_out = round(max_temp_out)
        
        if max_temp_out < 0:  # very cold
            display1.set_pen(255, 255, 255)
        elif 0 <= max_temp_out < 12:  # cold
            display1.set_pen(0, 0, 255)
        elif 12 <= max_temp_out < 17: # cool
            display1.set_pen(255, 255, 0)
        elif 17 <= max_temp_out < 25: # warm
            display1.set_pen(0, 255, 0)
        elif 25 <= max_temp_out < 30: # hot
            display1.set_pen(255, 140, 0)
        elif max_temp_out >= 30:      # very hot
            display1.set_pen(255, 0, 0)
        else:
            display1.set_pen(0, 0, 0)
            
        display1.text(max_string_out, 170, 80, 190, 3)  
    """
        
    
    # wind speed
    display2.set_pen(255, 255, 255)
    display2.text("wind speed:", 0, 160, 240, 3)
        
    # wind direction
    display2.set_pen(255, 255, 255)
    display2.text("wind direction:", 0, 190, 240, 3)
        
    # percipitaion
    display2.set_pen(255, 255, 255)
    display2.text("percipitation:", 0, 220, 240, 3)
        
    # update display 2
    display2.update()
    display2.set_pen(0, 0, 0)
    display2.clear()

    time.sleep(1.0)
    

That worked, I get 06:56 with 12 hour, its 6:56 AM local time here as I type this. No AM or PM indicator on the end, not a big deal, just posting back exactly what I get with that code.
EDIT: I started with the weather example from here.
pimoroni-pico/micropython/examples/pico_explorer at main · pimoroni/pimoroni-pico (github.com)

Need Help: Pico weather station guide using the Pico Explorer - Discussion / Learning Resources - Pimoroni Buccaneers

Glad to hear it is working. I’d like to setup multiple temperature sensors in the house and probably one outside one day. Though I get caught up in deciding how to power it inside, maybe I’ll eventually post about it on the forum here.

Thanks for posting the full code, I’ll take a look at some point.

I have several Pi based weather sensor builds. One is battery powered and portable via a powerboost 1000. This Pico based build is using a Pico Lipo. I want it to keep working if the power fails.

This is what I came up with to get me an AM PM indication.

rtc.set_24_hour()

    hours = rtc.get_hours()
    minutes = rtc.get_minutes()
    display2.text(rtc.string_date(), 30, 0, 180, 3)
    #display2.text(f"{hours:02}:{minutes:02}", 190, 0, 320, 3)
    
    if hours <12:
        display2.text(f"{hours:2}:{minutes:02}:am", 190, 0, 240, 3)
    elif hours == 12:
        display2.text(f"{hours:2}:{minutes:02}:pm", 190, 0, 240, 3)
    elif hours >12:
        hours = hours - 12
        display2.text(f"{hours:2}:{minutes:02}:pm", 190, 0, 240, 3)